ID:               20382
 Comment by:       [EMAIL PROTECTED]
 Reported By:      [EMAIL PROTECTED]
 Status:           Feedback
 Bug Type:         Date/time related
 Operating System: Linux Mandrake 7.2
 PHP Version:      4.3.0-dev
 New Comment:

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?


Previous Comments:
------------------------------------------------------------------------

[2002-11-12 19:25:41] [EMAIL PROTECTED]

No problem - Modified script slightly, as shown below, to use
gmmktime(), and to also print out the before and after timestamps.
Source:
=========================================
#!/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);
        $t_start = gmmktime (17,17,17,$month,$day,$year);
        $t_new   = strtotime ($modifier, $t_start);
        return "t_start: $t_start; t_new: $t_new; "
                        . date("Y-n-j", $t_new);
}

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

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

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

Output:
==========================================
[root@www tmp]# ./script.php 
<hr>
2001-3-17, goto mon: t_start: 984849437; t_new: 984920400; 2001-3-19;
should be 2001-3-19.<br>
2001-3-18, goto mon: t_start: 984935837; t_new: 984920400; 2001-3-19;
should be 2001-3-19.<br>
2001-3-19, goto mon: t_start: 985022237; t_new: 985525200; 2001-3-25;
should be 2001-3-19.<br>
2001-3-20, goto mon: t_start: 985108637; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-21, goto mon: t_start: 985195037; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-22, goto mon: t_start: 985281437; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-23, goto mon: t_start: 985367837; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-24, goto mon: t_start: 985454237; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-25, goto mon: t_start: 985540637; t_new: 985528800; 2001-3-26;
should be 2001-3-26 ###.<br>
2001-3-26, goto mon: t_start: 985627037; t_new: 986133600; 2001-4-2;
should be 2001-3-26.<br>
2001-3-27, goto mon: t_start: 985713437; t_new: 986133600; 2001-4-2 ;
should be 2001-4-2.<br>
<hr>
PHP version: 4.3.0-dev<br>
[root@www tmp]# 
==========================================

And here is the output using mktime() instead of gmmktime():
==========================================
[root@www tmp]# ./script.php 
<hr>
2001-3-17, goto mon: t_start: 984809837; t_new: 984920400; 2001-3-19;
should be 2001-3-19.<br>
2001-3-18, goto mon: t_start: 984896237; t_new: 984920400; 2001-3-19;
should be 2001-3-19.<br>
2001-3-19, goto mon: t_start: 984982637; t_new: 984920400; 2001-3-19;
should be 2001-3-19.<br>
2001-3-20, goto mon: t_start: 985069037; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-21, goto mon: t_start: 985155437; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-22, goto mon: t_start: 985241837; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-23, goto mon: t_start: 985328237; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-24, goto mon: t_start: 985414637; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-25, goto mon: t_start: 985504637; t_new: 985525200; 2001-3-25;
should be 2001-3-26 ###.<br>
2001-3-26, goto mon: t_start: 985591037; t_new: 985528800; 2001-3-26;
should be 2001-3-26.<br>
2001-3-27, goto mon: t_start: 985677437; t_new: 986133600; 2001-4-2 ;
should be 2001-4-2.<br>
<hr>
PHP version: 4.3.0-dev<br>
[root@www tmp]# 
==========================================

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

[2002-11-12 18:46:02] [EMAIL PROTECTED]

Hmm..could you try changing that mktime() to gmmktime() ?
And also add output of the gm/mktime() only to see what 
you get as timestamp.


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

[2002-11-12 18:10:27] [EMAIL PROTECTED]

Happy to comply. I tried it with the CVS snapshot (php4-200211122230),
output was:
=============================================================
[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.3.0-dev<br>
[root@www tmp]# 
=============================================================

i.e. same problem. The location of the php command-line executable
appears to have changed to 'sapi/cli/php' (in the PHP 4.2.3 build
process the executable just ends up in the root of the source
directory), so this was what I used, hope this is OK.

Here is some more info related to the problem that may or may not be
relevant:

* This machine and I are located in Sydney, Australia. The machine's
timezone as shown in 'timeconfig' is set of "Australia/Sydney", and
"Hardware clock set to GMT" is shown turned off. Output of the 'date'
command looks like this: "Wed Nov 13 10:40:22 EST 2002". Sydney is
(depending on daylight savings) around GMT + 10 hours.

* I've found today that there was a daylight savings transition for
this timezone in that week. From:
http://www.dstc.qut.edu.au/DST/marg/daylight.html - "[Daylight savings]
ends at 3am on Sunday 25 March 2001. Clocks should be turned back one
hour to read 2am (Australian Eastern Standard Time)." 

* Since there was a daylight savings transition, I've now tried various
parameters to the 'mktime' line, in case the hour/minute/second
parameters chosen were causing problems because they were too close to
the time transition. I've tried the following parameters, all of which
produce the same incorrect result:
 - mktime (23,23,23,$month,$day,$year);
 - mktime (15,15,15,$month,$day,$year);
 - mktime (10,10,10,$month,$day,$year);
 - mktime (5,5,5,$month,$day,$year);
 - mktime (1,1,1,$month,$day,$year);

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

[2002-11-12 06:17:41] [EMAIL PROTECTED]

Please try using this CVS snapshot:

  http://snaps.php.net/php4-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php4-win32-latest.zip


Your script produces the expected dates for me with latest CVS
snapshot. Please give try it out.


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

[2002-11-12 02:11:16] [EMAIL PROTECTED]

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 


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


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

Reply via email to