php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #55240 DateTime::createFromFormat with format 'd.m.Y Gi' returns wrong date
Submitted: 2011-07-19 11:11 UTC Modified: 2017-10-24 07:57 UTC
Votes:8
Avg. Score:3.8 ± 1.3
Reproduced:6 of 6 (100.0%)
Same Version:3 (50.0%)
Same OS:1 (16.7%)
From: m dot strucken at binserv dot de Assigned:
Status: Open Package: Date/time related
PHP Version: 5.3.6 OS: Windows Server 2008 R2
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2011-07-19 11:11 UTC] m dot strucken at binserv dot de
Description:
------------
Having a date without a delimiter between hour and minute and the hour without leading zero, the returned date from DateTime::createFromFormat() is incorrect

Test script:
---------------
$dt = DateTime::createFromFormat( 'd.m.Y Gi', '11.11.2009 800' );
echo $dt->format( 'd.m.Y Gi' );

Expected result:
----------------
11.11.2009 800

Actual result:
--------------
14.11.2009 800

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-07-19 18:33 UTC] felipe@php.net
-Package: Unknown/Other Function +Package: Date/time related
 [2011-08-03 20:09 UTC] derick@php.net
-Assigned To: +Assigned To: derick
 [2011-11-26 16:40 UTC] derick@php.net
Hi!

I've had a look at this, and now I can tell you what happens.
Without the delimiter, the 800 gets parsed as 80 hours, 0 minutes.
If you add 80 hours to  11.11.2009, that means 3 days, 8 hours, you get 14.11.2009, 8am.

If you call DateTime::getLastError, you see it shows a warning:

derick@whisky:~$ cat /tmp/test.php 
<?php
$dt = DateTime::createFromFormat( 'd.m.Y Gi', '11.11.2009 800' );
var_dump($dt);
var_dump(DateTime::getLastErrors());
echo $dt->format( 'd.m.Y G i' );
?>

derick@whisky:~$ php /tmp/test.php 
class DateTime#1 (3) {
  public $date =>  string(19) "2009-11-14 08:00:00"
  public $timezone_type =>  int(3)
  public $timezone =>  string(13) "Europe/London"
}
array(4) {
  'warning_count' =>
  int(1)
  'warnings' =>
  array(1) {
    [14] =>
    string(27) "The parsed time was invalid"
  }
  'error_count' =>
  int(0)
  'errors' =>
  array(0) {
  }
}
14.11.2009 8 00
derick@whisky:~$ 

The parser for "G" parses up to 2 characters, and it doesn't know how to stop if it encounters something too high. I'm looking at how I can changes this, but still not break BC in any form. I've changed the bug's status to FR now.

cheers,
Derick
 [2011-11-26 16:40 UTC] derick@php.net
-Type: Bug +Type: Feature/Change Request
 [2014-01-09 17:26 UTC] brian at brianhogg dot ca
This is similar to this example:

<?php
$date = DateTime::createFromFormat('MjY', 'Jan92014');
var_dump($date);
var_dump(DateTime::getLastErrors());

which outputs:

class DateTime#1 (3) {
  public $date =>
  string(19) "0014-04-02 18:24:29"
  public $timezone_type =>
  int(3)
  public $timezone =>
  string(13) "Europe/Zurich"
}
array(4) {
  'warning_count' =>
  int(1)
  'warnings' =>
  array(1) {
    [8] =>
    string(27) "The parsed date was invalid"
  }
  'error_count' =>
  int(0)
  'errors' =>
  array(0) {
  }
}

Technically you could know where to stop based on the fact that Y is 4 digits and M is 3 characters, but understand that parsing left-to-right makes this difficult.
 [2017-10-24 07:57 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: derick +Assigned To:
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC