ID:               14391
 Updated by:       [EMAIL PROTECTED]
 Reported By:      pilots at farlep dot net
-Status:           Open
+Status:           Closed
 Bug Type:         Documentation problem
 Operating System: Windows 2000 Server
 PHP Version:      4CVS/5CVS
 New Comment:

This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation
better.

"Parameters always represent a GMT date so is_dst doesn't influence the
result."


Previous Comments:
------------------------------------------------------------------------

[2003-09-03 07:33:38] [EMAIL PROTECTED]

From: Luke Ehresman <lehresma (at) css (dot) tayloru (ot) .edu>

Derick,

Alright, after analyzing every line of the php_mktime() function, I
finally figured out the problem.  There isn't actually a bug.  However,
the PHP documentation is very deceptive.  The 7th parameter of the
gmmktime function does not perform expected behavior.  In reality,
there is no need for the functionality that it does provide.  The only
reason it is there is so it is virtually the same as the mktime()
function.

Anyhow..  By reading the documentation, what I gathered that it would
do was to apply a daylight savings time offset to the GMT timestamp
before returning.  What it really is doing is turning on or off the
feature of compensating for the fact that the C "mktime" function
already applied the server's daylight savings time preference.

With gmmktime, we should ALWAYS compensate for that.  I see no possible
reason that you would not want to.

Anyhow, I think I am not the only one to get confused by this stuff.
Perhaps it would be a good idea to either updating the documentation,
or making the interfaces a little clearer in PHP, or both.

I'm kinda disappointed that it wasn't a bug though.  I was looking
forward to having my PHP patch accepted.  :)

Thanks for your help,
Luke


------------------------------------------------------------------------

[2003-08-18 19:22:27] lehresma at css dot tayloru dot edu

Posted this on php-dev and was advised to put it here as well.
--
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.
--




PATCH for php4.3.2
---
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.

------------------------------------------------------------------------

[2002-01-20 10:54:51] max at flipstorm dot net

Here's an example:

first of all, to show that the system understands what's going on:

$ date "+%c %Z"
Tue Dec 18 22:51:16 2001 GMT
$ date -u "+%c %Z"
Tue Dec 18 22:51:21 2001 GMT

 - same result. so the machine knows what tz it's in.

Now, I'm in GMT at the moment, so 

echo date("H:i",mktime(22,20,00,12,18,01))."<p>";  //gives 22.20
echo gmdate("H:i",mktime(22,20,00,12,18,01))."<p>"; // gives 22.20

as expected. but...

echo date("H:i",gmmktime(22,20,00,12,18,01))."<p>";  //gives 21.20
echo gmdate("H:i",gmmktime(22,20,00,12,18,01))."<p>"; // gives 21.20

These should also give 22.20, so it looks to me that gmmktime() is
screwed.

Max

------------------------------------------------------------------------

[2001-12-09 07:29:35] pilots at farlep dot net

Please see the code below. The comments are the result of running this
code on my PC, (my GMT Offset = +2 hours = +7200 sec.)
You may see that the mktime() and date() functions work correct, but
gmmktime() returns wrong value in winter time (when it is not a
daylight saving time), and gmdate returns wrong "Z" parameter.
Note: this bug does not appear on UNIX systems.

<?
$df="d.m.Y - H:i:s (Z), I";

$t=mktime(0,0,0,1,2,1970);
echo    "<br><b>Make 02.01.1970 - 00:00:00 (Local):</b><br>",
        "Timestamp: $t<br>",                    // 79200
        "GMT: ", gmdate($df,$t), "<br>",        // 01.01.1970 - 22:00:00 (7200)
        "Local: ", date($df,$t), "<br>",        // 02.01.1970 - 00:00:00 (7200)
        "----------------------------------------<br>";

$t=gmmktime(0,0,0,1,2,1970);
echo    "<br><b>Make 02.01.1970 - 00:00:00 (GMT):</b><br>",
        "Timestamp: $t<br>",                    // 82800 (Why !=86400 ?)
        "GMT: ", gmdate($df,$t), "<br>",        // 01.01.1970 - 23:00:00 (7200)
        "Local: ", date($df,$t), "<br>",        // 02.01.1970 - 01:00:00 (7200)
        "----------------------------------------<br>";

$t=mktime(0,0,0,7,20,1970);
echo    "<br><b>Make 20.07.1970 - 00:00:00 (Local):</b><br>",
        "Timestamp: $t<br>",                    // 17269200
        "GMT: ", gmdate($df,$t), "<br>",        // 01.07.1970 - 21:00:00 (7200)
        "Local: ", date($df,$t), "<br>",        // 02.07.1970 - 00:00:00 (10800)
        "----------------------------------------<br>";

$t=gmmktime(0,0,0,7,20,1970);
echo    "<br><b>Make 20.07.1970 - 00:00:00 (GMT):</b><br>",
        "Timestamp: $t<br>",                    // 17280000 (=86400*200)
        "GMT: ", gmdate($df,$t), "<br>",        // 02.07.1970 - 00:00:00 (7200)
        "Local: ", date($df,$t), "<br>",        // 02.07.1970 - 03:00:00 (10800)
        "----------------------------------------<br>";
?>


------------------------------------------------------------------------


-- 
Edit this bug report at http://bugs.php.net/?id=14391&edit=1

Reply via email to