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;
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;
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);
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;
}
--- /dev/null
+--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