How do you explain the result for a new \DateTime('0000-00-00 00:00:00')?
Asked Answered
R

2

27

Here is a test code:

<?php

ini_set('date.timezone', 'Europe/London');    
$dt = new \DateTime('0000-00-00 00:00:00');

var_dump($dt);

This provides:

object(DateTime)[1]
  public 'date' => string '-0001-11-30 00:00:00' (length=20)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/London' (length=13)

Whereas this is not a valid date. I don't understand the returned value, especially the month... can you explain?

Roadblock answered 4/5, 2012 at 14:17 Comment(6)
I get the same now afetr my update. But I still don't understand the result :/ I'm on PHP 5.3.5-1ubuntu7.7Roadblock
what is the slash for in new \DateTime?Barium
actually have found the answer myself. it's smart in this case but seems pointless as i doubt anyone would make a class named DateTime. https://mcmap.net/q/116269/-what-does-a-backslash-in-front-of-function-names-meanBarium
But anyone could extend it ...Roadblock
Yes Andrew, not for this sample, bu if you prefix always the official PHP classes with the root of namespaces, then when you work with namespaces you don't need to refactor nothing.Abridge
the real question is, why would you want to use a non existing date 0000-00-00 00:00:00 in the first place?Heavyladen
T
30

You are seeing two effects here. The first one is that you use a way of writing for a date that can be written in multiple forms:

0000-01-01 same as  0000-01-01
0000-01-00 same as -0001-12-31
0000-00-01 same as -0001-12-01
0000-00-00 same as -0001-11-30

So by the date itself, you already specify the 30th November -1.

Now there's the time offset left that differs about the 9 minutes and 21 seconds. That is because of a change in the clock compared to UTC in Paris/France that happened 10 Mar 1911 23:51:38/39 local time.


I modified your code example a bit and introduced the Europe/Paris setting as you have it, which is playing a role. This code is telling as well the offset in seconds from UTC (Z) which is what you're looking for:

$dt = new DateTime('0000-00-00 00:00:00', new DateTimeZone('Europe/Paris'));
printf("%s secs offset from UTC\n", $dt->format('r T (e) Z'));

I changed the dates a bit

Fri, 10 Mar 1911 23:51:38 +0009 PMT (Europe/Paris) 561 secs offset from UTC
                                                   ^^^

One second later:

Fri, 10 Mar 1911 23:51:39 +0000 WET (Europe/Paris) 0 secs offset from UTC

When local standard time was about to reach Saturday, 11 March 1911, 00:01:00 clocks were turned backward 0:09:21 hours to Friday, 10 March 1911, 23:51:39 local standard time instead.

That are 561 Secs. Reference: Clock changes in Paris - Time change dates in 1911 and Time zone changes and daylight saving time start/end dates between year 1900 and 1924.

Tatro answered 4/5, 2012 at 14:21 Comment(9)
I know this is not a valid date, I understand it couldn't provide a valid output, but my question is "Does someone know why that result ?"Roadblock
What was the timezone earlier? Normally there's a difference between the two that you see (here a negative delta).Tatro
@Tatro interestingly there are only timezones in steps of 30 minutes, not explaining the weird offset of 09 minutes 21 seconds. Even more interesting is the -1 year, 11 month, 29 days offset. This is just odd - no matter if 0000-00-00 00:00:00 is considered a valid date or not..Macias
I've updated my questions with no timezone change (even if i wonder about the 09 minutes 21 seconds offset...)Roadblock
@Tatro : I get the same result as yours. Why 30th november ?Roadblock
UTC changed in the past, there is an offset of 561 secs.Tatro
awesome find. still not explaining why a) '0000-00-00' as a date (disregard the time for now) is not producing an error and b) the offset of 1 year, 10 month, 40 days)Macias
@PéCé: I've updated the answer again, probably it's now more clear why 30th of november. It looks totally okay, because the month or day 0 is the previous month (november) or the last day of the previous month (30/31).Tatro
You got it ! I totally missed the month decrementation !Roadblock
M
7

Looks like the error handling in DateTime is incomplete. Normally, other PHP functions handle '0000-00-00' as an error (invalid date).

DateTime should follow the same guidelines, but it doesn't. This code does not throw an Exception, even if it should:

try { $dt = new \DateTime('0000-00-00 00:00:00'); } 
catch (Exception $e) { var_dump($e); }
var_dump($dt); 
/* result:
object(DateTime)#1 (3) {
  ["date"]=>
  string(20) "-0001-11-30 00:00:00"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(13) "Europe/Berlin"
*/

Other functions do treat that input as an error:

var_dump(strtotime('0000-00-00 00:00:00'));  // returns: bool(false)

Seems like PHP has always had problems handling that case.. examples: Bug #30190, Bug #60288

Cite from the comments in PHP bug tracker:

0000-00-00 is a non-existant date (the day before 01-01-0001 was 31/12/-0001)

Macias answered 4/5, 2012 at 14:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.