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 -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 -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);