octave-bug-tracker
[Top][All Lists]
Advanced

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

[Octave-bug-tracker] [bug #59979] Unexpected format for output from date


From: John W. Eaton
Subject: [Octave-bug-tracker] [bug #59979] Unexpected format for output from datevec
Date: Mon, 1 Feb 2021 11:37:45 -0500 (EST)
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0

Follow-up Comment #16, bug #59979 (project octave):

Neglecting for a moment any strange display issues that might be due to
rounding (like showing 19 minutes and 60 seconds instead of 20 minutes and 0
seconds) I find the following results quite surprising:


octave> datevec (0)
ans =

   -1   12   31    0    0    0


Shouldn't that be 0 years, 0 months, 0 days, 0 hours, 0 minutes, and 0
seconds?  For comparision, it looks like datevec (1) is correct:


octave> datevec (1)
ans =

   0   1   1   0   0   0


Zero years, the first month and day, zero hours, minutes, and seconds. 
Similarly, I see what appears to be the correct result for datevec (1.1):


octave> datevec (1.1)
ans =

    0    1    1    2   24    0


0.1 days is 144 minutes, or 2 hours and 24 minutes.

So maybe we just need to do the right thing when the datenum is between 0 and
1?

Looking at datevec.m, I see:


## Algorithm: Peter Baum (http://vsg.cape.com/~pbaum/date/date0.htm)


That link is no longer valid.  Maybe we could update it?  And also


  else   # datenum input

    if (! iscolumn (date))
      date_sz = size (date);
      do_resize = true;
    endif
    date = date(:);

    ## Move day 0 from midnight -0001-12-31 to midnight 0000-3-1
    z = double (floor (date) - 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.
    b = z - 0.25 + a - floor (a / 4);
    ## Calculate the year (year starts on March 1).
    y = floor (b / 365.25);
    ## Calculate day in year.
    c = fix (b - floor   else   # datenum input

    if (! iscolumn (date))
      date_sz = size (date);
      do_resize = true;
    endif
    date = date(:);

    ## Move day 0 from midnight -0001-12-31 to midnight 0000-3-1
    z = double (floor (date) - 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.
    b = z - 0.25 + a - floor (a / 4);
    ## Calculate the year (year starts on March 1).
    y = floor (b / 365.25);
    ## Calculate day in year.
    c = fix (b - floor (365.25 * y)) + 1;
    ## Calculate month in year.
    m = fix ((5 * c + 456) / 153);
    d = c - fix ((153 * m - 457) / 5);
    ## Move to Jan 1 as start of year.
    ++y(m > 12);
    m(m > 12) -= 12;

    ## Convert hour-minute-seconds.  Attempt to account for precision of
    ## datenum format.

    fracd = date - floor (date);
    tmps = abs (eps*86400*date);
    tmps(tmps == 0) = 1;
    srnd = 2 .^ floor (- log2 (tmps));
    s = round (86400 * fracd .* srnd) ./ srnd;
    h = floor (s / 3600);
    s -= 3600 * h;
    mi = floor (s / 60);
    s -= 60 * mi;

  endif
(365.25 * y)) + 1;
    ## Calculate month in year.
    m = fix ((5 * c + 456) / 153);
    d = c - fix ((153 * m - 457) / 5);
    ## Move to Jan 1 as start of year.
    ++y(m > 12);
    m(m > 12) -= 12;

    ## Convert hour-minute-seconds.  Attempt to account for precision of
    ## datenum format.

    fracd = date - floor (date);
    tmps = abs (eps*86400*date);
    tmps(tmps == 0) = 1;
    srnd = 2 .^ floor (- log2 (tmps));
    s = round (86400 * fracd .* srnd) ./ srnd;
    h = floor (s / 3600);
    s -= 3600 * h;
    mi = floor (s / 60);
    s -= 60 * mi;

  endif


There seems to be some ad hoc fudging here.  What is the real justification
for "K1 = 0.25 is to avoid rounding problems" and "K2 = 0.25 is to avoid
rounding problems"?  Are these arbitrary values really helpful in all cases? 
Maybe there is a better way?  This code appears to be mostly unchanged since
it was added to Octave.  (Note also that it was added long ago, before we used
Mercurial, when I was the only one committing changes, so looking at the
Mercurial logs won't give you proper author info.)

In any case, I don't think the algorithm is correct for small datenum values
and that the problems are not just display issues.

    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?59979>

_______________________________________________
  Message sent via Savannah
  https://savannah.gnu.org/




reply via email to

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