cvs: /php4/ext/standard datetime.c
| From: | Philippe Verdy | Date: | Sat, 28 Aug 1999 16:19:44 +0000 |
| Subject: | cvs: /php4/ext/standard datetime.c | ||
| Groups: | php.version4 | ||
| Request: | Send a blank email to php-version4+get-3812@lists.php.net to get a copy of this message | ||
verdy_p Sat Aug 28 12:19:44 1999 EDT
Modified files:
/php4/ext/standard datetime.c
Log:
Bug in gmmktime():
it produced wrong results in New Foundland,
Central Australia, India, Iran, and Java, with
half-hour timezones.
Index: php4/ext/standard/datetime.c
diff -u php4/ext/standard/datetime.c:1.19 php4/ext/standard/datetime.c:1.20
--- php4/ext/standard/datetime.c:1.19 Mon Aug 2 15:16:50 1999
+++ php4/ext/standard/datetime.c Sat Aug 28 12:19:14 1999
@@ -19,7 +19,7 @@
*/
-/* $Id: datetime.c,v 1.19 1999/08/02 19:16:50 zeev Exp $ */
+/* $Id: datetime.c,v 1.20 1999/08/28 16:19:14 verdy_p Exp $ */
#include "php.h"
@@ -88,18 +88,53 @@
for (i = 0; i < arg_count; i++) {
convert_to_long(arguments[i]);
}
- t=time(NULL);
+ t = time(NULL);
#ifdef HAVE_TZSET
tzset();
#endif
+ /*
+ ** Set default time parameters with local time values,
+ ** EVEN when some GMT time parameters are specified!
+ ** This may give strange result, with PHP gmmktime(0,0,0),
+ ** which is assumed to return GMT midnight time
+ ** for today (in localtime), so that the result time may be
+ ** AFTER or BEFORE the current time.
+ ** May be we should initialize tn using gmtime(), so that
+ ** default parameters for PHP gmmktime would be the current
+ ** GMT time values...
+ */
tn = localtime(&t);
- memcpy(&ta,tn,sizeof(struct tm));
- ta.tm_isdst = arg_count > 6 ? arguments[6]->value.lval : gm ? 0 : -1;
+ memcpy(&ta, tn, sizeof(struct tm));
+ if (gm) {
+ ta.tm_isdst = 0 /* force winter time if UTC flag is true */
+ /* unless the UTC flag is specified after GMT date parameters. */
+ }
+ else {
+ ta.tm_isdst = -1; /* let DST unknown */
+ /* this will recompute the DST status for the */
+ /* given date, based on localtime rules. */
+ /* Most often, this will return the same value */
+ }
+ /*
+ ** Now change date values with supplied parameters.
+ */
switch(arg_count) {
case 7:
+ ta.tm_isdst = arguments[6]->value.lval;
+ /* fall-through */
case 6:
- ta.tm_year = arguments[5]->value.lval - ((arguments[5]->value.lval > 1000) ? 1900 : 0);
+ /*
+ ** Accept parameter in range 0..1000 interpreted as 1900..2900
+ ** (if 100 is given, it means year 2000)
+ ** or in range 1001..9999 interpreted as is (this will store
+ ** negative tm_year for years in range 1001..1899)
+ ** This function is then Y2K ready, and accepts a wide range of
+ ** dates including the whole gregorian calendar.
+ ** But it cannot represent ancestral dates prior to year 1001.
+ */
+ ta.tm_year = arguments[5]->value.lval
+ - ((arguments[5]->value.lval > 1000) ? 1900 : 0);
/* fall-through */
case 5:
ta.tm_mday = arguments[4]->value.lval;
@@ -115,20 +150,51 @@
/* fall-through */
case 1:
ta.tm_hour = arguments[0]->value.lval;
+ /* fall-through */
case 0:
break;
}
- t=mktime(&ta); /* Need to do this because of Daylight savings */
- tn = localtime(&t);
if (gm) {
#if HAVE_TM_GMTOFF
- gmadjust=tn->tm_gmtoff;
+ /*
+ ** If GMT parameters were given, mktime() will
+ ** use the forced winter time local convention
+ ** and the structure will be adjusted to compute
+ ** the effective localtime GMT offset in seconds.
+ ** This value depends on date parameters in ta.
+ ** So this compute the Winter GMT offset.
+ */
+ t = mktime(&ta); /* Need to do this because of Daylight savings */
+ tn = localtime(&t);
+ /*
+ ** Note: despite locatime() returns a global structure,
+ ** structure, this structure is supposed to be thread-unique,
+ ** (this is true with MS Visual compiler for Windows)
+ ** so the localtime() function will be MT-safe.
+ ** On other systems, localtime() may not return thread-unique
+ ** structure, and won't be MT-safe. For now MT is supported
+ ** only on Windows for the DLL versions of PHP.
+ */
+ gmadjust = tn->tm_gmtoff;
#else
- gmadjust=timezone;
+ /*
+ ** 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).
+ */
+ gmadjust = timezone;
#endif
- ta.tm_hour += gmadjust / 3600;
- ta.tm_min += gmadjust % 3600;
+ /*
+ ** Adjust parameters, to void the GMT offset in seconds
+ ** in the supplied parameters, because mktime() below
+ ** computes a local time instead of GMT time.
+ */
+ ta.tm_hour += gmadjust / 3600;
+ /* bug here: gmadjust % 3600 gives seconds, not minutes!!! */
+ ta.tm_min += (gmadjust % 3600) / 60;
+ /* is there any timezone with seconds ? */
+ ta.tm_sec += gmadjust % 60;
}
RETURN_LONG(mktime(&ta));