I got this line of code:
echo (new DateTimeZone('UTC'))->getOffset(new DateTime('now', new DateTimeZone('America/New_York')));
It returns zero. But I expected it to return the difference between UTC and America/New_York time zones.
I then provided the same time zone twice:
echo (new DateTimeZone('America/New_York'))->getOffset(new DateTime('now', new DateTimeZone('America/New_York')));
I expected it to return zero because the time zones are the same. But it now returns -18000 (That's the offset between America/New_York and UTC).
In the documentation it says that getOffset() always returns the offset to GMT (=UTC). But then why is getOffset not static? And if it is always the offset relative to GMT why does the time zone in the first constructor play a role?
I know there's another getOffset method in the DateTime class which is easier to use. But i want to understand how the getOffset method in the DateTimeZone class works.
The offset of a timezone is how many hours it differs from UTC. The offset of a timezone may change throughout the year depending on when DST goes into and out of effect. So you cannot get the offset of a timezone just like that, since it's not a constant value. You can only interrogate a timezone what its offset from UTC is at a given time. That's what you pass the DateTime object to getOffset for: to ask the timezone what its offset value is for the given time. E.g.:
echo (new DateTimeZone('America/New_York'))->getOffset(new DateTime), PHP_EOL;
echo (new DateTimeZone('America/New_York'))->getOffset(new DateTime('+6 months'));
-18000
-14400
If you want to get the offset difference between two arbitrary timezones, you get their respective UTC offsets and subtract them.
I came here looking for a way to get the offset between PHP's current default timezone and UTC. I went down the rabbit hole with DateTimeZone::getOffset, but it turns out there's a much easier way:
$offset = date('O');
// Returns a string like '-0400'
$offset = date('P');
// Returns a string like '-04:00'
$offset = date('Z');
// Returns the offset in seconds, e.g. '-14400'
To be clear, this gets whatever the timezone offset is right now, but I imagine that's what is wanted most of the time.
You can switch PHP's current timezone with date_default_timezone_set().
See https://www.php.net/manual/en/datetime.format.php
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
My online application gets users timezone offset in + or - value in minutes. I want to set this value in server.
MySQL / MariaDB accepts timezone values and works perfectly
SET time_zone = "+0:15";
But php only accepts timezone string like this
date_default_timezone_set("Asia/Karachi"); // Works Perfectly
And does not set time in offset value
date_default_timezone_set("+0:15"); // Error
Is there any way to set php time with offset value?
After reading the documentation for the date_default_timezone_set() php function, this seems to be a common issue.
I'm sure there may be alternatives if you choose to use other date functions in php, however, to be able to set the timezone by an offset, you would require a helper function to do this.
I've copied and modified a helper function posted on the php doc page here
function setTimezoneByOffset($offset)
{
$testTimestamp = time();
date_default_timezone_set('UTC');
$testLocaltime = localtime($testTimestamp,true);
$testHour = $testLocaltime['tm_hour'];
$abbrarray = timezone_abbreviations_list();
foreach ($abbrarray as $abbr)
{
//$abbr."<br>";
foreach ($abbr as $city)
{
date_default_timezone_set($city['timezone_id']);
$testLocaltime = localtime($testTimestamp,true);
$hour = $testLocaltime['tm_hour'];
$testOffset = $hour - $testHour;
if($testOffset == $offset)
{
return $city['timezone_id'];
}
}
}
return false;
}
Where the parameter $offset is a string representation of the offset (ie. '+0:15'), which returns the timezone id of the timezone which matches that of your input.
My online application gets users timezone offset in + or - value in minutes.
This is problematic, because a time zone offset is not the same thing as a time zone. Consider that one cannot take the current offset and assume it is the correct offset to apply for any given date and time. Many time zones use more than one offset depending on time of year, and many time zones have had changes to their standard time offsets at different points in history. For more on this, see "Time Zone != Offset" in the timezone tag wiki.
As an example, you might be using a JavaScript function like new Date().getTimezoneOffset(). However, this returns the offset for the Date object returned by new Date() - which is the current date. For me, in the US Pacific time zone, it will return 480 (UTC-8) when run in the winter during standard time, but 420 (UTC-7) when run in the summer during daylight saving time.
Instead, have your front-end call Intl.DateTimeFormat().resolvedOptions().timeZone in JavaScript to return the time zone identifier, which for me returns "America/Los_Angeles". You can pass that to your back-end and use it with PHP.
As a side note, there are no time zones in the world that use or have ever used UTC+0:15. The closest to that would have been UTC+0:20 used in the Netherlands from 1 May 1909 to 16 May 1940. This is already captured in the history of "Europe/Amsterdam".
I can't figure out how timezones work. Why this code produces zero as ouput? Shouldn't it return 10800 instead of 0?
$myZone = new DateTimeZone('+0300');
$utcZone = new DateTimeZone('+0000');
$dateA = new DateTime('now', $myZone);
var_dump($utcZone->getOffset($dateA)); // 0
$dateA->setTimezone($utcZone);
var_dump($utcZone->getOffset($dateA)); // 0
$dateA->modify('+ 3600 seconds');
var_dump($utcZone->getOffset($dateA)); // 0
It seems like $utcZone->getOffset(...) does not care about it's argument timezone and time diff at all. Where is the logic?
<?php
$myZone = new DateTimeZone('+0300');
$utcZone = new DateTimeZone('+0000');
$dateA = new DateTime('now', $myZone);
$timeOffset = $myZone->getOffset($dateA);
var_dump($timeOffset);
This one will return 10800 as you said. It was the other way around in getOffset.
output is : int(10800)
getOffset returns the offset used by the timezone at a specific moment.
Timezones can have more than one offset during history - the most common case is Daylight Saving Time, when the offset changes for a specified period. So depending on the time of the year, a certain timezone can have a different offset.
The datetime parameter defines the instant you want to check, and getOffset will check in the timezone's history and return the one used at that specific datetime - no matter what the datetime's timezone is. In the documentation you can find an example of that: http://php.net/manual/en/datetimezone.getoffset.php#refsect1-datetimezone.getoffset-examples
That said, when you use fixed offset values such as "+0000", this means that the DateTimeZone object will always have that offset, all the time - it never changes. That's why when you call $utcZone->getOffset, it always returns zero, no matter what datetime parameter you pass.
If you want the date's offset, call the getOffset method on the DateTime object.
My variable $createdDate has a value '2014-06-23T01:44:22Z' something like this in it. It's fetched from database.
And when I convert it into standard format using strtotime(), the time returned is always 2 hours different(ahead) from the orginal variable's time.
$time1 = strtotime($createdDate);
$cretime_formated=date("Y-m-d h:i:s",$time1);
Output of $cretime_formated is 2014-06-23 03:44:22 instead of 2014-06-23 01:44:22. Why is there a difference of 2 hours in the time??? Is there anything wrong with my conversion process??
Given that the date is in Zulu timezone (and assuming all such timestamps are in that same timezone), you would need gmdate() to format it:
$cretime_formated = gmdate("Y-m-d h:i:s",$time1);
I think you have the time difference .You need to set it in UTC
date_default_timezone_set('UTC');
See Complete Refrence
List of Supported Timezones
Given a unix timestamp and timezone offset relative to UTC (e.g. -5), is it possible to calculate if DST is active?
I can do something like:
<?php
echo 'DST enabled? ' . date('I', 1345731453) ."<br>";
?>
But I cannot see how to pass in an offset or a TimeZone.
Im guessing also that there is a difference between the timezone and the offset, given that specific countries support DST?
Appreciate any thoughts.
Correct, you need to start with date and tz to determine offset.
in 5.3+ you can get transitions for start/end period, so you can just use your timestamp for both, something like this:
$inputTime = $your_unix_timestamp;
$inputTZ = new DateTimeZone('Europe/London');
$transitions = $inputTZ->getTransitions($inputTime,$inputTime);
$offset = $transitions[0]['offset'];
$offset is the DST offset at the time in question
Get the timezone with:
$old_zone = ini_get('date.timezone');
Change it to the one you want:
ini_set('date.timezone', 'Europe/Brussels');
Revert back:
ini_set('date.timezone', $old_zone);
The PHP timestamp is always UTC. Depending on your timezone setting it determine what time to show.