Why is this datetime formatting inconsistent?

$timestamp = time();
$datetime = new DateTime("@$timestamp", new DateTimeZone('UTC'));
$format = $datetime->format('e');
var_dump($format);

gives “2015-05-03 14:53:39 +00:00”

but doing it on several lines:

$time = time();
$datetime = new DateTime();
$datetime->setTimestamp($time);
$timezone = new DateTimeZone('UTC');
$datetime->setTimezone($timezone);
$format = $datetime->format('e');
var_dump($format);

gives “2015-05-03 14:49:49 UTC”.

Why is there a difference in the formatting output between these two ways of using the datetime class? One gives “UTC”, the other gives the offset for UTC instead. I want the string UTC given, not the offset, but I’d like to not use multiple line construction above.

In my opinion suppressing errors using @ is never a good thing.

2 Likes

Thanks for pointing that out. I agree with you. I strive to never use @ and so actually forgot about its usual meaning and thought it was a way to get datetime to take a unix timestamps after reading some (bad) tutorials elsewhere.

Is there a way to have the datetime constructor take a unix timestamp without resorting to $datetime->setTimestamp()?

This looks like a symptom of not instantiating your DateTime correctly. To set the time at construction, the DateTime class expects a string rather than a Unix timestamp (you should have been getting an exception when trying to provide the timestamp in the constructor).

If you were to var_dump your $datetime in both circumstances, you would see that there each has a different value for the timezone_type property, which is what determines the formatting of the output:

http://stackoverflow.com/questions/17694894/different-timezone-types-on-datetime-object

My guess is that the timezone_type property isn’t being set consistently because you are providing an invalid constructor option. If you want to provide the timestamp at construction, format the date to a date string first:

// date() defaults to current timestamp
$time = date("c");
$datetime = new DateTime($time, new DateTimeZone('UTC'));

Note that using date('c') will create the date using the default timezone for your server. If you want it represented as UTC, maybe format the date yourself:

$time = date("Y-m-d g:i:s \U\T\C");

I am not sure why there is the difference, but both are showing the same information, just in a different way.

You can do what you want to do like this:

$datetime = new DateTime("@$timestamp"); $datetime->setTimezone(new DateTimeZone('UTC')); $format = $datetime->format('Y-m-d H:i:s T');
That will return: 2015-05-04 19:55:11 UTC

You can pass a timestamp as well the way he did it by adding a @ infront of it. Though since UNIX timestamps are supposed to be UTC/GMT by default it ignore the timezone you pass to the constructor.

Note. Beware that if you use a timestamp created in PHP or MySQL (or your DB of choice) it is possible the timestamp is created in a different timezone!

Hmmm…Strange that using the error suppression operator would change the execution of the program:

<?php
// PHP 5.5.9-1ubuntu4.9
$time = strtotime("December 25, 2000");

// Without error suppression
$datetime = new DateTime("$time"); // Uncaught exception
var_dump($datetime);// NULL

// With error suppression
$datetime = new DateTime("@$time");
var_dump($datetime);// object(DateTime...)

Another reason to not use error suppression?

only that it’s not the error suppression operator, but a valid input format as specified in the manual: http://php.net/manual/en/datetime.formats.compound.php

1 Like

IMO The DateInterval, DateTime objects in php are “really bad”. Just having the constructor of a complex type receive a string, that need to be parsed and can be locale dependent, in order to be created, is a bad idea. It doesn’t have a clear contract and is not efficient.
Besides, different regions have different ways to input dates so a programmer needs to have caution and write dates in a standard way, and be twice as careful when receiving it from the user. If not, what exactly does this stringified date “05-02-2012” means. Is it month 2 or month 5 ?

I know it would be a huge BC bug the php DateTime object model would benefit if it allowed a constructor (or even a static one, and not a method) with (year = 0000, month = 1, day = 1, hour = 0, minute = 0, second = 0, miliseconds = 0, TimeZone = 0). A similar situation could be applied to the DateInterval.

These are just thoughts, but hundreds of questions are placed in the forums related to the Date manipulations in php, which isn’t a good sign.

The http://php.net/manual/en/datetime.createfromformat.php fuction is better for this purpose as it forces you to specify the format. I wish this was the constructor instead.

Still, prefer to have a contract based constructor (y, m, d, h, m, s) than a parse string as a “default”. This applied to any “native” data. Integers, Floats, Dates, …
IMO, Parsing dates should only be used to handle external interfaces, anywhere inside MY application (hopefully reminds you a quote from a particular person :smile: ) should be using “native” datetime formats and no string manipulation. And if I’m using serializes and other 3rd party software I don’t even use the DateTime(“format”), just use the DateTime(dateparts)

I tend to have parsed methods explicit saying “Parse” because they are usually time consuming, more complex, prone to output errors due to invalid data. Having that “complex” logic in a constructor isn’t a good sign for me.
Also, coming from C# I tend to have a “void Parse(data)” and an a “bool TryParse(data, output)” in order to gracefully return false in case of an error., which is not possible with a constructor.

I had the same kinda problem, thank you for solving it.

In my case (and to recap), the the behavior was explained by @TheRedDevil. The datetime constructor is ignoring the timezone since a timestamp was being offered, and the @ sign is not suppressing errors here but instead used to allow a timestamp to be placed in the constructor directly.

I couldn’t find any mention of the timezone being ignored in the docs when using a timestamp except "The “Unix Timestamp” format sets the timezone to UTC. " ( http://php.net/manual/en/datetime.formats.compound.php ) which doesn’t exactly say it is ignored but just automatically set. But given the exhibited behavior, assuming it is ignored, at least in the constructor, seems correct.

Interestingly, when using the ‘e’ formatting option with a timestamp the offset (+00:00) is given, while using the ‘T’ formatting option gives GMT (GMT+0000)! This is strange given that the docs says it converts it to UTC. UTC and GMT are (practically speaking) the same but they have different timezone identifiers within php.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.