Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.5.0a4

Bug #2378 getDate(DATE_FORMAT_UNIXTIME) doesn't convert to GMT
Submitted: 2004-09-23 05:32 UTC Modified: 2009-01-01 03:53 UTC
From: scragz at hotmail dot com Assigned: c01234
Status: Assigned Package: Date
PHP Version: 4.3.8 OS: Debian Sarge
Roadmaps: (Not assigned)    
Subscription  


 [2004-09-23 05:32 UTC] scragz at hotmail dot com
Description: ------------ If you have a Date in another TZ and ask use getDate(DATE_FORMAT_UNIXTIME) or getTime() the timestamp returned will be wrong since it is only using mktime. Trying to fix this caused me some problems, but I have a patch (below) that seems to work. Reproduce code: --------------- <?php $date =& new Date(); echo $date->getTime()."\n"; $date->convertTZbyID('America/Los_Angeles'); echo $date->getTime()."\n"; ?> This patch corrects the faulty behavior. I'm not sure if DATE_FORMAT_TIMESTAMP is expected to be GMT, but this could be adapted to that as well. Index: Date.php =================================================================== --- Date.php (revision 111) +++ Date.php (working copy) @@ -231,7 +231,16 @@ return $this->format("%Y%m%d%H%M%S"); break; case DATE_FORMAT_UNIXTIME: - return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); + $date =& new Date($this); + if ($date->tz->offset) { + $offset = ($date->tz->offset + $date->tz->getDSTSavings()) / 1000; + if ($offset > 0) { + $date->subtractSeconds(intval($offset)); + } else { + $date->addSeconds(intval(abs($offset))); + } + } + return mktime($date->hour, $date->minute, $date->second, $date->month, $date->day, $date->year); break; } } Expected result: ---------------- 1095935549 1095935549 Actual result: -------------- 1095935549 1095910349

Comments

 [2004-09-24 04:54 UTC] scragz at hotmail dot com
Forgot DST. --- Date.php (revision 100) +++ Date.php (working copy) @@ -231,7 +231,17 @@ return $this->format("%Y%m%d%H%M%S"); break; case DATE_FORMAT_UNIXTIME: - return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); + $date =& new Date($this); + if ($date->tz->offset) { + $dst = ($date->inDaylightTime()) ? $date->tz->getDSTSavings() : 0; + $offset = ($date->tz->offset + $dst) / 1000; + if ($offset > 0) { + $date->subtractSeconds(intval($offset)); + } else { + $date->addSeconds(intval(abs($offset))); + } + } + return mktime($date->hour, $date->minute, $date->second, $date->month, $date->day, $date->year); break; } }
 [2004-09-25 02:11 UTC] scragz at hotmail dot com
That whole patch could be consolidated to a single call to $date->toUTC(). Also, I just realized that Date_TimeZone::inDaylightTime() uses Date::getTime(), which causes recursion that segfaults PHP. I kluged through this by using strtotime(), which seems to be working since the TZ env variable is set right before there.
 [2005-03-14 14:27 UTC] mjs15451 at hotmail dot com
So what is the final patch for this since no one seems to be maintaining this?
 [2005-03-14 15:20 UTC] scragz at hotmail dot com
Below are all of my changes to Date. They involve this bug, bug 2217 (compare), 2401 (more lenient regexp), and maybe something else I'm missing. --- Date.dist.php 2005-03-14 12:07:42.172448280 -0800 +++ Date.php 2005-02-13 14:08:33.000000000 -0800 @@ -153,7 +153,7 @@ { if ( - preg_match('/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?$/i', $date, $regs) + preg_match('/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})?(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?$/i', $date, $regs) && $format != DATE_FORMAT_UNIXTIME) { // DATE_FORMAT_ISO, ISO_BASIC, ISO_EXTENDED, and TIMESTAMP // These formats are extremely close to each other. This regex @@ -231,7 +231,9 @@ return $this->format("%Y%m%d%H%M%S"); break; case DATE_FORMAT_UNIXTIME: - return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); + $date =& new Date($this); + $date->toUTC(); + return mktime($date->hour, $date->minute, $date->second, $date->month, $date->day, $date->year); break; } } @@ -731,6 +733,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); @@ -1222,4 +1226,3 @@ // // END ?> - --- Date/TimeZone.dist.php 2005-03-14 12:11:59.604192760 -0800 +++ Date/TimeZone.php 2005-02-13 14:08:33.000000000 -0800 @@ -255,7 +255,9 @@ $env_tz = getenv("TZ"); } putenv("TZ=".$this->id); - $ltime = localtime($date->getTime(), true); + //$ltime = localtime($date->getTime(), true); + $time = strtotime($date->getYear().'-'.$date->getMonth().'-'.$date->getDay().' '.$date->getHour().':'.$date->getMinute().':'.$date->getSecond()); + $ltime = localtime($time, true); putenv("TZ=".$env_tz); return $ltime['tm_isdst']; } @@ -3643,4 +3645,3 @@ // // END ?> -
 [2005-03-14 16:37 UTC] mjs15451 at hotmail dot com
I found that the best thing to do is to remove these two lines in timezone.php as they make absolutely no sense to use since all they do is screw up the conversion and it seems to perform just fine without it: putenv("TZ=".$this->id); putenv("TZ=".$env_tz);
 [2005-03-15 14:48 UTC] mjs15451 at hotmail dot com
Better yet, I did more testing and I found it's better to leave the putenv functions in. Just make sure you set putenv(TZ=YourTimeZone) before calling any Pear Date functions because PHP doesn't seem to set the server default Timezone in this variable. A null TZ variable is what is the most problematic. Obviously this variable setting needs to be allowed in safe mode for any date calculation to actually work correctly.
 [2005-03-15 17:04 UTC] scragz at hotmail dot com
That's the thing, in my app the TZ gets set so I haven't noticed any problems the way I have it.
 [2005-03-16 05:28 UTC] arnaud
Another way is to call gmmktime() if the TZ is UTC. One just needs to convert to the date toUTC() before calling getTime(), no DST detection is needed since it has been taken care of before.
 [2006-10-01 14:41 UTC] arnaud (Arnaud Limbourg)
Until the package gets a new maintainer.
 [2006-12-09 03:09 UTC] firman (Firman Wandayandi)
Yes, sometimes a value will not change after you call the convertTZbyID(), but your timezone has changed and you will get a right result. It would be wrong result if your patch applied and did BC break. You can try to run a test script below (with Date-1.4.7 or CVS): http://cvs.php.net/viewvc.cgi/pear/Date/tests/bugs/bug-2378.phpt?view=markup
 [2007-11-07 16:19 UTC] c01234 (Chuckie Chuck)
I think this bug is fixed now in CVS
 [2008-03-23 19:04 UTC] c01234 (Chuckie Chuck)
Thank you for your bug report. This issue has been fixed in the latest released version of the package, which you can download at http://pear.php.net/get/Date
 [2008-11-09 02:55 UTC] doconnor (Daniel O'Connor)
Reopening, because /home/clockwerx/pear/Date/tests/bugs/bug-2378-1.phpt is broken in the unit tests
 [2008-11-09 02:56 UTC] doconnor (Daniel O'Connor)
(broken: php 5.2.6, unbuntu)
 [2009-01-01 03:52 UTC] doconnor (Daniel O'Connor)
Bug #14413 has broken this test
 [2009-01-01 03:53 UTC] doconnor (Daniel O'Connor)
16) /home/clockwerx/pear/Date/tests/bugs/bug-2378-1.phpt --- Expected +++ Actual @@ -1,2 +1,2 @@ -1095935549 -1095935549 \ No newline at end of file +943885800 +1230733800 \ No newline at end of file /home/clockwerx/pear/AllTests.php:136 /home/clockwerx/pear/AllTests.php:525