I have a DateTime from my MySQL Database which I convert to a Unix TimeStamp with Twig:
In DB: 2016-06-22 00:00:00
In Twig as TimeStamp: dbEntry.start|date('U') ==> 1466546400
In Twig as Date dbEntry.start|date('Y-m-d H:i) ==> 2016-06-22 00:00
Doublechecking that timestamp here http://www.gaijin.at/olsutc.php says that the timestamp is local time.
I send this timestamp via AjaxCall to my Backend, where this happens:
$dateDB = \DateTime::createFromFormat('U',$date)->format('Y-m-d H:i');
dump($dateDB);
($date being 1466546400)
Output
2016-06-21 22:00
In all my php.ini files I set the timezone to Europe/Berlin, but the resulting timestamp is clearly UTC. Even setting the timezone manually with
$dateDB = \DateTime::createFromFormat('U',$date,new \DateTimeZone('Europe/Berlin'))->format('Y-m-d H:i');
dump($dateDB);
leads to 2016-06-21 22:00 as well.
How does this happen, and where can I start to look for it, besides the php.ini files?
Side Note
I see that this has been addresses here PHP timestamps & timezone configuration as well, I could just manually add 7200 seconds, but would that still be correct in Winter due to DailightSavingTime?
The issue comes from the fact that createFromFormat() is ignoring its third argument (time zone) by design:
Note: The timezone parameter and the current timezone are ignored
when the time parameter either contains a UNIX timestamp (e.g.
946684800) or specifies a timezone (e.g. 2010-01-28T15:00:00+02:00).
Here's a cleaner test case:
$dt = new DateTime('2016-06-22 00:00:00', new DateTimeZone('Europe/Berlin'));
$dt2 = DateTime::createFromFormat('U', $dt->getTimestamp(), new \DateTimeZone('Europe/Berlin'));
var_dump($dt->format('c'), $dt2->format('c'));
string(25) "2016-06-22T00:00:00+02:00"
string(25) "2016-06-21T22:00:00+00:00"
Here, you'd need to change time zone afterwards (default time zone is only used when no time zone information exists):
$dt2->setTimeZone(new DateTimeZone('Europe/Berlin'));
Related
Let's suppose we have this date 1972-12-31 23:59:59, if we get the TimeStamp for it from DateTimeImmutable object we will get this:
$formattedDate = '1972-12-31 23:59:59';
$ts = (new DateTimeImmutable($formatedDate))->getTimestamp(); // <- 94690799
The problem that if you try to revers the conversion, so it becomes from timestamp into formatted date:
$ts = 94690799;
$formattedDate =
(new DateTimeImmutable(sprintf('#%s', $ts)))->format('Y-m-d H:i:s'); // <- 1972-12-31 22:59:59
There is an hour gone in the second way.
So the million dolor question would be, which one of those timing is corresponding to the correct time?
Is this a bug? Or am I messing something in here?
When you create a DateTime object from a formatted string, it is created in your server's default timezone (see date_default_timezone_get). But Unix timestamps don't have a timezone - they're always in UTC. So if you write:
(new DateTimeImmutable('1972-12-31 23:59:59'))->getTimestamp();
then what you're really asking PHP is "How many seconds after 1970 in UTC was it, when it was that date + time in my current timezone". In your case, the server looks like it is running one hour ahead of UTC, hence the difference.
Crucially, when you do the inverse and create a DateTime object from a timestamp, the object's timezone is always set to UTC. There's a brief note about it on this manual page.
If you set the default timezone to UTC before running the code, you'll see that the output matches. I've added an example here: https://3v4l.org/2Rfp3
The output of the following is two identiacal lines of UTC
date_default_timezone_set('Europe/London');
$datetime = new DateTime();
echo "\n" . $datetime->format('U');
$datetime->setTimezone(new DateTimeZone('Pacific/Chatham'));
echo "\n" . $datetime->format('U');
They should obviously be different, and neither should be UTC!
As well as setting the timezone in the code, its set in php.ini as
date.timezone = 'Europe/London'
PHP version is PHP 5.6.30, and all appears to be working when you use the web-browser, running on OS X.
They should obviously be different, and neither should be UTC!
Completely wrong. Twice.
The U format specifier of DateTime::format() prints the date as a timestamp. As the documentation explains in the "Description" column, its meaning is "Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)"
You don't change the date or time stored in the $datetime object between the two calls to DateTime::format(), it is still the same date. The number of second passes since the Unix Epoch didn't change. There is no reason for the second call to DateTime::format() to print a different value.
Changing the timezone doesn't affect the date. It affects only how the date is represented using date & time components (years, months, days, hours, minutes, seconds, timezone).
A timestamp is an absolute representation of a date. It represents the number of seconds that passed since a fixed moment in the past. It doesn't depend on timezones.
Change the formatting to:
echo($datetime->format('U: Y-m-d H:i:s e')."\n");
and see for yourself:
1504791287: 2017-09-07 14:34:47 Europe/London
1504791287: 2017-09-08 02:19:47 Pacific/Chatham
How can I convert the time zone of a date string in php without changing the default time zone. I want to convert it locally to display only. The php time zone settting should not be modified.
EDIT:
My source time is a UTC string, I want to convert it to a different format, retaining the time zone as UTC, but php is converting it to local timezone.
The code I used was:
date('Y-m-d H:i::s',strtotime($time_str));
How do I retain timezone?
$src_tz = new DateTimeZone('America/Chicago');
$dest_tz = new DateTimeZone('America/New_York');
$dt = new DateTime("2000-01-01 12:00:00", $src_tz);
$dt->setTimeZone($dest_tz);
echo $dt->format('Y-m-d H:i:s');
Note that if the source time is UTC, you can change the one line to this:
$dt = new DateTime("2000-01-01 12:00:00 UTC");
Edit: Looks like you want to go to UTC. In that case, just use "UTC" as the parameter to the $dest_tz constructor, and use the original block of code. (And of course, you can omit the $src_tz parameter if it is the same as the default time zone.)
The PHP manual for DateTime states
The $timezone parameter and the
current timezone are ignored when the
$time parameter either is a UNIX
timestamp (e.g. #946684800) or
specifies a timezone (e.g.
2010-01-28T15:00:00+02:00).
Which means that when I do
$time1 = new DateTime('#'.time());
$time2 = new DateTime();
I will have two different results since my default timezone is not UTC. How do you handle this? I don't want to change my server timezone - yet I need timestamps to be output in my timezone.
Use:
$time1 = new DateTime(NULL, "<your timezone here>");
Or you can specify your preferred format in the first field and leave the timezone NULL.
How would I take a stored date, like 2011-01-30 18:23:49, and adjust it to any chosen timezone? Is there a simple way such as simply defining the time zone by abbreviation or adding/subtracting x amount of hours?
Basically I want users to be able to choose their time zone and this default date be adjusted to fit theirs.
Have the user choose their time zone
Use that zone name or offset with date_default_timezone_set to set the default time zone used in date functions throughout the rest of script execution.
Use date('Z') to get that time zone's offset from GMT in seconds
Convert your stored date to a timestamp with strtotime -- UNIX timestamps are always GMT, so you now have the time in GMT.
Add the offset from step 3 to convert that time to the user's time zone.
Use date again to format the timestamp as a string in the desired display format.
Example:
$user_timezone = 'America/Los_Angeles';
$stored_time = '2011-01-30 18:23:49';
date_default_timezone_set($user_timezone);
$timestamp = strtotime($stored_time);
$local_timestamp = $timestamp + date('Z');
$local_date = date('Y-m-d H:i:s', $local_timestamp);
echo $local_date;
Here comes my solution. I tested it with America/Los_Angeles as the servers timezone, and my timezone as the users. I assume that the time is stored using the servers timezone.
<?php
// My (user) timezone
$user_timezone = 'Europe/Berlin';
// Server timezone
$stored_timezone = 'America/Los_Angeles';
// Date/Time stored in your DB, using timezone of the server (yours, that is)
$stored_datetime = '2011-01-29 22:40:00'; // this is the current time in L.A.
// Setting default to servers timezone if not done before
date_default_timezone_set($stored_timezone);
// converting to unix timestamp
$stored_timestamp = strtotime($stored_datetime);
// setting default to users timezone
date_default_timezone_set($user_timezone);
// converting to timestamp
$user_datetime = date('Y-m-d H:i:s', $stored_timestamp);
// setting default back to servers timezone
date_default_timezone_set($stored_timezone);
echo $user_datetime; // output is my current time