Home » Date and Time » Date » Bug #2338
Comparison of dates changes the time zone
Details
| Submitted | 2004-09-15 14:50 UTC |
|---|---|
| From | andrew at awarez dot net |
| Assigned | firman |
| Status | Suspended |
| Package | Date |
| PHP Version | 4.3.10 |
| OS | Fedora Core 3 |
| Roadmaps | (Not assigned) |
Comments
[2004-09-15 14:50 UTC] andrew at awarez dot net
Description:
------------
Comparison of two dates using the Date::before(), or Date::after() methods results in the timezone that the date() function uses being changed to UTC. As a result, after calling these Date class methods, any Date objects created using "new Date()" may have the wrong current time.
In the following examples, "BST" is British Summer Time.
Using Date v1.4.3.
Reproduce code:
---------------
<?php
// Set the PEAR Date class location
ini_set('include_path', '/home/andrew/pear');
// Incluide the PEAR Date class
require_once 'Date.php';
/**************************************************************************/
// Echo the timezone obtained via the getenv() function
echo 'Current timezone is: ' . getenv('TZ') . '<br>';
// Echo the timezone obtained via the date() function
echo 'Current timezone is: ' . date('T') . '<br>';
// Create a new date
$date1 = new Date();
// Echo the date
echo 'Current date is: ' . $date1->format('%Y-%m-%d %H:%M:%S') . '<br>';
/**************************************************************************/
// Do nothing...
/**************************************************************************/
// Echo the timezone obtained via the getenv() function
echo 'Current timezone is: ' . getenv('TZ') . '<br>';
// Echo the timezone obtained via the date() function
echo 'Current timezone is: ' . date('T') . '<br>';
// Create a new date
$date2 = new Date();
// Echo the date
echo 'Current date is: ' . $date2->format('%Y-%m-%d %H:%M:%S') . '<br>';
/**************************************************************************/
// Compare date 1 and date 2
$date1->after($date2);
/**************************************************************************/
// Echo the timezone obtained via the getenv() function
echo 'Current timezone is: ' . getenv('TZ') . '<br>';
// Echo the timezone obtained via the date() function
echo 'Current timezone is: ' . date('T') . '<br>';
// Create a new date
$date3 = new Date();
// Echo the date
echo 'Current date is: ' . $date3->format('%Y-%m-%d %H:%M:%S') . '<br>';
/**************************************************************************/
?>
Expected result:
----------------
Current timezone is:
Current timezone is: BST
Current date is: 2004-09-15 15:46:06
Current timezone is:
Current timezone is: BST
Current date is: 2004-09-15 15:46:06
Current timezone is:
Current timezone is: BST
Current date is: 2004-09-15 15:46:06
Actual result:
--------------
Current timezone is:
Current timezone is: BST
Current date is: 2004-09-15 15:46:06
Current timezone is:
Current timezone is: BST
Current date is: 2004-09-15 15:46:06
Current timezone is:
Current timezone is: UTC
Current date is: 2004-09-15 14:46:06
[2004-09-22 21:09 UTC] scragz at hotmail dot com
I just ran in to this problem and this is how I fixed it:
Index: Date.php
===================================================================
--- Date.php (revision 111)
+++ Date.php (working copy)
@@ -731,6 +731,8 @@
*/
function compare($d1, $d2)
{
+ $d1 =& new Date($d1);
+ $d2 =& new Date($d2);
$d1->convertTZ(new Date_TimeZone('UTC'));
$d2->convertTZ(new Date_TimeZone('UTC'));
$days1 = Date_Calc::dateToDays($d1->day, $d1->month, $d1->year);
[2004-09-27 13:39 UTC] andrew at awarez dot net
Okay, that's a possible way to work around the bug, but what happens when I actually want the Dates to be in BST (which they should be)?
[2004-12-04 04:05 UTC] rbro at hotmail dot com
Has there been any update on this? I just added a comment in bug 2217 which basically describes the same problem. An additional side effect when running Date::compare in PHP 5 is that the 2 parameters passed to the compare function also get converted into UTC because objects are passed by reference in PHP 5.
[2004-12-20 01:19 UTC] skrald at amossen dot dk
A fix on this could be really nice. Date becomes quite unusefull when before(), after() and compare() resets the timezone.
However, a fix is easily done by cloning the arguments for compare() before using them:
function compare($d1, $d2)
{
$d1 = clone($d1);
$d2 = clone($d2);
....
This should also fix the errors in before() and after().
Notice: In order to make the class thread safe, compare() must operate on a clone because another thread might access the arguments for compare() in the meantime.
[2004-12-20 09:55 UTC] christian at wenz dot org
I don't think "clone $d1; clone $d2;" would work as PEAR::Date only requires PHP >= 4.2.
[2004-12-22 14:45 UTC] andrew at awarez dot net
Okay, I've located where the problem is. On the system I have described, when the Date_TimeZone::inDaylightTime() method is called, the call to getenv("TZ") returns false. As a result, later on in the method, when the timezone is attempted to be restored, this means a call is made putenv("TZ="), which results in the UTC timezone.
So, does anyone that know more about getenv and putenv than me know a way to actually remove the set TZ env "variable", rather than setting it to a null string?
[2005-07-11 12:49 UTC] andrew at awarez dot net
I have tried the patch, but the error persists.
[2005-10-24 09:27 UTC] franek5 at wp dot pl
I think that problem is quite easy to solve... It's caused by null initial value of TZ enviroment variable. Method Date_TimeZone::inDaylightTime() converts time value to UTC timezone - value TC's variable is changed to UTC. Later this method try to convert time back to original TZ setting (this can't be done properly because original TZ value was NULL). In result timezone setting in current script changes to UTC.
Solution i used to bypass this problem is quite simple -
I set TZ's value on beginning of my script to my default timezone:
putenv("TZ=CET"); -- for Central European Timezone
[2006-06-13 17:26 UTC] Nagy dot Attila dot Gabor at gmail dot com
Well, I believe this bug is serious enough to be patched in the current tree, without API change. Nathan's patch works well, and I believe it has a little resource impact.
Here's how I've patched (also php4-php5 safe):
--- /tmp/Date.php 2006-06-13 18:48:41.000000000 +0200
+++ Date.php 2006-06-13 18:53:48.000000000 +0200
@@ -763,6 +763,10 @@
*/
function compare($d1, $d2)
{
+ if (version_compare('5.0.0', phpversion(), '<')) {
+ $d1 = new Date($d1);
+ $d2 = new Date($d2);
+ }
$d1->convertTZ(new Date_TimeZone('UTC'));
$d2->convertTZ(new Date_TimeZone('UTC'));
$days1 = Date_Calc::dateToDays($d1->day, $d1->month, $d1->year);