diff scripts/time/datevec.m @ 13848:40e32fe44aaa

Ugrade time functions to accept millisecond format string FFF (Bug #34586) * datestr.m: Add millisecond FFF format. Change numerical formats 21,22,29 to match Matlab. Remove unused persistent variables. Vectorize some for loops. Use strrep rather than regexp where possible for speed. * datevec.m: Add millisecond FFF format. Use strrep rather than regexp where possible for speed. * datenum.m: Update docstring. Use modern coding style. Only calculate second output argument if requested. Allow cellstr inputs.
author Rik <octave@nomad.inbox5.com>
date Wed, 09 Nov 2011 14:49:09 -0800
parents c792872f8942
children d490ca8ab1a5
line wrap: on
line diff
--- a/scripts/time/datevec.m	Tue Nov 08 19:59:37 2011 -0500
+++ b/scripts/time/datevec.m	Wed Nov 09 14:49:09 2011 -0800
@@ -31,9 +31,9 @@
 ## @var{f} is the format string used to interpret date strings
 ## (see @code{datestr}).
 ##
-## @var{p} is the year at the start of the century in which two-digit years
-## are to be interpreted in.  If not specified, it defaults to the current
-## year minus 50.
+## @var{p} is the year at the start of the century to which two-digit years
+## will be referenced.  If not specified, it defaults to the current year
+## minus 50.
 ## @seealso{datenum, datestr, date, clock, now}
 ## @end deftypefn
 
@@ -46,13 +46,15 @@
 
 ## The function __date_str2vec__ is based on datesplit by Bill Denney.
 
-function [y, m, d, h, mi, s] = datevec (date, varargin)
+function [y, m, d, h, mi, s] = datevec (date, f = [], p = [])
 
   persistent std_formats nfmt;
 
   if (isempty (std_formats))
     std_formats = cell ();
     nfmt = 0;
+    ## These formats are specified by Matlab to be parsed
+    ## The '# XX' refers to the datestr numerical format code
     std_formats{++nfmt} = "dd-mmm-yyyy HH:MM:SS";   # 0
     std_formats{++nfmt} = "dd-mmm-yyyy";            # 1
     std_formats{++nfmt} = "mm/dd/yy";               # 2
@@ -62,6 +64,8 @@
     std_formats{++nfmt} = "HH:MM";                  # 15
     std_formats{++nfmt} = "HH:MM PM";               # 16
     std_formats{++nfmt} = "mm/dd/yyyy";             # 23
+
+    ## These are other formats that Octave tries
     std_formats{++nfmt} = "mmm-dd-yyyy HH:MM:SS";
     std_formats{++nfmt} = "mmm-dd-yyyy";
     std_formats{++nfmt} = "dd mmm yyyy HH:MM:SS";
@@ -72,8 +76,6 @@
     std_formats{++nfmt} = "dd.mmm.yyyy";
     std_formats{++nfmt} = "mmm.dd.yyyy HH:MM:SS";
     std_formats{++nfmt} = "mmm.dd.yyyy";
-
-    ## Custom formats.
     std_formats{++nfmt} = "mmmyy";                  # 12
     std_formats{++nfmt} = "mm/dd/yyyy HH:MM";
   endif
@@ -82,22 +84,14 @@
     print_usage ();
   endif
 
-  switch (nargin)
-  case 1
+  if (ischar (date))
+    date = cellstr (date);
+  endif
+
+  if (isnumeric (f))
+    p = f;
     f = [];
-    p = [];
-  case 2
-    if (ischar (varargin{1}))
-      f = varargin{1};
-      p = [];
-    else
-      f = [];
-      p = varargin{1};
-    endif
-  case 3
-      f = varargin{1};
-      p = varargin{2};
-  endswitch
+  endif
 
   if (isempty (f))
     f = -1;
@@ -107,10 +101,6 @@
     p = (localtime (time ())).year + 1900 - 50;
   endif
 
-  if (ischar (date))
-    date = cellstr (date);
-  endif
-
   if (iscell (date))
 
     nd = numel (date);
@@ -132,7 +122,7 @@
         endif
       endfor
     else
-      ## Decipher the format string just once for sake of speed.
+      ## Decipher the format string just once for speed.
       [f, rY, ry, fy, fm, fd, fh, fmi, fs] = __date_vfmt2sfmt__ (f);
       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);
@@ -142,7 +132,7 @@
       endfor
     endif
 
-  else
+  else   # datenum input
 
     date = date(:);
 
@@ -187,38 +177,7 @@
 function [f, rY, ry, fy, fm, fd, fh, fmi, fs] = __date_vfmt2sfmt__ (f)
 
   ## Play safe with percent signs.
-  f = strrep(f, "%", "%%");
-
-  ## Dates to lowercase (note: we cannot convert MM to mm).
-  f = strrep (f, "YYYY", "yyyy");
-  f = strrep (f, "YY", "yy");
-  f = strrep (f, "QQ", "qq");
-  f = strrep (f, "MMMM", "mmmm");
-  f = strrep (f, "MMM", "mmm");
-  f = strrep (f, "DDDD", "dddd");
-  f = strrep (f, "DDD", "ddd");
-  f = strrep (f, "DD", "dd");
-  ## Times to uppercase (also cannot convert mm to MM).
-  f = strrep (f, "hh", "HH");
-  f = strrep (f, "ss", "SS");
-  f = strrep (f, "pm", "PM");
-  f = strrep (f, "am", "AM");
-
-  ## Right now, the format string may only contain these tokens:
-  ##
-  ## yyyy   4 digit year
-  ## yy     2 digit year
-  ## mmmm   month name, full
-  ## mmm    month name, abbreviated
-  ## mm     month number
-  ## dddd   weekday name, full
-  ## ddd    weekday name, abbreviated
-  ## dd     date
-  ## HH     hour
-  ## MM     minutes
-  ## SS     seconds
-  ## PM     AM/PM
-  ## AM     AM/PM
+  f = strrep (f, "%", "%%");
 
   if (! isempty (strfind (f, "PM")) || ! isempty (strfind (f, "AM")))
     ampm = true;
@@ -227,14 +186,14 @@
   endif
 
   ## Date part.
-  f = strrep (f, "yyyy", "%Y");
-  f = strrep (f, "yy", "%y");
+  f = regexprep (f, '[Yy][Yy][Yy][Yy]', "%Y");
+  f = regexprep (f, '[Yy][Yy]', "%y");
   f = strrep (f, "mmmm", "%B");
   f = strrep (f, "mmm", "%b");
   f = strrep (f, "mm", "%m");
-  f = strrep (f, "dddd", "%A");
-  f = strrep (f, "ddd", "%a");
-  f = strrep (f, "dd", "%d");
+  f = regexprep (f, '[Dd][Dd][Dd][Dd]', "%A");
+  f = regexprep (f, '[Dd][Dd][Dd]', "%a");
+  f = regexprep (f, '[Dd][Dd]', "%d");
 
   ## Time part.
   if (ampm)
@@ -245,7 +204,7 @@
     f = strrep (f, "HH", "%H");
   endif
   f = strrep (f, "MM", "%M");
-  f = strrep (f, "SS", "%S");
+  f = regexprep (f, '[Ss][Ss]', "%S");
 
   rY = rindex (f, "%Y");
   ry = rindex (f, "%y");
@@ -263,12 +222,25 @@
 
 function [found, y, m, d, h, mi, s] = __date_str2vec__ (ds, p, f, rY, ry, fy, fm, fd, fh, fmi, fs)
 
-  [tm, nc] = strptime (ds, f);
-
-  if (nc == size (ds, 2) + 1)
+  idx = strfind (f, "FFF");
+  if (! isempty (idx)) 
+    ## Kludge to handle FFF millisecond format since strptime does not
+    f(idx:idx+2) = []; 
+    [~, nc] = strptime (ds, f);
+    if (nc > 0)
+      msec = ds(nc:min(nc+2, end)); 
+      f = [f(1:idx-1) msec f(idx:end)]; 
+      [tm, nc] = strptime (ds, f);
+      tm.usec = 1000 * str2double (msec);
+    endif
+  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;
-    found = true;
     if (rY < ry)
       if (y > 1999)
         y -= 2000;
@@ -289,7 +261,6 @@
       tmp = localtime (time ());
       y = tmp.year + 1900;
     elseif (fy && fm && ! fd)
-      tmp = localtime (time ());
       d = 1;
     endif
     if (! fh && ! fmi && ! fs)
@@ -304,23 +275,30 @@
 
 endfunction
 
+
+%!demo
+%! ## Current date and time
+%! datevec (now ())
+
 %!shared nowvec
 %! nowvec = datevec (now); # Some tests could fail around midnight!
-# tests for standard formats: 0, 1, 2, 6, 13, 14, 15, 16, 23
-%!assert(datevec("07-Sep-2000 15:38:09"),[2000,9,7,15,38,9]);
-%!assert(datevec("07-Sep-2000"),[2000,9,7,0,0,0]);
-%!assert(datevec("09/07/00"),[2000,9,7,0,0,0]);
-%!assert(datevec("09/13"),[nowvec(1),9,13,0,0,0]);
-%!assert(datevec("15:38:09"),[nowvec(1:3),15,38,9]);
-%!assert(datevec("3:38:09 PM"),[nowvec(1:3),15,38,9]);
-%!assert(datevec("15:38"),[nowvec(1:3),15,38,0]);
-%!assert(datevec("03:38 PM"),[nowvec(1:3),15,38,0]);
-%!assert(datevec("03/13/1962"),[1962,3,13,0,0,0]);
-# other tests
-%!assert(all(datenum(datevec([-1e4:1e4]))==[-1e4:1e4]'))
+%!# tests for standard formats: 0, 1, 2, 6, 13, 14, 15, 16, 23
+%!assert (datevec ("07-Sep-2000 15:38:09"), [2000,9,7,15,38,9])
+%!assert (datevec ("07-Sep-2000"), [2000,9,7,0,0,0])
+%!assert (datevec ("09/07/00"), [2000,9,7,0,0,0])
+%!assert (datevec ("09/13"), [nowvec(1),9,13,0,0,0])
+%!assert (datevec ("15:38:09"), [nowvec(1:3),15,38,9])
+%!assert (datevec ("3:38:09 PM"), [nowvec(1:3),15,38,9])
+%!assert (datevec ("15:38"), [nowvec(1:3),15,38,0])
+%!assert (datevec ("03:38 PM"), [nowvec(1:3),15,38,0])
+%!assert (datevec ("03/13/1962"), [1962,3,13,0,0,0])
+
+%% Test millisecond format FFF
+%!assert (datevec ("15:38:21.25", "HH:MM:SS.FFF"), [nowvec(1:3),15,38,21.025])
+
+# Other tests
+%!assert (datenum (datevec ([-1e4:1e4])), [-1e4:1e4]')
 %!test
 %! t = linspace (-2e5, 2e5, 10993);
 %! assert (all (abs (datenum (datevec (t)) - t') < 1e-5));
-# demos
-%!demo
-%! datevec (now ())
+