# Resolved gmmktime() bug (patch enclosed)

- Thread: https://externals.io/message/4076
- Original archive: https://news-web.php.net/php.internals/4076
- Started by Luke Ehresman on 2003-08-18T21:55:56+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #4076 — Luke Ehresman — 2003-08-18T21:55:56+00:00

URL: https://externals.io/message/4076#4076

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

---

## #4077 — Derick Rethans — 2003-08-18T21:59:14+00:00

URL: https://externals.io/message/4076#4077 · In reply to: #4076

Hi,

can you please put all this information in the bugreport, so that we can 
track thie proceedings of this problem? I'll assign it to myself that so 
that I won't forget about it either :)

regards,
Derick



> 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
> 

-- 
"Interpreting what the GPL actually means is a job best left to those
                    that read the future by examining animal entrails."
-------------------------------------------------------------------------
 Derick Rethans                                 http://derickrethans.nl/ 
 International PHP Magazine                          http://php-mag.net/

---

## #4082 — Luke Ehresman — 2003-08-19T00:24:48+00:00

URL: https://externals.io/message/4076#4082 · In reply to: #4076

Thanks,  I added the comment, and the 4.3.2 patch to the bug report.
Luke



> 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, <lehresma@css.tayloru.edu>
> +	*/
> +	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, <lehresma@css.tayloru.edu>
> +	*/
> +	if (gm) {
> +		ta->tm_isdst = 0;
> +		is_dst = 0;
> +	} else {
> +		ta->tm_isdst = -1;
> +		is_dst = -1;
> +	}
>  
>  	/*
>  	** Now change date values with supplied parameters.
> 

> -- 
> 
> 

-- 
Luke Ehresman
luke[at]ehresman.org
http://www.luke.ehresman.org
