IMPORTANT: Timezone patch
| From: | Andrei Zmievski | Date: | Tue, 13 Jun 2000 20:08:58 +0000 |
| Subject: | IMPORTANT: Timezone patch | ||
| Groups: | php.dev php.general | ||
| Request: | Send a blank email to php-general+get-1748@lists.php.net to get a copy of this message | ||
Basically, I noticed the error when I wanted to take a GMT date/time and
convert it to local time. Before the patch the output of the code below
was totally wrong - it did not account for non-HAVE_TM_GMTOFF case where
timezone offsets are positive instead of negative, like in
HAVE_TM_GMTOFF case. Solaris was one of the systems affected, for
example. Furthermore, it didn't seem to do daylight savings time
adjustment correctly. Without the patch the following code (for CDT
timezone = -0500):
<?
var_dump(date("M d, Y H:i:s", gmmktime(12, 0, 0, 6, 9, 2000)));
var_dump(date("M d, Y H:i:s", gmmktime(12, 0, 0, 6, 9, 2000, 1)));
var_dump(date("M d, Y H:i:s", gmmktime(12, 0, 0, 6, 9, 2000, 0)));
?>
gave:
string(21) "Jun 09, 2000 18:00:00"
string(21) "Jun 09, 2000 18:00:00"
string(21) "Jun 09, 2000 19:00:00"
with the patch it gives:
string(21) "Jun 09, 2000 07:00:00"
string(21) "Jun 09, 2000 07:00:00"
string(21) "Jun 09, 2000 06:00:00"
Which is exactly what I'd expect for noon GMT time for my timezone.
So, I propose the attached patch. Please test it and comment so that we
know whether to put it in 4.0.1.
-Andrei
When we eliminate the impossible, whatever remains,
however improbable, must be true. -- Sherlock Holmes
Index: ext/standard/datetime.c =================================================================== RCS file: /repository/php4/ext/standard/datetime.c,v retrieving revision 1.43 diff -u -r1.43 datetime.c --- ext/standard/datetime.c 2000/06/09 20:18:36 1.43 +++ ext/standard/datetime.c 2000/06/12 20:08:14 @@ -53,7 +53,7 @@ }; #if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) && !defined(HAVE_DECLARED_TIMEZONE) -extern time_t timezone; +extern time_t timezone, altzone; extern int daylight; #endif @@ -81,6 +81,7 @@ struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS(); + int is_dst = -1; if (arg_count > 7 || zend_get_parameters_array_ex(arg_count,arguments) == FAILURE) { WRONG_PARAM_COUNT; @@ -116,7 +117,7 @@ */ switch(arg_count) { case 7: - ta->tm_isdst = (*arguments[6])->value.lval; + ta->tm_isdst = is_dst = (*arguments[6])->value.lval; /* fall-through */ case 6: /* @@ -155,6 +156,8 @@ } seconds = mktime(ta); + if (is_dst == -1) + is_dst = ta->tm_isdst; if (gm) { #if HAVE_TM_GMTOFF @@ -165,11 +168,12 @@ gmadjust = ta->tm_gmtoff; #else /* - ** Without tm_gmtoff, the non-ANSI C run-time global 'timezone' - ** variable simply returns the current Winter GMT offset - ** in the current locale (defined in DOS/Windows compilers). + ** If correcting for daylight savings time, we set the adjustment to + ** the value of altzone variable. Otherwise, we need to overcorrect and + ** set the adjustment to the main timezone offset plus difference + ** between the main and alternate ones. */ - gmadjust = timezone; + gmadjust = -(is_dst ? altzone : timezone + (timezone - altzone)); #endif seconds += gmadjust; } @@ -405,9 +409,9 @@ break; case 'Z': /* timezone offset in seconds */ #if HAVE_TM_GMTOFF - sprintf(tmp_buff, "%ld", ta->tm_isdst ? ta->tm_gmtoff-3600 : ta->tm_gmtoff); + sprintf(tmp_buff, "%ld", ta->tm_gmtoff); #else - sprintf(tmp_buff, "%ld", daylight ? timezone-3600 : timezone); + sprintf(tmp_buff, "%ld", ta->tm_isdst ? altzone : timezone); #endif strcat(return_value->value.str.val, tmp_buff); break; @@ -720,8 +724,8 @@ RETURN_LONG(parsedate((*timep)->value.str.val, NULL)); } } - /* }}} */ + /* * Local variables:
Index: ext/standard/datetime.c =================================================================== RCS file: /repository/php4/ext/standard/datetime.c,v retrieving revision 1.43 diff -u -r1.43 datetime.c --- ext/standard/datetime.c 2000/06/09 20:18:36 1.43 +++ ext/standard/datetime.c 2000/06/12 20:08:14 @@ -53,7 +53,7 @@ }; #if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) && !defined(HAVE_DECLARED_TIMEZONE) -extern time_t timezone; +extern time_t timezone, altzone; extern int daylight; #endif @@ -81,6 +81,7 @@ struct tm *ta, tmbuf; time_t t; int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS(); + int is_dst = -1; if (arg_count > 7 || zend_get_parameters_array_ex(arg_count,arguments) == FAILURE) { WRONG_PARAM_COUNT; @@ -116,7 +117,7 @@ */ switch(arg_count) { case 7: - ta->tm_isdst = (*arguments[6])->value.lval; + ta->tm_isdst = is_dst = (*arguments[6])->value.lval; /* fall-through */ case 6: /* @@ -155,6 +156,8 @@ } seconds = mktime(ta); + if (is_dst == -1) + is_dst = ta->tm_isdst; if (gm) { #if HAVE_TM_GMTOFF @@ -165,11 +168,12 @@ gmadjust = ta->tm_gmtoff; #else /* - ** Without tm_gmtoff, the non-ANSI C run-time global 'timezone' - ** variable simply returns the current Winter GMT offset - ** in the current locale (defined in DOS/Windows compilers). + ** If correcting for daylight savings time, we set the adjustment to + ** the value of altzone variable. Otherwise, we need to overcorrect and + ** set the adjustment to the main timezone offset plus difference + ** between the main and alternate ones. */ - gmadjust = timezone; + gmadjust = -(is_dst ? altzone : timezone + (timezone - altzone)); #endif seconds += gmadjust; } @@ -405,9 +409,9 @@ break; case 'Z': /* timezone offset in seconds */ #if HAVE_TM_GMTOFF - sprintf(tmp_buff, "%ld", ta->tm_isdst ? ta->tm_gmtoff-3600 : ta->tm_gmtoff); + sprintf(tmp_buff, "%ld", ta->tm_gmtoff); #else - sprintf(tmp_buff, "%ld", daylight ? timezone-3600 : timezone); + sprintf(tmp_buff, "%ld", ta->tm_isdst ? altzone : timezone); #endif strcat(return_value->value.str.val, tmp_buff); break; @@ -720,8 +724,8 @@ RETURN_LONG(parsedate((*timep)->value.str.val, NULL)); } } - /* }}} */ + /* * Local variables: