php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #20382 strtotime ("Monday", $date) can produce incorrect output
Submitted: 2002-11-12 02:11 UTC Modified: 2005-06-21 02:18 UTC
Votes:17
Avg. Score:4.5 ± 0.8
Reproduced:14 of 14 (100.0%)
Same Version:7 (50.0%)
Same OS:7 (50.0%)
From: nickj-phpbugs at nickj dot org Assigned: derick
Status: Closed Package: Date/time related
PHP Version: 5CVS, 4CVS (2004-04-13) OS: *
Private report: No CVE-ID:
 [2002-11-12 02:11 UTC] nickj-phpbugs at nickj dot org
Strtotime() appears to produce incorrect output under some circumstances - specifically when wanting the date of a particular day of the week day of the week from a given starting date. For example, using 2001-3-20 as a starting point, we want the date for the next Monday. The correct answer is the 26th, but the result produced is the 25th (a Sunday). The correct result is given sometimes, so this appears to depend on the input.

A sample script to illustrate:
=======================================================
#!/root/php-4.2.3 -q
<?php

// report any errors at all
error_reporting (E_ALL);

// pass a date, supply a strtotime modifier, and get a date back
function getDateWithModifier($date, $modifier) {
        list ($year, $month, $day) = explode ("-",$date);
        $starting_timestamp = mktime (10,10,10,$month,$day,$year);
        $timestamp_with_modifier = strtotime ($modifier, $starting_timestamp);
        return date("Y-n-j", $timestamp_with_modifier);
}

print "<hr>\n";
print "from 2001-3-17, goto monday: " . getDateWithModifier("2001-3-17", "Monday") . "; should be 2001-3-19.<br>\n";
print "from 2001-3-18, goto monday: " . getDateWithModifier("2001-3-18", "Monday") . "; should be 2001-3-19.<br>\n";
print "from 2001-3-19, goto monday: " . getDateWithModifier("2001-3-19", "Monday") . "; should be 2001-3-19.<br>\n";
print "from 2001-3-20, goto monday: " . getDateWithModifier("2001-3-20", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-21, goto monday: " . getDateWithModifier("2001-3-21", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-22, goto monday: " . getDateWithModifier("2001-3-22", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-23, goto monday: " . getDateWithModifier("2001-3-23", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-24, goto monday: " . getDateWithModifier("2001-3-24", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-25, goto monday: " . getDateWithModifier("2001-3-25", "Monday") . "; should be 2001-3-26 ###.<br>\n";
print "from 2001-3-26, goto monday: " . getDateWithModifier("2001-3-26", "Monday") . "; should be 2001-3-26.<br>\n";
print "from 2001-3-27, goto monday: " . getDateWithModifier("2001-3-27", "Monday") . " ; should be 2001-4-2.<br>\n";
print "<hr>\n";

print "PHP version: " . phpversion(). "<br>\n";

?>
=======================================================

Produces this output:
=======================================================
[root@www tmp]# ./script.php 
<hr>
from 2001-3-17, goto monday: 2001-3-19; should be 2001-3-19.<br>
from 2001-3-18, goto monday: 2001-3-19; should be 2001-3-19.<br>
from 2001-3-19, goto monday: 2001-3-19; should be 2001-3-19.<br>
from 2001-3-20, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-21, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-22, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-23, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-24, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-25, goto monday: 2001-3-25; should be 2001-3-26 ###.<br>
from 2001-3-26, goto monday: 2001-3-26; should be 2001-3-26.<br>
from 2001-3-27, goto monday: 2001-4-2 ; should be 2001-4-2.<br>
<hr>
PHP version: 4.2.3<br>
[root@www tmp]#
========================================================

Expected output: The 6 lines with "###" are expected to produce the indicated output, but do not.

Problem was noticed today in PHP 4.06, and then verified as being reproducible in PHP 4.2.3 (same output).

PHP 4.2.3 configured with:
./configure --with-mysql --enable-xml --enable-wddx 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-11-12 19:46 UTC] nickj-phpbugs at nickj dot org
OK, I decided that was needed was some kind of automated testing, so I wrote it:
============================================
#!/root/php4-200211122230 -q
<?php

// report any errors at all
error_reporting (E_ALL);

// pass a date, supply a strtotime modifier, and get a date back
function getDateWithModifier($date, $modifier) {
	list ($year, $month, $day) = explode ("-",$date);
	$starting_timestamp = mktime (1,1,1,$month,$day,$year);
	$timestamp_with_modifier = strtotime ($modifier, $starting_timestamp);
	return date("Y-n-j", $timestamp_with_modifier);
}

/*
** @desc: for the specified date, will find the date for the desired day of the 
**        week that is also in the same week. Does NOT use 'strtotime'
*/
function getDayOfTheWeekFromDate($date, $desired_day_of_week) {
	// weekdays - note special case for sundays (7, not 0), so as to treat as end of week, not start
    $weekdays = array ("Sunday" => 7, "Monday" => 1, "Tuesday" => 2, "Wednesday" => 3,
                            "Thursday" => 4, "Friday" => 5, "Saturday" => 6);

    // convert into a number
    $desired_day_of_week_number = $weekdays[$desired_day_of_week];

    // see what day we have currently
    list ($year, $month, $day) = explode ("-",$date);
    $date_day_of_week = date("w", mktime (17,17,17,$month,$day,$year));

	$new_day = $day+(($desired_day_of_week_number-$date_day_of_week)+7) % 7;
    return date("Y-n-j", mktime (17,17,17,$month,$new_day,$year));
}


// run an automated test to compare the output of these two functions, and complain if they differ
for ($i=1; $i<1000; $i++) {
	$date =  date("Y-n-j", mktime (17,17,17,1,$i,1999));
	$strtotime_date = getDateWithModifier($date, "Monday");
	$other_date = getDayOfTheWeekFromDate($date, "Monday");
	if ($strtotime_date != $other_date) {
		print "Discrepancy for $date - results were $strtotime_date vs $other_date\n";
	}
}

print "PHP version: " . phpversion(). "<br>\n";

?>
============================================


Here's the output that I get:
============================================
[root@www tmp]# ./automated-date-test.php 
Discrepancy for 1999-3-23 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 1999-3-24 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 1999-3-25 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 1999-3-26 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 1999-3-27 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 1999-3-28 - results were 1999-3-28 vs 1999-3-29
Discrepancy for 2000-3-21 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2000-3-22 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2000-3-23 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2000-3-24 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2000-3-25 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2000-3-26 - results were 2000-3-26 vs 2000-3-27
Discrepancy for 2001-3-20 - results were 2001-3-25 vs 2001-3-26
Discrepancy for 2001-3-21 - results were 2001-3-25 vs 2001-3-26
Discrepancy for 2001-3-22 - results were 2001-3-25 vs 2001-3-26
Discrepancy for 2001-3-23 - results were 2001-3-25 vs 2001-3-26
Discrepancy for 2001-3-24 - results were 2001-3-25 vs 2001-3-26
Discrepancy for 2001-3-25 - results were 2001-3-25 vs 2001-3-26
PHP version: 4.3.0-dev<br>
[root@www tmp]# 
============================================

In other words, the result for these 6 days of the year consistently appears to be wrong. (I suppose I should be glad that the very first date I choose to test this function with just by fluke happened to be one of those 6 days, as opposed to causing mysterious problems later!) 

Does anyone else get any results that appear incorrect on running this script?
 [2003-04-06 18:47 UTC] scottmacvicar at ntlworld dot com
This is a DST problem by the looks of it. The specific dates mentioned are when DST takes effect which is the last sunday in March.
 [2004-04-08 04:25 UTC] sniper@php.net
Can you please give a simpler test? (I somehow have a feeling your script is buggy, not PHP) 

 [2004-04-08 07:00 UTC] derick@php.net
I'm pretty sure the script is buggy. Please give us a test case for ONE date that is wrong, and comment your code properly too.
 [2004-04-08 07:15 UTC] nickj-phpbugs at nickj dot org
How's this for a short and simple test script?

Applies strtotime() to every day between 1970 and 2037, and gives a list of everything that looks wrong.

======================================================
<?php
$request_day = "Monday";
for ($i=1; ; $i++) {
    // start at year 1970, bail out at year 2038
    $tStamp = mktime (17,17,17,1,$i,1970);
    if (date("Y", $tStamp) == 2038) break;
    // request a day, check what we got, complain if differs
    $strtotime_timestamp = strtotime ($request_day, $tStamp);
    $result_day = date("l", $strtotime_timestamp);
    if ($result_day != $request_day)
        print "strtotime wrong on: " . date("j-M-Y", $tStamp) . 
               " - gave a $result_day, not a $request_day.\n"; 
}
?>
 [2004-04-08 10:13 UTC] derick@php.net
This one shows it better:

<?php
    putenv("TZ=Europe/Amsterdam");
    $tStamp = mktime (17, 17, 17, 10, 27, 2004);
    echo "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
                                                                                                                                           
    $strtotime_timestamp = strtotime ("Monday", $tStamp);
    echo "result=". date("l Y-m-d H:i:s T", $strtotime_timestamp). "\n";
    echo "wanted=Monday 2004-11-01 00:00:00 CET\n";
?>

 [2004-10-19 21:30 UTC] joe at dataport dot tv
How's this?

<?php
$day=date("w",strtotime("this monday"));
echo $day;
?>
Outputs: 1

<?php
$day=date("w",strtotime("next monday"));
echo $day;
?>
Outputs: 0

I was going to submit a seperate bug but this definately looks related even though this is a totally different way of going about getting the same type of problem.

(I knew Mondays were a little odd, but does strtotime seem to think the sunday of the next week has an extra second after midnight? As this example demonstrates it doesn't do it if you prefix the weekday with "this", just "next" or no prefix at all.)
 [2004-10-20 20:14 UTC] joe at dataport dot tv
Oh, also forgot to mention that while "next monday" does not work, "next tuesday" does.  There's definately a bug here, if "this monday" works and "next tuesday" works, it seems to me that "next monday" should work as well and that it's not just some time zone issue.
 [2005-06-16 21:35 UTC] derick@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Fixed for PHP 5.1
 [2005-06-18 01:29 UTC] nickj-phpbugs at nickj dot org
Reopening, as the original test case is now working correctly (thank you!), but there are others that don't appear to be producing the expected results.

The ones that don't work seem to differ between operating systems. For Linux, I've included some of these below as a series of ten small, separate, simple test cases, structured in the format you've indicated you prefer. Then below that I've included another ten cases for Windows 2000 systems, in the same format:

======================================================
<?php

putenv("TZ=Europe/Andorra");
$tStamp = mktime (17, 17, 17, 1, 24764, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Dubai");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Kabul");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Antigua");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Anguilla");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Europe/Tirane");
$tStamp = mktime (17, 17, 17, 1, 4849, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Yerevan");
$tStamp = mktime (17, 17, 17, 1, 24764, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Curacao");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Africa/Luanda");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Antarctica/McMurdo");
$tStamp = mktime (17, 17, 17, 1, 24743, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";

?>
======================================================
Results (on my system, a Debian GNU/Linux Woody 3.0r6 box), are as follows:


ludo:~/tmp/php-5.1-dev/php5-200506170030/sapi/cli# ./php ~/test/test-output.php 
tStamp=Monday 2037-10-19 17:17:17 CEST
result=Monday 2037-10-26 01:00:00 CET
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 GST
result=Monday 1970-01-05 04:00:00 GST
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 AFT
result=Monday 1970-01-05 04:30:00 AFT
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 AST
result=Sunday 1970-01-04 20:00:00 AST
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 AST
result=Sunday 1970-01-04 20:00:00 AST
wanted=Monday            00:00:00

tStamp=Monday 1983-04-11 17:17:17 CET
result=Monday 1983-04-18 01:00:00 CEST
wanted=Monday            00:00:00

tStamp=Monday 2037-10-19 17:17:17 AMST
result=Monday 2037-10-26 04:00:00 AMT
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 AST
result=Sunday 1970-01-04 20:00:00 AST
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 WAT
result=Monday 1970-01-05 01:00:00 WAT
wanted=Monday            00:00:00

tStamp=Monday 2037-09-28 17:17:17 NZST
result=Monday 2037-10-05 13:00:00 NZDT
wanted=Monday            00:00:00

ludo:~/tmp/php-5.1-dev/php5-200506170030/sapi/cli# 

======================================================

However, on a windows 2000 system, the above tests work OK, but these tests do not:

======================================================

<?php

putenv("TZ=Australia/Adelaide");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Australia/Darwin");
$tStamp = mktime (17, 17, 17, 1, 88, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Australia/Perth");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Aruba");
$tStamp = mktime (17, 17, 17, 1, 88, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Baku");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Europe/Sarajevo");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Barbados");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Dacca");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Europe/Brussels");
$tStamp = mktime (17, 17, 17, 1, 1, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Africa/Ouagadougou");
$tStamp = mktime (17, 17, 17, 1, 88, 1971);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";

?>

======================================================
Results on a Windows 2000 SP4 box, are as follows:


G:\PHP bugs\PHP bug 20382\php5.1-dev\php5-win32-200506171830>php-cgi.exe ..\..\new-test-output.php
Content-type: text/html
X-Powered-By: PHP/5.1.0-dev

tStamp=Friday 1971-01-01 17:17:17 Aus
result=Sunday 1971-01-03 14:30:00 Aus
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 Aus
result=Monday 1971-04-05 01:00:00 tra
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Aus
result=Sunday 1971-01-03 16:00:00 Aus
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 Ame
result=Monday 1971-04-05 01:00:00 ric
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Asi
result=Sunday 1971-01-03 20:00:00 Asi
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Eur
result=Sunday 1971-01-03 23:00:00 Eur
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Ame
result=Monday 1971-01-04 04:00:00 Ame
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Asi
result=Sunday 1971-01-03 18:00:00 Asi
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 Eur
result=Sunday 1971-01-03 23:00:00 Eur
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 Afr
result=Monday 1971-04-05 01:00:00 ica
wanted=Monday            00:00:00


G:\PHP bugs\PHP bug 20382\php5.1-dev\php5-win32-200506171830>

====================================================================
And running the win2000 tests on the Linux box give this:

ludo:~/tmp/php-5.1-dev/php5-200506170030/sapi/cli# ./php ~/test/new-test-win2000.php 
tStamp=Friday 1971-01-01 17:17:17 CST
result=Monday 1971-01-04 00:00:00 CST
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 CST
result=Monday 1971-04-05 09:30:00 CST
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 WST
result=Monday 1971-01-04 00:00:00 WST
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 AST
result=Sunday 1971-04-04 20:00:00 AST
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 BAKT
result=Monday 1971-01-04 00:00:00 BAKT
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 CET
result=Monday 1971-01-04 00:00:00 CET
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 AST
result=Monday 1971-01-04 00:00:00 AST
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 DACT
result=Monday 1971-01-04 00:00:00 DACT
wanted=Monday            00:00:00

tStamp=Friday 1971-01-01 17:17:17 CET
result=Monday 1971-01-04 00:00:00 CET
wanted=Monday            00:00:00

tStamp=Monday 1971-03-29 17:17:17 GMT
result=Monday 1971-04-05 00:00:00 GMT
wanted=Monday            00:00:00


I.e. the 2nd and 4th results are also wrong on Linux, the remaining 8 look correct (so there is some overlap in incorrect results between operating systems, although most of the time there is not).
 [2005-06-18 16:10 UTC] derick@php.net
All those tests run fine for me, perhaps my latest commit already changed this, so please try a new snapshot.

About the WIndows tests, they are not going to work yet because on Windows the date() function doesn't understand timezone names like "Asia/Dubai". This is going to be implement before 5.1 is released if I have the time.
 [2005-06-19 03:44 UTC] nickj-phpbugs at nickj dot org
That's a lot better, it takes much longer to find problems, but there are still some cases it doesn't seem to work on (using the same Debian GNU/Linux Woody 3.0r6 system), such as:

===============================================================
<?php

putenv("TZ=Europe/Tirane");
$tStamp = mktime (17, 17, 17, 1, 4849, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Yerevan");
$tStamp = mktime (17, 17, 17, 1, 4102, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Wednesday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Wednesday            00:00:00\n\n";


putenv("TZ=Antarctica/Palmer");
$tStamp = mktime (17, 17, 17, 1, 1477, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Wednesday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Wednesday            00:00:00\n\n";


putenv("TZ=America/Buenos_Aires");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Rosario");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Cordoba");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Jujuy");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Catamarca");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=America/Mendoza");
$tStamp = mktime (17, 17, 17, 1, 1734, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Europe/Vienna");
$tStamp = mktime (17, 17, 17, 1, 3743, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Australia/Lord_Howe");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";


putenv("TZ=Asia/Baku");
$tStamp = mktime (17, 17, 17, 1, 9490, 1970);
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";

?>


===============================================================

Which for me gives:

===============================================================
ludo:~/tmp/php-5.1-dev/php5-200506182230/sapi/cli# ./php ~/test/19-june-2005-linux-strtotime-tests.php 
tStamp=Monday 1983-04-11 17:17:17 CET
result=Monday 1983-04-18 01:00:00 CEST
wanted=Monday            00:00:00

tStamp=Wednesday 1981-03-25 17:17:17 YERT
result=Wednesday 1981-04-01 01:00:00 YERST
wanted=Wednesday            00:00:00

tStamp=Wednesday 1974-01-16 17:17:17 ART
result=Wednesday 1974-01-23 01:00:00 ARST
wanted=Wednesday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1974-09-30 17:17:17 ART
result=Monday 1974-10-07 01:00:00 ARST
wanted=Monday            00:00:00

tStamp=Monday 1980-03-31 17:17:17 CET
result=Sunday 1980-04-06 23:00:00 CET
wanted=Monday            00:00:00

tStamp=Thursday 1970-01-01 17:17:17 EST
result=Sunday 1970-01-04 23:00:00 EST
wanted=Monday            00:00:00

tStamp=Monday 1995-12-25 17:17:17 AZT
result=Monday 1996-01-01 01:00:00 AZST
wanted=Monday            00:00:00

ludo:~/tmp/php-5.1-dev/php5-200506182230/sapi/cli# 
===============================================================

> About the Windows tests, they are not going to work yet because
> on Windows the date() function doesn't understand timezone 
> names like "Asia/Dubai". This is going to be implement before
> 5.1 is released if I have the time.

No worries; If this does get added, feel free to let me know, and I can rerun some of the date-related tests on the Win32 platform.
 [2005-06-19 14:10 UTC] derick@php.net
These new tests are all correct, except the one for Vienna and perhaps the one for Lord Howe. They are correct because there is no 00:00 for those specific dates, as the time goes from:
23:59 winter time
to
01:00 summer time
the clock is set an hour forward there.

I'll check out the Vienna and Lord Howe ones now, can you please file a different bug for the rendering problem on Windows?
 [2005-06-19 16:51 UTC] derick@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

The Vienna testcase works just fine here, and the Lord Howe testcase shows a bug in the date() function. Compare the PHP script:

<?php
putenv("TZ=Australia/Lord_Howe");
$tStamp = mktime (17, 17, 17, 1, 1, 1970);
echo $tStamp, "\n";
print "tStamp=". date("l Y-m-d H:i:s T", $tStamp). "\n";
$strtotime_tstamp = strtotime("Monday", $tStamp);
echo $strtotime_tstamp, "\n";
print "result=".date("l Y-m-d H:i:s T", $strtotime_tstamp)."\n";
print "wanted=Monday            00:00:00\n\n";
?>

output:
26237
tStamp=Thursday 1970-01-01 17:17:17 EST
306000
result=Sunday 1970-01-04 23:00:00 EST
wanted=Monday            00:00:00

with the code that the timelib does:

derick@kossu:/dat/dev/timelib$ ./tester-create-ts "1970-01-01 17:17:17 Monday" "" "Australia/Lord_Howe"

TS: 306000 | 1970-01-05 00:00:00 LHST Australia/Lord_Howe  0Y   0M   0D /   0H  0M   0S / 0

derick@kossu:/dat/dev/timelib$ ./tester-render-ts 306000 Australia/Lord_Howe

TYPE: 3 TS: 306000 | 1970-01-05 00:00:00 LHST Australia/Lord_Howe

You see that the timestamp is the same, but that the date() function renders it wrongly as 1970-01-04 23:00:00 EST while it should have been 1970-01-05 00:00:00 LHST. The EST is not even part of the timezone information for Lord Howe.

Closing bug. (But feel free to report a new one for the date() function).
 [2005-06-21 02:18 UTC] nickj-phpbugs at nickj dot org
> They are correct because there is no 00:00 for those specific dates

Ahhh - live and learn! I honestly never knew that there were timezones that did that. I had just assumed (incorrectly) they all jumped from 2 AM to 3 AM, I guess simply because that's what the timezone I live in ("Australia/Sydney") does.

Thank you Derick, for all of your help in getting this problem resolved.

Some quick notes regarding tying up loose ends:

The win32 timezone format support for date() has been logged at http://bugs.php.net/33403

The time rendering bug in the date() function for the Lord Howe timezone has been logged at http://bugs.php.net/33402

The only thing I don't understand is the Vienna timezone one. I retried it with php5-200506201830, and it still happened. So I reran the tests, this time ignoring anything on the expected day at midnight, plus anything on the expected day at 1 AM. This was my most complete strtotime() test run to date, running overnight and taking around 11 hours, and performing 615 million date-related tests:
// Approximate total number of tests =
//   354 timezones
// * 7 days
// * 5 tests per day (e.g. "Monday", "next Tuesday", "last Thursday", "Friday +1 week", "Sunday -1 week")
// * (2038 - 1970) years
// * 365 days per year
// * 2 checks for each strtotime result (one for correct day, one for checking time = midnight or 1 AM)
// = 615,039,600 tests in total.

So basically, if there's any lurking gremlins, this test had an fairly good chance of finding them.

It found roughly 33 situations that seem to be giving the wrong day (one of which is Vienna, but the rest are not). This includes 2 situations which were off by > 24 hours (i.e. ask for "Monday", but returns a time on Saturday). This may be the same underlying problem as the Lord Howe thing, or something else, I honestly don't know. I've logged these at http://bugs.php.net/33414

It also found roughly 26 situations that were giving the right day, but a time that wasn't midnight or 1 AM. There can be valid 0.5 hour and 2 hour DST transitions (very rare, but they do happen), so there is a good chance that at least some of these are bogus. However, I thought it best to err on the side of caution, most especially because 17 of the 26 do not appear to involve a DST or timezone transition. I've logged these at http://bugs.php.net/33415
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sat Apr 19 09:02:28 2014 UTC