php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #70811 Future date calculation error if DST
Submitted: 2015-10-29 11:25 UTC Modified: 2015-10-29 12:21 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: ricardosanchez at orangemail dot es Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 5.6.14 OS: Linux
Private report: No CVE-ID: None
 [2015-10-29 11:25 UTC] 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

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-10-29 12:21 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2015-10-29 12:21 UTC] 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-30 07:55 UTC] ricardosanchez at orangemail dot es
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...
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue May 21 10:02:33 2024 UTC