]> granicus.if.org Git - php/commitdiff
MFB test case for bug #27719 and improve comments in this tricky DST code
authorRasmus Lerdorf <rasmus@php.net>
Sun, 28 Mar 2004 15:03:56 +0000 (15:03 +0000)
committerRasmus Lerdorf <rasmus@php.net>
Sun, 28 Mar 2004 15:03:56 +0000 (15:03 +0000)
NEWS
ext/standard/datetime.c
ext/standard/tests/time/bug27719.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 399bf2e27823d3621a9a038bc4f700e1c312668a..84c841b08fdcb7fb06e5c08e20da07310433e4aa 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ????? 2004, PHP 5 Release Candidate 2
+- Fixed bug #27719 (mktime issues on and around DST changeover). (Rasmus)
 - Changed sqlite to use studlyCaps convention for its OO API. (Marcus)
 - Force destructors to have empty signatures. (Marcus)
 - Stopped file uploads from throwing E_WARNINGs and E_NOTICEs which can not be
index fe973c80422f9a1ad25c52126364a96c5777c48b..b639c37a2fae400d3bd42963ac6530df5622d6b5 100644 (file)
@@ -158,7 +158,7 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
                        ta->tm_year = Z_LVAL_PP(arguments[5])
                          - ((Z_LVAL_PP(arguments[5]) > 1000) ? 1900 : 0);
                /* fall-through */
-       case 5: /* day in month (1-baesd) */
+       case 5: /* day in month (1-based) */
                val = (*arguments[4])->value.lval; 
                if (val < 1) { 
                        chgsecs += (1-val) * 60*60*24; 
@@ -190,10 +190,10 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
        case 1: /* hour */
                val = (*arguments[0])->value.lval; 
                /*
-                  We don't use 1 here to work around problems in some mktime implementations
-                  when it comes to daylight savings time.  Setting it to 4 and working back from
-                  there with the chgsecs offset makes us immune to these problems.
-                  See http://bugs.php.net/27533 for more info.
+                  We avoid midnight and a couple of hours after midnight here to work around
+                  various OS-level bugs in mktime and specifically daylight savings time issues
+                  in many mktime implementation.
+                  See bugs #27533 and #27719 for more info.
                */
                if (val < 4) { 
                        chgsecs += (4-val) * 60*60; val = 4; 
@@ -215,6 +215,11 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
 
        seconds = t - chgsecs;
 
+       /*
+          Here we check to see if the chgsecs fuzz factor we applied caused us to
+          move from dst to non-dst or vice-versa.  If so we adjust accordingly to
+          avoid being off by an hour on the dst changeover date.
+       */
        if (is_dst == -1) {
                struct tm t1, t2;
                t1 = *localtime(&t);
@@ -225,6 +230,11 @@ void php_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
                        ta = localtime(&seconds);
                }
 
+               /*
+                  If the user didn't specify whether the timestamp passed in was dst or not
+                  then we fill it in based on the dst setting at the evaluated timestamp
+                  at the current TZ
+               */
                is_dst = ta->tm_isdst; 
        }
        
diff --git a/ext/standard/tests/time/bug27719.phpt b/ext/standard/tests/time/bug27719.phpt
new file mode 100644 (file)
index 0000000..926fc58
--- /dev/null
@@ -0,0 +1,65 @@
+--TEST--
+Bug #27719: mktime returns incorrect timestamp for dst days
+--FILE--
+<?php
+       putenv("TZ=EST");  // No DST
+       $a = mktime(0, 0, 0, 4, 4, 2004, 0);
+       $b = mktime(0, 0, 0, 4, 4, 2004, 1);
+       $c = mktime(0, 0, 0, 4, 4, 2004, -1);
+       echo "$a ".date("m/d/y h:i:s\n",$a);
+       echo "$b ".date("m/d/y h:i:s\n",$b);
+       echo "$c ".date("m/d/y h:i:s\n",$c);
+       echo "\n";
+       putenv("TZ=EST5DST");  // DST not in effect
+       $a = mktime(0, 0, 0, 2, 4, 2004, 0);
+       $b = mktime(0, 0, 0, 2, 4, 2004, 1);
+       $c = mktime(0, 0, 0, 2, 4, 2004, -1);
+       echo "$a ".date("m/d/y h:i:s\n",$a);
+       echo "$b ".date("m/d/y h:i:s\n",$b);
+       echo "$c ".date("m/d/y h:i:s\n",$c);
+       echo "\n";
+       putenv("TZ=EST5DST");  // Just before DST changeover
+       $a = mktime(0, 0, 0, 4, 4, 2004, 0);
+       $b = mktime(0, 0, 0, 4, 4, 2004, 1);
+       $c = mktime(0, 0, 0, 4, 4, 2004, -1);
+       echo "$a ".date("m/d/y h:i:s\n",$a);
+       echo "$b ".date("m/d/y h:i:s\n",$b);
+       echo "$c ".date("m/d/y h:i:s\n",$c);
+       echo "\n";
+       putenv("TZ=EST5DST");  // Just after DST changeover
+       $a = mktime(3, 0, 0, 4, 4, 2004, 0);
+       $b = mktime(3, 0, 0, 4, 4, 2004, 1);
+       $c = mktime(3, 0, 0, 4, 4, 2004, -1);
+       echo "$a ".date("m/d/y h:i:s\n",$a);
+       echo "$b ".date("m/d/y h:i:s\n",$b);
+       echo "$c ".date("m/d/y h:i:s\n",$c);
+       echo "\n";
+       putenv("TZ=EST5DST");  // DST in effect
+       $a = mktime(0, 0, 0, 6, 4, 2004, 0);
+       $b = mktime(0, 0, 0, 6, 4, 2004, 1);
+       $c = mktime(0, 0, 0, 6, 4, 2004, -1);
+       echo "$a ".date("m/d/y h:i:s\n",$a);
+       echo "$b ".date("m/d/y h:i:s\n",$b);
+       echo "$c ".date("m/d/y h:i:s\n",$c);
+       echo "\n";
+?>
+--EXPECT--
+1081054800 04/04/04 12:00:00
+1081054800 04/04/04 12:00:00
+1081054800 04/04/04 12:00:00
+1075870800 02/04/04 12:00:00
+1075867200 02/03/04 11:00:00
+1075870800 02/04/04 12:00:00
+1081054800 04/04/04 12:00:00
+1081051200 04/03/04 11:00:00
+1081054800 04/04/04 12:00:00
+1081065600 04/04/04 04:00:00
+1081062000 04/04/04 03:00:00
+1081062000 04/04/04 03:00:00
+1086325200 06/04/04 01:00:00
+1086321600 06/04/04 12:00:00
+1086321600 06/04/04 12:00:00