php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #61955 Adding DateInterval to DateTime adds 1 additional hour
Submitted: 2012-05-05 20:45 UTC Modified: 2017-03-19 10:06 UTC
Votes:22
Avg. Score:4.7 ± 0.7
Reproduced:19 of 19 (100.0%)
Same Version:3 (15.8%)
Same OS:11 (57.9%)
From: php at arjanonline dot net Assigned: derick (profile)
Status: Closed Package: Date/time related
PHP Version: 5.3.12 OS: Linux / Mac
Private report: No CVE-ID: None
 [2012-05-05 20:45 UTC] php at arjanonline dot net
Description:
------------
When I create a DateTime object from a (any) timestamp and then add a DateInterval object to the DateTime object, the time in the DateInterval object is added and one additional hour is also added.

I have not noticed this behavior in versions up to and including 5.3.8, only in newer 5.3 versions. (I did not test in 5.4.)
Also the behavior is related to the default time zone, even though the created DateTime object is in UTC. I have tested several timezones and it appears that all Europe/* and North American America/* timezones are affected. The Australian timezones seem to be unaffected.

Information from phpinfo():
date
- date/time support => enabled
- "Olson" Timezone Database Version => 2012.3
- Timezone Database => internal


Test script:
---------------
date_default_timezone_set('Europe/Amsterdam');
$d1 = new DateTime('@0');
$d2 = clone($d1);
$d2->add(new DateInterval('PT5S'));
var_dump($d2);


Expected result:
----------------
object(DateTime)[2]
  public 'date' => string '1970-01-01 00:00:05' (length=19)
  public 'timezone_type' => int 1
  public 'timezone' => string '+00:00' (length=6)

Actual result:
--------------
object(DateTime)[2]
  public 'date' => string '1970-01-01 01:00:05' (length=19)
  public 'timezone_type' => int 1
  public 'timezone' => string '+00:00' (length=6)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-05-11 15:51 UTC] zhanglijiu at gmail dot com
My result is object(DateTime)#2 (3) { ["date"]=> string(19) "1970-01-01 00:00:05" 
["timezone_type"]=> int(1) ["timezone"]=> string(6) "+00:00" }

My system is MAC 10.6.8 php 5.3.1
 [2012-05-19 15:03 UTC] graham at grahamc dot com
One minor clarification - This is occurring in every version above 5.3.8.

After running git bisect, I've narrowed it down to this particular commit: 
https://github.com/php/php-src/commit/7411ae09f5565b3f0dfbbfeb71c8f848fd38d6ca
 [2012-05-19 15:40 UTC] derick@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: derick
 [2012-07-09 19:47 UTC] jgardynik at endlessrealities dot com
I'm getting the same thing. Any single date_modify() call is causing an extra hour to be added. If I add 1 minute, it still adds an extra hour. The commit that was bisected is very clearly adding an extra hour. If I use Pacific/Honolulu or UTC in date_default_timezone_set() it works fine. Apparently the fix was not specific enough in its implementation and it's taking effect all the time.

This is causing every single one of my monthly comparison reports to break in a rather large system because the time is getting thrown off.

I'm using PHP 5.4.4 on linux.
 [2012-09-11 14:58 UTC] chris dot baker dot gr at gmail dot com
Can reproduce this as well, just determined it to be the cause of new errors in a scheduling web app after updating to 5.4.
 [2012-09-11 19:13 UTC] chris dot baker dot gr at gmail dot com
To amend my earlier comment: my repro attempts show that if I create an instance of DateTime by passing a string to the constructor, everything works fine. If I use a timestamp in combination with DateTime::createFromFormat, I see the bug affect the results

Use of a string
-------------------------	
$start = new DateTime('09/13/2012 7:00pm');
$end = new DateTime('09/13/2012 8:00pm');
$interval = DateInterval::createFromDateString('30 minutes');

// expected, 1 hours, 0 minutes, get 1 hours, 0 minutes
$diff = $start->diff($end);
print 'Diff: '.$diff->h.' hours, '.$diff->i.' minutes'."\n";

$end->add($interval);
$diff = $start->diff($end);
// ecpected: 1 hours, 30 minutes, get 1 hours, 30 minutes
print "\n".'Diff after interval: '.$diff->h.' hours, '.$diff->i.' minutes';


Use of a timestamp
-------------------------

$start = DateTime::createFromFormat('U', 1347577200);
$end =  DateTime::createFromFormat('U', 1347580800);
$interval = DateInterval::createFromDateString('30 minutes');

// expected, 1 hours, 0 minutes, get 1 hours, 0 minutes
$diff = $start->diff($end);
print 'Diff: '.$diff->h.' hours, '.$diff->i.' minutes'."\n";

$end->add($interval);
$diff = $start->diff($end);
// ecpected: 1 hours, 30 minutes, get 2 hours, 30 minutes
print "\n".'Diff after interval: '.$diff->h.' hours, '.$diff->i.' minutes';

http://3v4l.org/fivbW

The extra one hour makes less sense considering that my server timezone is -5 UTC -- not that it makes sense for DateInterval to be sensitive to timezone!
 [2012-11-24 00:13 UTC] whistl0r+php at googlemail dot com
This bug seems to be still present in PHP 5.3.19. My test script:

<?php
// The local system is set to Europe/Berlin timezone, so set it for PHP, too:
date_default_timezone_set( 'Europe/Berlin');
echo 'Current date: ' . date('c') . PHP_EOL;

// Now, we are switching to UTC...
date_default_timezone_set( 'UTC');

$timezone = new DateTimeZone( 'UTC' );
$datetime = new DateTime( null, $timezone );
$datetime->setTime( 00, 00, 00 );
$datetime->add( new DateInterval( 'P1D' ) );

// Output
echo 'mktime():    ' . ( mktime( 23, 59, 59 ) + 1 ) . PHP_EOL;
echo 'gmmktime():  ' . ( gmmktime( 23, 59, 59 ) + 1 ) . PHP_EOL;
echo 'datetime():  ' . $datetime->getTimestamp() . PHP_EOL;
echo 'time():      ' . time() . PHP_EOL;
echo 'microtime(): ' . microtime( true ) . PHP_EOL;
echo 'Used TZ:     ' . date_default_timezone_get() . PHP_EOL;
?>

I run this test script at 2012-11-24T00:00:00+01:00. This is my output:

Current date: 2012-11-24T00:00:00+01:00
mktime():    1353715200
gmmktime():  1353715200
datetime():  1353715200
time():      1353711600
microtime(): 1353711600.7557
Used TZ:     UTC

I am expecting that at least the DateTime value should be equal to time(), because both functions should represent a UNIX timestamp (which is per definition UTC).

But I am also not sure if the gmmktime() *and* mktime() should be equal... and I don't understand the 3600 offset at all - remember, we set UTC timezone before...
 [2012-11-24 01:15 UTC] whistl0r+php at googlemail dot com
I think this bug was introduced with http://svn.php.net/viewvc/?view=revision&amp;revision=319767
 [2013-05-05 12:10 UTC] jack at jtom dot me
This bug is still up. I'm experiencing it on PHP 5.4.3 and Windows 8 x64 platform. 
I had to have 'Europe/Warsaw' set as the default timezone to make the bug occur.

Currently I managed to handle this bug by switching the default timezone to UTC 
every time I make date->add/sub/modify , but it's definitely annoying :(
 [2015-03-18 19:31 UTC] floridia at gmail dot com
Similiar issue:

The following code doesn't work with particular date 2015-02-21 23:45:00 when trying to add 15 minutes...


$date1 = new DateTime('2015-02-21 23:45:00');
$interval = new DateInterval('PT15M');
print_r($date1);
$date1->add($interval);
print_r($date1);

Output
DateTime Object
(
    [date] => 2015-02-21 23:45:00.000000
    [timezone_type] => 3
    [timezone] => America/Sao_Paulo
)
DateTime Object
(
    [date] => 2015-02-21 23:00:00.000000
    [timezone_type] => 3
    [timezone] => America/Sao_Paulo
)

Expected Output
DateTime Object
(
    [date] => 2015-02-22 00:00:00.000000
    [timezone_type] => 3
    [timezone] => America/Sao_Paulo
)
 [2015-03-18 19:38 UTC] floridia at gmail dot com
Related with DST Change:
https://bugs.php.net/bug.php?id=51051
 [2015-03-18 20:11 UTC] floridia at gmail dot com
Got it. It is not really a bug in my case. That day is the turning point of DST. To work around that behavior I disabled the DST, changing the timezone to a neutral one (Etc/GMT-3) instead of a political one (America/Sao Paulo). More detail in Qualcuno's answer here:
http://stackoverflow.com/questions/25478998/disable-daylight-saving-functionality
 [2017-03-19 10:06 UTC] heiglandreas@php.net
-Status: Assigned +Status: Closed
 [2017-03-19 10:06 UTC] heiglandreas@php.net
The original issue seems to be fixed in currently supported PHP-Versions. Therefore I'm closing this issue.

PHP 7.1.2:

php > date_default_timezone_set('Europe/Amsterdam');
php > $d1 = new DateTime('@0');
php > $d2 = clone($d1);
php > $d2->add(new DateInterval('PT5S'));
php > var_dump($d2);
php shell code:1:
class DateTime#5 (3) {
  public $date =>
  string(26) "1970-01-01 00:00:05.000000"
  public $timezone_type =>
  int(1)
  public $timezone =>
  string(6) "+00:00"
}
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC