Thanks, I added the comment, and the 4.3.2 patch to the bug report. Luke
On Mon, Aug 18, 2003 at 04:55:56PM -0500, Luke Ehresman wrote: > Hi, > > A co-worker and I have been working on some intensive timestamp/timezone > manipulation code for the past week or so, and ran across what we believed > to be a bug in the way PHP handled gmmktime(). Browsing through the code, > sure enough I found the source of the problem. I fixed it, and have > attached a patch. > > As I was searching around, I discovered that this has been an open bug > since 4.0.6 (2 years!). I believe that this patch should fix most of the > issues related to the following problem: > http://bugs.php.net/bug.php?id=14391 > > > The Problem: > ============ > The function gmmktime() is supposed to take a date in GMT as a paramter > and return a timestamp in GMT. No manipulation of the time should occur. > The only circumstance in which manipulation of the time should happen is > if the seventh parameter (is_dst) is set to 1. This is the expected > behavior. However, in reality I noticed that when I didn't specify a > seventh parameter, it was applying a daylight savings time offset when I > tried to get the epoch. See the example code. > > <?php > > // Get a timestamp for the epoch (jan 1, 1970) > echo "<pre>"; > echo gmmktime(0,0,0,1,1,1970,1)."\n"; > echo gmmktime(0,0,0,1,1,1970,0)."\n"; > echo gmmktime(0,0,0,1,1,1970)."\n"; > > // Now get timestamp for June 1 > echo "\n"; > echo gmmktime(0,0,0,6,1,1970,1)."\n"; > echo gmmktime(0,0,0,6,1,1970,0)."\n"; > echo gmmktime(0,0,0,6,1,1970)."\n"; > > ?> > > I expected the first set of outputs to look like this: > > -3600 > 0 > 0 > > Which it does, so this is fine. However, The second block of outputs is > in June which if I had been using simply mktime(), I would have expected a > DST offset (note: DST = daylight savings time) to be applied by default > (on the 3rd command). However, since I'm using gmmktime() by default no > DST offset should be applied. The odd behavior manifests itself in the > second block of output: > > 13046400 > 13050000 > 13046400 > > This is pretty meaningless until you realize what is actually going on. > The last output, which is generated by a gmmktime() that has no 7th > parameter, is applying an offset for daylight savings time. > > The Solution > ============ > I had a moment of panic and was sincerely hoping that GMT did not actually > use daylight savings time, so I did some research and found that while the > timezone that contains Greenwich actually does use daylight savings time, > the GMT standard time reference does not. So right there I knew something > was wrong on the PHP side. I loaded up the source of PHP (like a good > open source enthusiast), and sure enough, I discovered the source of the > problem (no pun intended). > > PHP is using the C function php_mktime() for both mktime() and gmmktime(). > There is a flag as a parameter called "gm" which is 1 or 0 depending on > whether it was called from mktime() or gmmktime(). The problem is that > there is no check before applying the server's daylight savings > information to the timestamp. > > As a fix for this, I changed the behavior so that by default if there is > no 7th parameter for gmmktime, it will not apply any DST offset. This > differs from mktime which by default will appy the server's DST offset. > > I have attached patches for both PHP php-5.0.0b1 and php-4.3.2. I would > imagine the same code would work on most recent versions of PHP as it > doesn't seem that this function has had much recent development. The > patch can be applied by using the following: > > $ cd /usr/local/php-4.3.2 > $ patch -p2 < ~/gmmktime-php_4.3.2.patch > > Feel free to contact me if you have any questions. > > Luke > -- > Luke Ehresman > luke[at]ehresman.org > http://www.luke.ehresman.org > diff -u clean/php-4.3.2/ext/standard/datetime.c php-4.3.2/ext/standard/datetime.c > --- clean/php-4.3.2/ext/standard/datetime.c 2003-05-04 07:22:00.000000000 -0400 > +++ php-4.3.2/ext/standard/datetime.c 2003-08-18 17:18:19.000000000 -0400 > @@ -116,7 +116,20 @@ > /* Let DST be unknown. mktime() should compute the right value > ** and behave correctly. Unless the user overrides this. > */ > - ta->tm_isdst = -1; > + /* > + ** If we are using gmmktime(), do not use the local > + ** server's setting of DST. GMT does not use daylight > + ** savings, so unless the user overrides us, this should > + ** be set to 0. > + ** - Luke Ehresman, Aug 2003, <[EMAIL PROTECTED]> > + */ > + if (gm) { > + ta->tm_isdst = 0; > + is_dst = 0; > + } else { > + ta->tm_isdst = -1; > + is_dst = -1; > + } > > /* > ** Now change date values with supplied parameters. > Common subdirectories: clean/php-4.3.2/ext/standard/tests and > php-4.3.2/ext/standard/tests > --- php-5.0.0b1/ext/standard/bak 2003-08-18 17:30:31.000000000 -0400 > +++ php-5.0.0b1/ext/standard/datetime.c 2003-08-18 17:30:48.000000000 -0400 > @@ -112,7 +112,20 @@ > /* Let DST be unknown. mktime() should compute the right value > ** and behave correctly. Unless the user overrides this. > */ > - ta->tm_isdst = -1; > + /* > + ** If we are using gmmktime(), do not use the local > + ** server's setting of DST. GMT does not use daylight > + ** savings, so unless the user overrides us, this should > + ** be set to 0. > + ** - Luke Ehresman, Aug 2003, <[EMAIL PROTECTED]> > + */ > + if (gm) { > + ta->tm_isdst = 0; > + is_dst = 0; > + } else { > + ta->tm_isdst = -1; > + is_dst = -1; > + } > > /* > ** Now change date values with supplied parameters. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php -- Luke Ehresman luke[at]ehresman.org http://www.luke.ehresman.org -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php