Issues

ZF-11438: Zend Date 2038

Issue Type: Bug Created: 2011-06-03T16:17:50.000+0000 Last Updated: 2012-03-02T19:16:07.000+0000 Status: Open Fix version(s): Reporter: Timmo Henseler (zensys) Assignee: Thomas Weidner (thomas) Tags: - Zend_Date

  • zend_date

Related issues: Attachments:

Description

Though Zend_Date claims to solve the 2038 issue, when I do:

$date = new Zend_Date(); $date->addMonth(350);

I get a date in 1970.

With my limited knowledge of the ZF internals I tracked this down to Zend_Date_DateObject in the (internal) function mktime() where a check is made on $year being between 1901 and 2038. But with months > 12 this would not be the right check resulting in the native mktime() function receiving a date > 2038.

Comments

Posted by Adam Lundrigan (adamlundrigan) on 2011-06-03T16:31:31.000+0000

Could you provide an example?

I attempted to reproduce your issue:

<pre class="highlight">
/**
 * @group ZF-11438
 */
public function testAddMonthsDoesNotCauseDateToFallVictimTo2038Bug()
{
    $date = new Zend_Date();
    $date->addMonth(350);
    $this->assertEquals('2040',date("Y", $date->getTimestamp()));
}

However, this test passes when run against SVN trunk.

Posted by Timmo Henseler (zensys) on 2011-08-19T18:11:45.000+0000

Sorry to have left this so long, on my system (Ubuntu 11.04, PHP Version 5.3.5-1ubuntu7.2, ZF 1.11.10) this test does not pass. There I was stuck, but looking at the below snippet of the internal mktime function of Zend_Date_DateObject I understand my negative result:

<pre class="highlight">protected function mktime($hour, $minute, $second, $month, $day, $year, $gmt = false)
    {
        // complete date but in 32bit timestamp - use PHP internal
        if ((1901 < $year) and ($year < 2038)) {

            $oldzone = @date_default_timezone_get();
            // Timezone also includes DST settings, therefor substracting the GMT offset is not enough
            // We have to set the correct timezone to get the right value
            if (($this->_timezone != $oldzone) and ($gmt === false)) {
                date_default_timezone_set($this->_timezone);
            }
            $result = ($gmt) ? @gmmktime($hour, $minute, $second, $month, $day, $year)
                             :   @mktime($hour, $minute, $second, $month, $day, $year);
            date_default_timezone_set($oldzone);

            return $result;
        }

This checks for the $year argument but not for the total result of adding months, $years and the other arguments. Unless I miss some subtilities in other parts of the code, this is clearly a bug imho.

E.g. php mktime(0,0,0,350,0,2011) returns false on my system - as does mktime(0,0,0,11,0,2038) but not mktime(0,0,0,1,0,2038) - but these arguments pass the test to qualify for the internal php mktime in the function above. This would not be noticed in most cases because either the year needs to be close to 2038 or the number of months needs to be equivalent to a large number of years, as in my case (I use Zend_Date for actuarial calculations where these extreme cases are not unusual).

Still this does explain why your assertEquals passes ...

Posted by Timmo Henseler (zensys) on 2011-08-19T18:15:34.000+0000

Last line of my previous comment should of course be:

Still this does NOT explain why your assertEquals passes ...

Posted by Shaun Freeman (vincentbluff) on 2011-09-03T21:39:33.000+0000

Are you using a 32bit OS or 64bit OS as I checked this on Ubuntu 64bit and got:

$date = new Zend_Date(); $date->addMonth(350);

= 3 Nov 2040 22:35:45

Posted by Shaun Freeman (vincentbluff) on 2011-09-03T21:44:53.000+0000

Sorry I forgot year 2038+ dates do not work on 32bit machines

Posted by Timmo Henseler (zensys) on 2011-09-04T07:14:07.000+0000

32 bit Ubuntu

I now use the following workaround:

// convert months to years to avoid 2038 bug in addMonth() $years = 0;
if (11 < $months) { $years = floor ($months / 12); $months -= 12 * $years; }

with the expected result (date somewhere in 2040)

Posted by Vasyl (vasylp) on 2012-03-02T19:16:07.000+0000

I reported absolutely the same issue few months earlier, but no response: http://framework.zend.com/issues/browse/…

In description I suggested the solution of this issue. Hope it will help to somebody. For me it works like a charm after mine modifications within internal mktime.

Have you found an issue?

See the Overview section for more details.

Copyright

© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.

Contacts