# HG changeset patch
# User Andrew Janke <andrew@apjanke.net>
# Date 1547991152 18000
#      Sun Jan 20 08:32:32 2019 -0500
# Branch datenum-no-TZ
# Node ID cccf32a5c634e851d94c00c630e0ab612f182d01
# Parent  2ae2dcf0f4d5b6b2395c6d37b445b235b2f018f4
datevec: modify strings locally instead of fiddling with TZ  env var

See https://savannah.gnu.org/bugs/index.php?55437

diff --git a/scripts/time/datevec.m b/scripts/time/datevec.m
--- a/scripts/time/datevec.m
+++ b/scripts/time/datevec.m
@@ -134,17 +134,24 @@ function [y, m, d, h, mi, s] = datevec (
           endif
         endfor
         if (! found)
           error ("datevec: none of the standard formats match the DATE string");
         endif
       endfor
     else
       ## Decipher the format string just once for speed.
-      [f, rY, ry, fy, fm, fd, fh, fmi, fs] = __date_vfmt2sfmt__ (f);
+      [f, rY, ry, fy, fm, fd, fh, fmi, fs, tz] = __date_vfmt2sfmt__ (f);
+      ## Local time zone is irrelevant, and potentially dangerous, when using
+      ## strptime to simply convert a string into a broken down struct tm.
+      ## Append explicit time zone so it is parsed exactly as is. See bug #36954.
+      if ! tz
+        f = [f " %Z"];
+        date = strcat(date, {" GMT"});
+      endif
       for k = 1:nd
         [found y(k) m(k) d(k) h(k) mi(k) s(k)] = ...
           __date_str2vec__ (date{k}, p, f, rY, ry, fy, fm, fd, fh, fmi, fs);
         if (! found)
           error ("datevec: DATE not parsed correctly with given format");
         endif
       endfor
     endif
@@ -197,17 +204,17 @@ function [y, m, d, h, mi, s] = datevec (
     d = reshape (d, date_sz);
     h = reshape (h, date_sz);
     mi = reshape (mi, date_sz);
     s = reshape (s, date_sz);
   endif
 
 endfunction
 
-function [f, rY, ry, fy, fm, fd, fh, fmi, fs] = __date_vfmt2sfmt__ (f)
+function [f, rY, ry, fy, fm, fd, fh, fmi, fs, tz] = __date_vfmt2sfmt__ (f)
 
   ## Play safe with percent signs.
   f = strrep (f, "%", "%%");
 
   if (! isempty (strfind (f, "PM")) || ! isempty (strfind (f, "AM")))
     ampm = true;
   else
     ampm = false;
@@ -231,76 +238,65 @@ function [f, rY, ry, fy, fm, fd, fh, fmi
   else
     f = strrep (f, "HH", "%H");
   endif
   f = strrep (f, "MM", "%M");
   f = regexprep (f, '[Ss][Ss]', "%S");
 
   rY = rindex (f, "%Y");
   ry = rindex (f, "%y");
+  
+  ## Time zone
+  tz = ! isempty (regexp (f, '%[Zz]'));
 
   ## Check whether we need to give default values.
   ## Possible error when string contains "%%".
   fy = rY || ry;
   fm = index (f, "%m") || index (f, "%b") || index (f, "%B");
   fd = index (f, "%d") || index (f, "%a") || index (f, "%A");
   fh = index (f, "%H") || index (f, "%I");
   fmi = index (f, "%M");
   fs = index (f, "%S");
 
 endfunction
 
 function [found, y, m, d, h, mi, s] = __date_str2vec__ (ds, p, f, rY, ry, fy, fm, fd, fh, fmi, fs)
 
-  ## Local time zone is irrelevant, and potentially dangerous, when using
-  ## strptime to simply convert a string into a broken down struct tm.
-  ## Set and restore TZ so time is parsed exactly as-is. See bug #36954.
-  TZ_orig = getenv ("TZ");
-  unwind_protect
-    setenv ("TZ", "UTC0");
+  idx = strfind (f, "FFF");
+  if (! isempty (idx))
+    ## Kludge to handle FFF millisecond format since strptime does not.
 
-    idx = strfind (f, "FFF");
-    if (! isempty (idx))
-      ## Kludge to handle FFF millisecond format since strptime does not.
+    ## Find location of FFF in ds.
+    ## Might not match idx because of things like yyyy -> %y.
+    [~, nc] = strptime (ds, f(1:idx-1));
 
-      ## Find location of FFF in ds.
-      ## Might not match idx because of things like yyyy -> %y.
-      [~, nc] = strptime (ds, f(1:idx-1));
-
-      msec = ds(nc:min (nc+2,end)); # pull 3-digit fractional seconds.
-      msec_idx = find (! isdigit (msec), 1);
+    msec = ds(nc:min (nc+2,end)); # pull 3-digit fractional seconds.
+    msec_idx = find (! isdigit (msec), 1);
 
-      if (! isempty (msec_idx))  # non-digits in msec
-        msec = msec(1:msec_idx-1);
-        msec(end+1:3) = "0";     # pad msec with trailing zeros
-        ds = [ds(1:(nc-1)), msec, ds((nc-1)+msec_idx:end)];  # zero pad ds
-      elseif (numel (msec) < 3)  # less than three digits in msec
-        m_len = numel (msec);
-        msec(end+1:3) = "0";     # pad msec with trailing zeros
-        ds = [ds(1:(nc-1)), msec, ds(nc+m_len:end)];  # zero pad ds as well
-      endif
-
-      ## replace FFF with digits to guarantee match in strptime.
-      f(idx:idx+2) = msec;
+    if (! isempty (msec_idx))  # non-digits in msec
+      msec = msec(1:msec_idx-1);
+      msec(end+1:3) = "0";     # pad msec with trailing zeros
+      ds = [ds(1:(nc-1)), msec, ds((nc-1)+msec_idx:end)];  # zero pad ds
+    elseif (numel (msec) < 3)  # less than three digits in msec
+      m_len = numel (msec);
+      msec(end+1:3) = "0";     # pad msec with trailing zeros
+      ds = [ds(1:(nc-1)), msec, ds(nc+m_len:end)];  # zero pad ds as well
+    endif
 
-      if (nc > 0)
-        [tm, nc] = strptime (ds, f);
-        tm.usec = 1000 * str2double (msec);
-      endif
+    ## replace FFF with digits to guarantee match in strptime.
+    f(idx:idx+2) = msec;
 
-    else
+    if (nc > 0)
       [tm, nc] = strptime (ds, f);
+      tm.usec = 1000 * str2double (msec);
     endif
-  unwind_protect_cleanup
-    if (isempty (TZ_orig))
-      unsetenv ("TZ");
-    else
-      setenv ("TZ", TZ_orig);
-    endif
-  end_unwind_protect
+
+  else
+    [tm, nc] = strptime (ds, f);
+  endif
 
   if (nc == columns (ds) + 1)
     found = true;
     y = tm.year + 1900; m = tm.mon + 1; d = tm.mday;
     h = tm.hour; mi = tm.min; s = tm.sec + tm.usec / 1e6;
     if (rY < ry)
       if (y > 1999)
         y -= 2000;
