Bug #70811 [Com]: Future date calculation error if DST

From: Date: Fri, 30 Oct 2015 07:55:39 +0000
Subject: Bug #70811 [Com]: Future date calculation error if DST
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-196912@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=70811&edit=1

 ID:                 70811
 Comment by:         ricardosanchez at orangemail dot es
 Reported by:        ricardosanchez at orangemail dot es
 Summary:            Future date calculation error if DST
 Status:             Not a bug
 Type:               Bug
 Package:            Date/time related
 Operating System:   Linux
 PHP Version:        5.6.14
 Block user comment: N
 Private report:     N

 New Comment:

Well, so it is a bug on documentation, because in it, this "way of calculating dates" is
not explained at all: Nor a note, nor an example, nor explained how it calculates and how it affects
the individual date-time parts...

I expect that if I want to add +7 days, it will add 7 days (2015-10-20 15:00 +7 days = 2015-10-27
15:00), but if I want to add hours +168 hours, it must add hours (real hours, so 2015-10-20 14:00). 

If anybody really wants to add +7 days, he can calculate that "frequently" 7 days = 168
hours. But not always 168 hours == 7 complete days (as well as not all days have 24 hours, 0 minutes
and 0 seconds (Leap second, you are not forgotten), nor all February months have 28 days...)

The same happens with +1 month: 2015-01-31 +1 month = 2015-03-03... well, supposing that all months
have 31 days all of them... It is not explained how it works at all on documentation...


Previous Comments:
------------------------------------------------------------------------
[2015-10-29 12:21:18] requinix@php.net

I don't believe this is a bug because there is a misunderstanding here in what the function is
supposed to do.

When you say "+168 hours", strtotime() does not interpret that as an amount of elapsed
time that you wish to add. As in what might happen if you set a timer for 168 hours and waited for
it to count down to zero.

What it does is manipulate the date/time according to the spec you've given it. What you
effectively created is the time "2015-10-20 183:00". Obviously not valid, the date then
gets fixed: 183 hours is 7 days 15 hours, the date is incremented by 7 days and the hour is set to
15, resulting in "2015-10-27 15:00". Which is valid.

(With a higher number you could cause it to overflow again. 336 hours is two weeks and would create
"2015-10-34 15:00", causing a second overflow into the month part, from October into
November, and you would get "2015-11-03 15:00". Even more and you could overflow into the
year.)

This is exactly the same thing that happens if you used mktime() like
  date("Y-m-d H:i", mktime(15 + 168, 0, 0, 10, 20, 2015))

When you do the math yourself you deal with actual elapsed time. Because that is how Unix timestamps
work: they count the number of seconds elapsed since the Unix epoch (1970-01-01 00:00:00 UTC). That
means you're creating a new time that is exactly 168 hours further in the future. One of those
hours is "lost" when the clock rewinds at the end of DST and so you get 14:00.


The moral is:
1. strtotime() is for modifying the date string according to how you want to affect the individual
parts. +168 hours will literally add 168 hours to the time, then the time and date components will
overflow until it becomes valid again.
2. Doing math on the Unix timestamp is for dealing with the flow of time as actually perceived by
human beings. +168 hours will literally increase the amount of time elapsed since the Unix epoch by
168 hours.
3. Dealing with dates programmatically is not trivial. Never has been, probably never will be. In
any language.

------------------------------------------------------------------------
[2015-10-29 11:25:53] ricardosanchez at orangemail dot es

Description:
------------
---
From manual page: http://www.php.net/function.strtotime
---

strtotime( $date . ' +24 hours' ) adds +1 extra hour if between these +24 hours changes
happens a DST change (equivalent to add +25 hours instead +24 hours in case of one hour delayed due
to DST time change)

Test script:
---------------
// For a start date (before DST - Daily Save Time change (3am -> 2am again...))
$date_start = '2015-10-20 15:00';

// Two ways to add 168 hours (7 days). DST changes on 2015-10-25, so result expected is 2015-10-27
14:00 (2015-10-20 15:00 +168 hours)

$date_end_ok = date( 'Y-m-d H:i', strtotime( $date_start ) + 168 * 3600 ); // It adds 168
hours OK >> Result: 2015-10-27 14:00

$date_end_error = date( 'Y-m-d H:i', strtotime( $date_start . ' +168 hours' ) );
// It adds 169 hours instead! >> Result 2015-10-27 15:00

echo "Date initial $date_start - date limit OK (+168 * 3600) : $date_end_ok >> date limit
ERROR (+168 hours) $date_end_error";


Expected result:
----------------
$date_end_ok and $date_end_error must be the same => +168 hours OK: 2015-10-27 14:00


Actual result:
--------------
$date_end_error = date( 'Y-m-d H:i', strtotime( $date_start . ' +168 hours' ) );
// It adds 169 hours instead 168 hours, because on 2015-10-25 an hour is delayed due DST time
change! >> Actual result 2015-10-27 15:00


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=70811&edit=1


Thread (3 messages)

« previous php.bugs (#196912) next »