octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Octave-forge Date Functions Patch


From: John W. Eaton
Subject: Octave-forge Date Functions Patch
Date: Thu, 16 Mar 2006 15:31:45 -0500

On  7-Jan-2006, Bill Denney wrote:

| Here is a patch to the functions datesplit, datevec, and datenum to allow 
| formats (as in strptime) to be used.  It's very slow (at least on my 
| testing in cygwin which I know is slow to begin with), so it may be 
| worthwhile for someone to vectorize strptime.
| 
| Changelog:
| 
| 2005 Jan 7: Bill Denney
| 
|      datesplit.m, datevec.m, datenum.m: allow the specification of a format
|      for the date

Sorry, I didn't realize that these were submitted here until after I
committed the changes.  Can you please see if there are any changes in
your patch that should be applied to the current CVS sources and send
a revised patch relative to that?

Thanks,

jwe


| Bill
| 
| -- 
| "Hurray for our side."  -- Flynn, _Tron_
| Index: datenum.m
| ===================================================================
| RCS file: /cvsroot/octave/octave-forge/main/time/datenum.m,v
| retrieving revision 1.8
| diff -u -r1.8 datenum.m
| --- datenum.m 8 Sep 2005 02:00:18 -0000       1.8
| +++ datenum.m 7 Jan 2006 05:50:36 -0000
| @@ -1,6 +1,6 @@
|  ## -*- texinfo -*-
|  ## @deftypefn {Function File} {} datenum(Y, M, D [, h , m [, s]])
| -## @deftypefnx {Function File} {} datenum('date' [, P])
| +## @deftypefnx {Function File} {} datenum('date' [, P [, fmt]])
|  ## Returns the specified local time as a day number, with Jan 1, 0000
|  ## being day 1. By this reckoning, Jan 1, 1970 is day number 719529.  
|  ## The fractional portion, corresponds to the portion of the specified day.
| @@ -12,6 +12,17 @@
|  ## Days before the beginning of the month go to the previous month.
|  ## Days can be fractional.
|  ##
| +## The parameter @var{P} is needed to convert date strings with 2 digit
| +## years into dates with 4 digit years.  2 digit years are assumed to be
| +## between @var{P} and @code{P+99}. If @var{P} is not given then the 
| +## current year - 50 is used, so that dates are centered on the present.
| +## For birthdates, you would want @var{P} to be current year - 99.  For
| +## appointments, you would want @var{P} to be current year.
| +##
| +## The parameter @var{fmt} is optional and it allows you to specify the
| +## format as in @code{strftime}.  See the @code{strftime} help for how
| +## to specify a format string.
| +##
|  ## XXX WARNING XXX this function does not attempt to handle Julian
|  ## calendars so dates before Octave 15, 1582 are wrong by as much
|  ## as eleven days.  Also be aware that only Roman Catholic countries
| @@ -22,7 +33,7 @@
|  ## XXX WARNING XXX leap seconds are ignored.  A table of leap seconds
|  ## is available on the Wikipedia entry for leap seconds.
|  ##
| -## @seealso{date,clock,now,datestr,datevec,calendar,weekday}
| +## 
@seealso{date,clock,now,datestr,datevec,calendar,weekday,strptime,strftime}
|  ## @end deftypefn
|  
|  ## Algorithm: Peter Baum (http://vsg.cape.com/~pbaum/date/date0.htm)
| @@ -32,12 +43,13 @@
|  function n = datenum(Y,M,D,h,m,s)
|    persistent monthstart = [306,337,0,31,61,92,122,153,184,214,245,275];
|  
| -  if nargin == 0 || (nargin > 2  && ischar(Y)) || nargin > 6
| +  if nargin == 0 || (nargin > 3 && isstr(Y)) || nargin > 6
|      usage("n=datenum('date' [, P]) or n=datenum(Y, M, D [, h, m [, s]])");
|    endif
| -  if ischar(Y)
| -    if nargin < 2, M=[]; endif
| -    [Y,M,D,h,m,s] = datevec(Y,M);
| +  if (isstr(Y) || iscellstr(Y))
| +    if nargin < 2, M=[]; endif ## set P empty
| +    if nargin < 3, D=""; endif ## set fmt empty
| +    [Y,M,D,h,m,s] = datevec(Y,M,D);
|    else
|      if nargin < 6, s = 0; endif
|      if nargin < 5, m = 0; endif
| Index: datesplit.m
| ===================================================================
| RCS file: /cvsroot/octave/octave-forge/main/time/datesplit.m,v
| retrieving revision 1.6
| diff -u -r1.6 datesplit.m
| --- datesplit.m       2 May 2005 15:30:16 -0000       1.6
| +++ datesplit.m       7 Jan 2006 05:50:37 -0000
| @@ -17,6 +17,7 @@
|  ## -*- texinfo -*-
|  ## @deftypefn {Function File} {Y =} datesplit(date, P)
|  ## @deftypefnx {Function File} {[Y,M,D,h,m,s] =} datesplit(date, P)
| +## @deftypefnx {Function File} {[Y,M,D,h,m,s] =} datesplit(date, P, fmt)
|  ## Split a date string into the Year, Month, Day, hour, minute, and
|  ## second.  This routine tries to be as forgiving as possible to the
|  ## date input while requiring that the date is not ambiguous.
| @@ -26,10 +27,10 @@
|  ## along the same lines, where possible, commas were allowed with
|  ## spaces, and the year/month/day separators were allowed as period (.),
|  ## slash (/), and dash (-).  Not all format possibilities are shown in
| -## the following table, but a date like @code{dd-mmm-yyyy HH:MM:SS} is
| -## parsed just as well as @code{d/mmm.yyyy,  ,H:MM, AM}.
| +## the following table, but a date like @var{dd-mmm-yyyy HH:MM:SS} is
| +## parsed just as well as @var{d/mmm.yyyy,  ,H:MM, AM}.
|  ##
| -## Supported @code{date} formats include (the same as datestr):
| +## Supported @var{date} formats include (the same as datestr):
|  ## @multitable @columnfractions 0.1 0.45 0.45
|  ## @item @strong{Code} @tab @strong{Format} @tab @strong{Example}
|  ## @item  0  @tab dd-mmm-yyyy HH:MM:SS    @tab 07-Sep-2000 15:38:09
| @@ -59,12 +60,16 @@
|  ## @item 31  @tab yyyy-mm-dd HH:MM:SS     @tab 1047-03-13 13:26:03
|  ## @end multitable
|  ##
| -## The parameter @code{P} is needed to convert date strings with 2 digit
| +## The parameter @var{P} is needed to convert date strings with 2 digit
|  ## years into dates with 4 digit years.  2 digit years are assumed to be
| -## between @code{P} and @code{P+99}. If @code{P} is not given then the 
| +## between @var{P} and @code{P+99}. If @var{P} is not given then the 
|  ## current year - 50 is used, so that dates are centered on the present.
| -## For birthdates, you would want @code{P} to be current year - 99.  For
| -## appointments, you would want @code{P} to be current year.
| +## For birthdates, you would want @var{P} to be current year - 99.  For
| +## appointments, you would want @var{P} to be current year.
| +##
| +## The parameter @var{fmt} is optional and it allows you to specify the
| +## format as in strptime and strftime.  See the strftime help for how to
| +## specify a format string.
|  ##
|  ## This function makes no strong attempt to verify the accuracy of the
|  ## numbers that it returns in that it doesn't (currently) check to see
| @@ -74,12 +79,10 @@
|  ## but if there is doubt, datesplit will return an error instead of
|  ## trying to guess the wrong value.
|  ##
| -## @seealso{date,clock,now,datestr,datenum,calendar,weekday} 
| +## 
@seealso{date,clock,now,datestr,datenum,calendar,weekday,strftime,strptime}
|  ## @end deftypefn
|  
|  ## TODO:
| -##  * Some formats are ambiguous.  Allow the user to specify the format
| -##    to remove ambiguity.
|  ##  * Validate the dates.
|  ##  * Possible bug (after dates are validated): There are times where
|  ##    the year is assumed, Feb 29 may be a valid date, but with the
| @@ -89,11 +92,17 @@
|  
|  ## Author: Bill Denney <address@hidden>
|  
| -function [y, m, d, h, mi, s] = datesplit(ds, P)
| +function [y, m, d, h, mi, s] = datesplit(ds, P, fmt)
|  
| -  if nargin < 2
| +  if (nargin < 1)
| +    usage("datesplit(ds, P, fmt)");
| +  endif
| +  if (nargin < 2)
|      P = [];
|    endif
| +  if (nargin < 3)
| +    fmt = "";
| +  endif
|  
|    today = datevec(now);
|  
| @@ -106,17 +115,48 @@
|    global __day_names   = ["Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat"];
|    global __time_names  = ["AM";"PM"];
|  
| -  if (iscellstr(ds))
| +  if iscell(ds)
| +    if (prod(size(ds)) > 1)
| +      error("datesplit: only single element cells are allowed.");
| +    endif
|      ds = ds{1};
|    endif
| +
|    ds = tolower(deblank(ds));
|  
| -  if (nargin < 1)
| -    error("datesplit: no input arguments");
| -  elseif (nargin == 1)
| -    fmt = [];
| +  ## it's easy if we have a format to use
| +  if (~ isempty(fmt))
| +    for i = 1:size(ds,1)
| +      datestruct(i) = strptime(ds(i,:), fmt);
| +    endfor
| +
| +    for i = 1:length(datestruct)
| +      y(i) = datestruct.year;
| +      m(i) = datestruct.mon;
| +      d(i) = datestruct.mday;
| +      h(i) = datestruct.hour;
| +      mi(i) = datestruct.min;
| +      s(i) = datestruct.sec;
| +    endfor
| +
| +    ## convert the digits to the digits that we use in this function
| +    if all(y < 170)
| +      ## strftime splits between the current and the last century at
| +      ## 1970.
| +
| +      ## make them use the P that is specified by our function and
| +      ## convert to four digit years
| +      y = mod(y,100);
| +      y(y <= P) = y(y <= P) + 100;
| +      y = y + 1900;
| +    endif
| +
| +    ## convert the months from zero to one based
| +    m = m + 1;
| +    return;
|    endif
| -  %% we have to determine the format, this could be error prone
| +
| +  ## we have to determine the format, this could be error prone
|  
|    ## format  0  dd-mmm-yyyy HH:MM:SS    e.g. 07-Sep-2000 15:38:09
|    [match, d, m, y, h, mi, s, ap] = \
| Index: datevec.m
| ===================================================================
| RCS file: /cvsroot/octave/octave-forge/main/time/datevec.m,v
| retrieving revision 1.7
| diff -u -r1.7 datevec.m
| --- datevec.m 8 Sep 2005 02:00:18 -0000       1.7
| +++ datevec.m 7 Jan 2006 05:50:37 -0000
| @@ -2,6 +2,7 @@
|  ## -*- texinfo -*-
|  ## @deftypefn {Function File} {V =} datevec(date)
|  ## @deftypefnx {Function File} {[Y,M,D,h,m,s] =} datevec(date, P)
| +## @deftypefnx {Function File} {[Y,M,D,h,m,s] =} datevec(date, P, fmt)
|  ## Breaks the number of days since Jan 1, 0000 into a year-month-day
|  ## hour-minute-second format. By this reckoning, Jan 1, 1970 is day
|  ## number 719529.  The fractional portion of @code{date} corresponds to the
| @@ -19,11 +20,14 @@
|  ## For birthdates, you would want @code{P} to be current year - 99.  For
|  ## appointments, you would want @code{P} to be current year.
|  ##
| +## The optional arguement @var{fmt} is allowed to indicate a format
| +## (parsable by @code{strptime}) to remove ambiguity about the date format.
| +##
|  ## Dates must be represented as an integer date code or in a format
|  ## recognisable by datesplit as either a string, string array, cell, or
|  ## cell string array.
|  ##
| -## @seealso{date,clock,now,datestr,datenum,calendar,weekday,datesplit} 
| +## 
@seealso{date,clock,now,datestr,datenum,calendar,weekday,datesplit,strptime,strftime}
 
|  ## @end deftypefn
|  
|  ## Algorithm: Peter Baum (http://vsg.cape.com/~pbaum/date/date0.htm)
| @@ -31,14 +35,15 @@
|  ## This program is granted to the public domain.
|  ## Modified-by: Bill Denney <address@hidden>
|  
| -function [Y,M,D,h,m,s] = datevec(date,P)
| +function [Y,M,D,h,m,s] = datevec(dv,P,fmt)
|  
| -  if nargin == 0 || nargin > 2
| -    usage("V=datevec(n) or [Y,M,D,h,m,s]=datevec(n)");
| +  if nargin == 0 || nargin > 3
| +    usage("V=datevec(n,P,fmt) or [Y,M,D,h,m,s]=datevec(n,P,fmt)");
|    endif
|    if nargin < 2, P = []; endif
| +  if nargin < 3, fmt = ""; endif
|  
| -  if (ischar(date) || iscellstr(date))
| +  if (isstr(dv) || iscellstr(dv))
|      ## handle strings
|      if isempty(P)
|        tm = localtime(time);
| @@ -49,22 +54,28 @@
|                           "Jul";"Aug";"Sep";"Oct";"Nov";"Dec"];
|      global __time_names = ["AM";"PM"];
|  
| -    Y = h = m = s = zeros(rows(date),1);
| +    if iscellstr(dv)
| +      niter = length(dv(:));
| +    else
| +      niter = size(dv,1);
| +    endif
| +
| +    Y = h = m = s = zeros(niter,1);
|      M = D = ones(size(Y));
|  
| -    for i = 1:size(date,1)
| -      if (iscellstr(date))
| -     thisdate = date{i};
| +    for i = 1:niter
| +      if (iscellstr(dv))
| +     thisdv = dv{i};
|        else
| -     thisdate = date(i,:);
| +     thisdv = dv(i,:);
|        endif
| -      [Y(i) M(i) D(i) h(i) m(i) s(i)] = datesplit(date(i,:), P);
| +      [Y(i) M(i) D(i) h(i) m(i) s(i)] = datesplit(thisdv, P, fmt);
|      endfor
|    else
|      ## handle date numbers
|  
|      ## Move day 0 from midnight -0001-12-31 to midnight 0001-3-1
| -    z = floor(date) - 60; 
| +    z = floor(dv) - 60; 
|      ## Calculate number of centuries; K1=0.25 is to avoid rounding problems.
|      a = floor((z-0.25)/36524.25);
|      ## Days within century;  K2=0.25 is to avoid rounding problems.
| @@ -81,7 +92,7 @@
|      M(M>12)-=12;
|  
|      ## Convert hour-minute-seconds
| -    s = 86400*(date-floor(date));
| +    s = 86400*(dv-floor(dv));
|      h = floor(s/3600);
|      s = s - 3600*h;
|      m = floor(s/60);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]