Trying to understand Timestamps and Timezones in PHP - php

I have a PHP application that needs to support timezones. Now I am storing date and time values in the database as integers. So here is what I do.
// now create the DateTime object for this time and user time zone
$dtime = new DateTime($date_time, new DateTimeZone($time_zone));
$timestamp = $dtime->format('U');
What I don't understand is even if the person is in New Zealand (Pacific/Auckland) and the application stores this date: 24-12-2010 00:00:00 using the above code the value comes back as: 1293102000
Then using the exact same date/time and setting the time zone to London (Europe/London) I get this timestamp:1293148800
Why are the timestamps different? I thought the timestamp would be the same number of seconds as its the same date from the Unix Epoch?
If they are different that means when someone is searching the database for all records between 24-12-2010 00:00:00 and 24-12-2010 23:59:59 I need to use the users timezone for the creation of the timestamps and I must use the timezone to firstly create the timestamps.
Help!

Because timezone for New Zealand is +1300 UTC, where London is zero UTC, 13 x 3600seconds = 1293148800-1293102000
Since you already store as integer, you should always use zero UTC skip timezone when you construct $dtime
For testing
# date_create is procedural style
$obj = date_create('24-12-2010 00:00:00', new DateTimeZone('europe/london'));
echo $obj->format('U');
$obj = date_create('24-12-2010 00:00:00');
echo $obj->format('U');

Related

Converting a Time from a database to BST with PHP

So I've trying all sorts of combinations to get a date from my database (using Wordpress) to display in British Summer Time and I cannot get anything to work.
Is there any simple solution that can take the date string and make sure that in Summer Time in the UK it's an hour on from UTC time?
$classJson = $class->info;
$classJsonAsArray = json_decode($classJson, TRUE);
$classStartDate = strtotime($class->periodStart);
$classStartTime = date('H:i',$classStartDate);
So currently $class->periodStart returns: 2022-04-06 08:30:00
The time of that event should be 9.30am
All I need it to do is display the correct time, as at the moment, on the front end it displays as 8.30am.
DateTime handles timezones quite well.
$dateStringInUtc = '2022-04-06 08:30:00';
$date = new DateTime($dateStringInUtc, new DateTimeZone('UTC'));
$date->setTimezone(new DateTimeZone('Europe/London'));
echo $date->format('Y-m-d H:i:s'); // will output 2022-04-06 09:30:00
Working with DateTime and timezones like in the accepted answer is the better way.
But it also works with strtotime if the timezone is appended to the date string. Date then returns the local time for a timestamp.
$utcDate = '2022-04-06 08:30:00';
echo date('Y-m-d H:i:s',strtotime($utcDate.' UTC'));

php - Different behaviour of `DateTimeImmutable` for the same datetime value in different format

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

PHP date timestamp timezone not converted properly

So I have this code:
$timestamp = 1414708099;
echo $timestamp;
$date = date_make_date($timestamp, 'UTC', 'datestamp');
date_timezone_set($date, timezone_open('America/New_York'));
$timestamp = $date->format('U');
echo '<br>';
echo $timestamp;
which is supposed to convert the timezone of the initial timestamp from UTC to new york.
but then this ends up printing
1414708099<br>1414708099
hence the timezone didnt change...
what did I do wrong?
btw it also uses Drupal 6 date_api.module: http://drupalcontrib.org/api/drupal/contributions!date!date_api.module/function/date_make_date/6
As per comments
A timestamp is always UTC. You can't apply a time zone to a timestamp - consider its timezone as 0. Whatever you do, it stays 0. You asked for a date formatted with U - manual states this:
U: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
You can't get seconds from Unix Epoch for New York. That number is the same for any location in the world.
Now, had you formatted that date using, say, $date->format('Y-m-d H:i:s') then you would get correctly formatted time with the timezone offset for New York.
Long story short - there is no problem whatsoever here. It all works as intended.

Shifting unix time stamp according to timezone

I know this question has been answered many many times. I came in to a solution to solve this and its goes like this. I store all time stamps for each post in UTC on the server. Now i need to display the time stamp for a given timezone. I do this:
$tz : requested timezone
$ts : timstamp on db
$newts : new timestamp
$datetime = date('m/d/Y g:i a', $ts);
$dt = new DateTime($datetime, new DateTimeZone('UTC'));
date_default_timezone_set(trim($tz));
$newts = $dt->format('U');
date_default_timezone_set('UTC');
However the resulting time stamp is 60~ seconds higher than what is should be.
What am i doing wrong?
You're close, all you need to do is create the original DateTime object based on the timestamp/server timezone then set the new timezone and print the result, like so:
$datetime = new DateTime('#'.$ts, new DateTimeZone('UTC'));
$datetime->setTimezone(new DateTimeZone($tz));
print $datetime->format('m/d/Y g:i a');
The unix timestamp will be the same regardless of the timezone (it is TZ agnostic). The offset occurs when displaying it for different time zones. This is you can test this by printing the unix timestamp for each different timezone (they will be the same).
The U format gives you the number of "seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)". That number does not depend on where on earth you are. So even if it might be 14:59 at your place while it's 10:24 at my place, the number of seconds since January 1 1970 00:00:00 GMT is the same at both our places. A "time stamp for a given timezone" does not make sense.

PHP timezone function not working

I'm creating a forum, which also stores the time a post was sent, and I need to convert that into the user's timezone.
Now, the MySQL DataBase stores the time with UTC_TIMESTAMP() (in a column with the DATETIME type), and I created a little function from the code on http://www.ultramegatech.com/blog/2009/04/working-with-time-zones-in-php/ to convert the time to the user's timezone. This is the function:
function convertTZ($timestamp, $tz='UTC', $format='d-m-Y H:i:s') {
// timestamp to convert
$timestamp = strtotime($timestamp);
// the time formatting to use
$format = $format;
// the time zone provided
$tz = $tz;
// create the DateTimeZone object for later
$dtzone = new DateTimeZone($tz);
// first convert the timestamp into an RFC 2822 formatted date
$time = date('r', $timestamp);
// now create the DateTime object for this time
$dtime = new DateTime($time);
// convert this to the user's timezone using the DateTimeZone object
$dtime->setTimeZone($dtzone);
// print the time using your preferred format
$time = $dtime->format($format);
return $time;
}
And I made a test page at http://assets.momo40k.ch/timezones.php.
Now, when I insert a post into the DataBase at, say, 11:50 in my timezone (which is Europe/Rome), it inserts 09:50 in UTC, wich is correct, according to some online timezone converters.
But when I try to convert it back to Europe/Rome with the convertTZ() function, it returns 09:50, as if Europe/Rome is UTC. If I try converting it to a GMT+2:00 timezone, it returns 10:50. Can anyone fugure out why this is?
P.S: I'm not using the CONVERT_TZ() SQL function because my server does not support named timezones, so this function is my workaround.
Make sure your stored timestamps are UTC:
$date = new DateTime($timestamp, new DateTimeZone("UTC"));
$date->format(DATE_W3C); // does it gives the expected result ?
BTW your function can be simplified to this:
function convertTZ($timestamp, $tz='UTC', $format='d-m-Y H:i:s') {
$dtime = new DateTime($timestamp, new DateTimeZone("UTC"))
$dtime->setTimezone(new DateTimeZone("UTC"));
return $dtime->format($format);
}
MySQL always stores TIMESTAMP fields in UTC internally (that's the definition of a unix timestamp, in fact). So when you SELECT or UPDATE/INSERT/REPLACE, the time you get or set is always in the MySQL server's local time zone.
So a common mistake is to store UTC_TIMESTAMP(), which MySQL interprets as a local time and so the current time gets double-converted to UTC when it stores it internally in the field as a unix TIMESTAMP.

Categories