Datestr problem with Hour

I wrote a test routine to set a start time stamp and step through hours.
function HourlyDateTEST2()
dvec(1)=2014;
dvec(2)=06;
dvec(3)=15;
dvec(4)=21;
dvec(5)=00;
dvec(6)=00;
dateVal=datenum(dvec);
for ii = 1:7
datestr(dateVal, 'mm/dd/yyyy HH:MM:SS')
dateVal = dateVal + 1/24;
end;
end
The output looks like the following:
06/15/2014 21:00:00
06/15/2014 22:00:00
06/15/2014 23:00:00
06/15/2014 00:00:00
06/16/2014 01:00:00
06/16/2014 02:00:00
06/16/2014 03:00:00
Notice that the 4th line has the wrong date. Should be 06/16/2014 00:00:00.
What am I doing wrong?
I am using MATLAB R2014a.

 Accepted Answer

Star Strider
Star Strider on 15 Jun 2014
That’s easiest with the addtodate function.

13 Comments

dpb
dpb on 15 Jun 2014
Edited: dpb on 15 Jun 2014
Excepting for
>> addtodate(datenum(now),[1:7].','h')
Error using addtodate (line 49)
Quantity must be a numeric scalar.
>>
it would be. Don't know why it wasn't vectorized; seems easy enough to have been.
ADDENDUM
Actually, now I realize why...just played at adding a version for my R12 using datenum instead of the current mex file that does the guts and where one has a problem in a neat implementation is adding the vector to the right datevec column.
One can't write
v=datevec(dn); % the datevec from the input origin
v(idx)=v(idx)+addVal; % addVal is the dT to add for field idx
R=datenum(v); % if addVal is a vector as in my usage above
Can only write it as a whole vector
vadd=v(idx)+addVal;
and then pass the scalar values for the other fields explicitly. That means, as near as I can tell, having to use a CASE statement to explicitly write each possible field individually. Doable, but not neat; TMW chose to not...
Definite needs vectorizing, since that behavior is still present in 2014a.
When I use it, it’s usually in a loop, which is actually not too much of a hindrance unless there are a lot of them. Using it in a loop does get around the floating-point-approximation problem, though.
I’ll submit vectorizing it as a ‘Support’ request. Nothing ventured, nothing gained. (My last brilliant idea was to add an engineering notation edit descriptor to the fprintf options. Maybe 1014b?)
dpb
dpb on 15 Jun 2014
Well, there's always arrayfun and friends...
My application requires a loop. I tried two approaches:
Approach 1 -- Offset from start date.
function HourlyDateTEST2()
dvec(1) = 2014;
dvec(2) = 06;
dvec(3) = 15;
dvec(4) = 21;
dvec(5) = 00;
dvec(6) = 00;
dateStart = datenum(dvec);
for ii = 0:6
dateVal = addtodate(dateStart, ii, 'hour');
datestr(dateVal, 'mm/dd/yyyy HH:MM:SS')
end;
end
Result:
06/15/2014 21:00:00
06/15/2014 22:00:00
06/15/2014 23:00:00
*06/16/2014 00:00:00*
06/16/2014 01:00:00
06/16/2014 02:00:00
06/16/2014 03:00:00
Approach 2 – Update dateVal on each loop
function HourlyDateTEST3()
dvec(1) = 2014;
dvec(2) = 06;
dvec(3) = 15;
dvec(4) = 21;
dvec(5) = 00;
dvec(6) = 00;
dateVal = datenum(dvec);
for ii = 0:6
datestr(dateVal, 'mm/dd/yyyy HH:MM:SS')
dateVal = addtodate(dateVal, 1, 'hour');
end;
end
Result:
06/15/2014 21:00:00
06/15/2014 22:00:00
06/15/2014 23:00:00
*06/15/2014 00:00:00*
06/16/2014 01:00:00
06/16/2014 02:00:00
06/16/2014 03:00:00
Approach 1 worked but Approach 2 gave the same result as using dateVal + 1/24. Must still be some round off error.
I'll use Approach 1.
dpb
dpb on 16 Jun 2014
...My application requires a loop.
Why should that be, necessarily?
...
Approach 2 – Update dateVal on each loop...
Of course; it's the same thing as you did originally, just recast.
It's no different than running a for loop over a floating point iterator that ends up either one under or one over the expected number depending on which way the rounding goes on any particular numeric value.
Star Strider
Star Strider on 16 Jun 2014
Edited: Star Strider on 16 Jun 2014
I’m glad you found a workable solution.
This is interesting. The date functions are usually robust. I submitted the results of your experiment (the URL of this thread) to MathWorks Support and reported it as a bug.
I also asked that any replies to me be copied to Harold Kidder and to dpb.
dpb
dpb on 16 Jun 2014
Edited: dpb on 16 Jun 2014
...date functions are usually robust
The symptoms are quite easy to generate if one uses floating point computations outside the internals of the functions as did OP in both of his cases that fail. It's unavoidable when the roundoff is accumulated externally as both of those cases do.
If, otoh, one starts w/ the base value and increments that value by the integer values, then the roundoff is limited and joy ensues.
It's why I've always preferred the vector solution as in original response; one avoids making the mistake by accident or forgetting.
I could understand being off by a few seconds or even a minute as the result of floating-point approximation error, but having the time roll back to midnight of the same day, rather than advancing to midnight (or close to it) of the next day is clearly a bug!
dpb
dpb on 16 Jun 2014
Edited: dpb on 16 Jun 2014
The error will only be ~1E-15 or so on the datenum; since the day in the whole part, if truncate ( fix instead of round as example), the day would still be the preceding; only when the fractional part is 0+ instead of 9- will the whole portion have yet turned over. So, the datenum value isn't off by a whole day in absolute value, only that it hasn't yet turned over the new leaf.
I've mentioned earlier I've had cases where I could see the effects when using floating point outside the various functions and then utilizing those values inside. Your case here is the only time I've ever observed it within where up until now the rounding has never shown up in anything I've ever caught it at, anyway.
I was going to demonstrate the value difference but interestingly this morning I can't duplicate it...I just reran OPs test here and received--
>> for ii = 1:7
datestr(dateVal, 'mm/dd/yyyy HH:MM:SS')
dateVal = dateVal + 1/24;
end
ans =
06/15/2014 21:00:00
ans =
06/15/2014 22:00:00
ans =
06/15/2014 23:00:00
ans =
06/16/2014 00:00:00
...
Now that one I can't explain...that's Twilight Zone stuff, there.
ADDENDUM
Just for grins I closed and restarted Matlab and can't reproduce it there, either. Yet last night got the OPs results. Wishing now had save the intermediaries then but they were already in the bit bucket....
MOST peculiar...
You obviously did that from the Command Window. I just now did the same thing in my test function (I clear and close all at the top) and the Command Window and repeated OP’s results in both.
dpb
dpb on 16 Jun 2014
Edited: dpb on 16 Jun 2014
Yes all I did up to now was at the command line. I also just put in a script and still can't reproduce it this AM.
If you can repeat it, save the datenum values and then run one of the integer-addition cases also saving the datenums there. Then do
diff(dnfloatcase,dnintegercase)
I reported this a a bug to TMW yesterday. I got an e-mail a few minutes ago that said that they were able to reproduce it in R2014a, and will fix it ‘in a future release’. Whether this means an update or wait until R2014b I’m not sure. I sent them the link to this thread, so they have all the information they need.
Congratulations to Harold for discovering it!
dpb
dpb on 16 Jun 2014
I'd still be curious if you can generate the two cases to see the actual datenum values. You running 32- or 64-bit version?
I'm still greatly puzzled how can't now seem to reproduce it here when was certain saw it in the original loop version. I suppose I could have mistakenly thought I saw what I didn't.

Sign in to comment.

More Answers (1)

dpb
dpb on 15 Jun 2014
What am I doing wrong?
for ii = 1:7
datestr(dateVal, 'mm/dd/yyyy HH:MM:SS')
dateVal = dateVal + 1/24;
...
Using floating point arithmetic; the rounding in the accumulation of the 1/24 factor caused it.
Use
>> datestr(datenum(dvec(1),dvec(2),dvec(3),dvec(4)+[0:7].',dvec(5),dvec(6)))
ans =
15-Jun-2014 21:00:00
15-Jun-2014 22:00:00
15-Jun-2014 23:00:00
16-Jun-2014 00:00:00
16-Jun-2014 01:00:00
16-Jun-2014 02:00:00
16-Jun-2014 03:00:00
16-Jun-2014 04:00:00
>>
instead (add the integer hours, not the fractional days) to avoid rounding errors.

Categories

Products

Asked:

on 15 Jun 2014

Commented:

dpb
on 16 Jun 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!