I was doing some research on the 2,357th report of a timezone error in date or calendar or event, one of those errors that not everyone can reproduce, and found some very interesting info about gmmktime() -- a function that is used extensively in all these modules.
The launchpad was this issue: http://drupal.org/node/147392. Here dgtlmoon was proposing to change some code from:
<?php
$now = (time() - date("Z"));
?>to:
<?php
$now = (gmmktime()) ;
?>I told him there should be no reason for such a change because time() should create the current time, adjusted by the server's timezone, date('Z') should adjust it for the timezone difference, and gmmktime() should be the current time with no timezone adjustment. In other words, they should be the same.
He ran some tests and reported that they were NOT the same on his server, so I set up a very simple 2 line test script and ran it on my own server to determine the difference between time() and gmmktime() on a server that is not set to GMT. I would expect the difference to be the timezone offset, and in php 4, that's what it is. But on php 5 time() and gmmktime() produce identical results. Whoa!!
Aha, I thought. This is maybe a php 5 bug that needs to be reported. So I went to the zend site and searched through bugs and found a number of interesting ones for various versions of php. I also found that although all arguments for mktime() and gmmktime() are stated to be optional, apparently they are not. Basically, it looks like gmmktime() may be the source behind at least some of the timezone errors on the issue queues.
Here are some of the things I found:
From the php issue queue http://bugs.php.net/bug.php?id=30096:
Bug #30096 - a mysterious 1 hour discrepancy in the results for gmmktime() depending on whether it is being calculated during daylight savings time or not.
Another issue on the php issue queue http://bugs.php.net/bug.php?id=36367:
Bug #36367 gmmktime() returns GMT offset in wrong direction -- if 2 hours should be added, instead 2 hours are subtracted.
From the Zend newsletter at http://devzone.zend.com/article/464-Zend-Weekly-Summaries-Issue-210:
Derick...agreed that the problem Vladimir had identified was real - gmmktime() returns bogus results due to some confusion over DST.
Another Zend newsletter: http://devzone.zend.com/node/view/id/1517
Last week's discussion about mktime()'s newfangled E_STRICT error message turned out to be the key that opened a can of worms..Effectively, that boiled down to silently making mktime() with no arguments a synonym for time()...Pierre pointed out that gmmktime() will also throw an E_STRICT warning now. He couldn't see any reason not to just fix both functions in the way he'd suggested; it was obvious from a simple search that a lot of PHP applications use mktime() in what is now deemed the 'wrong' way... Pierre pointed out that his fix would force mktime() without arguments to use the exact same internal code as time(), and there would be next to no advantage in choosing one over the other if he got his way...Derick stuck to his [guns], too, writing a careful explanation of the way gmmktime() without arguments is broken in PHP 4 and correctly handled in PHP 5.1 and up.

Comments
you said "time() should
you said "time() should create the current time, adjusted by the server's timezone" but that's not correct, time() gives you the number of seconds since January 1 1970 00:00:00 GMT -- this will be the same no matter where you are or what timezone you're using.
with the optional arguments, often times you don't want to leave them out because weird things will happen. for instance you need to choose a generic day or hour that is always valid.
I don't think that is right,
I don't think that is right, according to Zend, time() is equivalent to mktime(), an the mktime() documentation says
while the gmmktime() documentation says
Also, note that all parameters are supposed to be optional, so gmmktime() should be creating the current GMT date and time() and mktime() should be creating the current local date. So they should be different, and they are different in php4 but are not different in php5.
mktime() and gmmktime accept
mktime() and gmmktime accept different things (times in local timezone vs. GMT) but create the same thing, a unix timestamp. as does time(), which doesn't accept any parameters.
The values you put in to the mktime functions, as well as any you leave out, are assumed to be local timezone hours, days, etc. for mktime() and GMT hours, days, etc. for gmmktime().
They all create unix timestamps, which are timezone agnostic; just a count of seconds; a unix timestamp in one timezone is the same as the unix timestamp in another. If the unix timestamps are different then they are different/non-simultaneous times.
if you're not passing any parameters, there's no reason to use mktime() or gmmktime(), you just use time() which I'd assume uses a little less resources.
I was using time(), it was
I was using time(), it was some of the proposed patches that were using gmmktime().
However, you're right about time() -- my understanding was that it would produce a different result depending on the timezone of the server and it does not.
time(), mktime(), and gmmktime() tests
I ran some tests to see what happened by changing between php4 and php5 on negative, positive and gmt server settings, with and without arguments, and came up with the following. I just changed my server timezone, then switched back and forth between php4 and php5, restarting apache each time.
The server offset (date('Z')) that was zero in php4 ended up as 3600 in php5, while all other offsets matched. I have no explanation for that.I goofed on that value, the timezone offset is the same in all versions. I was trying for GMT but got 1 hour of DST instead.Actual local time starting June 26, 2007 at 8:46 AM, negative timezone
Php version: 4.4.7>
Server offset: -18000>
Php version: 5.2.2>
Server offset: -18000>
Change server to GMT
Php version: 4.4.7>
Server offset: 3600>
Php version: 5.2.2>
Server offset: 3600>
Change server to positive timezone
Php version: 4.4.7>
Server offset: 36000>
Php version: 5.2.2>
Server offset: 36000>
I have my server set to UTC
I have my server set to UTC by simply removing the /etc/localtime file, which causes the operating system to default to UTC. It works the same on both PHP4 and PHP5:
% php -r "print date(r);"
Tue, 26 Jun 2007 15:32:26 +0000
% php-4.4.7/sapi/cli/php -r "print date(r);"
Tue, 26 Jun 2007 15:32:34 +0000
If I change to british summer time it also works the same on PHP4 and PHP5:
% export TZ=Europe/London
% php -r "print date(r);"
Tue, 26 Jun 2007 16:33:01 +0100
% php-4.4.7/sapi/cli/php -r "print date(r);"
Tue, 26 Jun 2007 16:33:10 +0100
I guess I should just read
I guess I should just read the site rather than what landed in my inbox :p
date('r') would be the same
date('r') would be the same as date('r', time()), and in my tests there was no difference between php4 and php5 on that either. The problem is we can't assume people have any control over their server timezone (many don't) so the best we can do is adjust for it, which we usually do by using date('Z') to adjust results.
My main point is that gmmktime() is not reliable/consistant between php4 and php5 if no arguments are supplied, and if you read some of the bug reports I linked to above you'll see that gmmktime() can also produce wrong results in some php versions even if arguments are supplied, so we just have to be very careful how we use it.
Anyway, looking at the results in my table above, I need to go back through all my Date and Calendar code and make sure I've made the right use of all these functions, and I'm starting to do that now.
Is the issue that you're
Is the issue that you're storing dates in local server time? It would be preferable to store dates in GMT, this also makes the site and database more portable between servers.
In my testing at least the latest versions of PHP4 and PHP5 have identical behavior of gmmktime() with no arguments. You do have to be careful how you use both mktime and gmmktime, for instance some months don't have certain days (february) and some days don't have certain hours (when clocks are set forward) so weird things can happen if you don't supply a valid time.
I'm trying to store gmt, not
I'm trying to store gmt, not local time, so any time that didn't happen it was a mistake that needs to be corrected.
But in my testing they don't, as you can see above. Anyway, results are not consistent across systems and versions, which is my point.
OK I did find a difference
OK I did find a difference between the latest versions of PHP4 and PHP5, if my server environment is not UTC, if values are not passed in to gmmktime(). In this case you need to use time(). To get a GMT date in some format, given any unix timestamp, use gmdate(). Hopefully gmmktime() does work the same everywhere when at least one valid parameter is passed in...
gmmktime() doesn't work the
gmmktime() doesn't work the same in all versions even when you pass in valid parameters. One problem noted was that if you don't pass in the dst parameter (the last optional parameter that practically no one uses) you can have dst errors in some versions. There were bug report and comments on the php.net site reporting this. So a good rule of thumb may be to just avoid gmmktime() whenever possible.
Some results when parameters are given
I know the discussion is old, but I thought this info could fit here.
The following was run with the date_php4 module, when server date is 2008-07-18T19:55:15 +7200. Timezone is Europe/Stockholm with DST (daylight saving time). I fear some results may differ if run with the server clock on standard time (during winter).
For the summer-date where the versions differ, I believe PHP5 is correct. The
is_dst-parameter (0,1or omitted) tells how to treat input (standard time or DST), while timestamps always can be thought of as using standard time.With
mktimeand the parameters used above, there is no difference between PHP4 and PHP5.I got "off by +1 hour"-errors when viewing datetimes since date_php4.inc. When I changed line 888 (July 10, 2008) into
<?phpif (gmmktime(0,0,0,6,1,2008, 0) == 1212282000) {
//Seems to be running PHP (like 4.3.11).
//At least if current local timezone is Europe/Stockholm with DST in effect, skipping the ,0 helps:
return @gmmktime($hr, $min, $sec, $mon, $day, $year); //without is_dst-parameter at the end
}
return @gmmktime($hr, $min, $sec, $mon, $day, $year, 0); // original line 888
?>
the problems were solved. I am however not sure if the check always works as intended, and if it will work during winter.
I'll probably report an issue about this later, but I feel very uncertain whether my change would work everywhere.