Php: Setting a Timezone by Utc Offset

php: setting a timezone by UTC offset

how about this...

$original = new DateTime("now", new DateTimeZone('UTC'));
$timezoneName = timezone_name_from_abbr("", 3*3600, false);
$modified = $original->setTimezone(new DateTimezone($timezoneName));

Convert UTC offset to timezone or date

It can be done quite simply, by turning the offset into seconds and passing it to timezone_name_from_abbr:

<?php
$offset = '-7:00';

// Calculate seconds from offset
list($hours, $minutes) = explode(':', $offset);
$seconds = $hours * 60 * 60 + $minutes * 60;
// Get timezone name from seconds
$tz = timezone_name_from_abbr('', $seconds, 1);
// Workaround for bug #44780
if($tz === false) $tz = timezone_name_from_abbr('', $seconds, 0);
// Set timezone
date_default_timezone_set($tz);

echo $tz . ': ' . date('r');

Demo

The third parameter of timezone_name_from_abbr controls whether to adjust for daylight saving time or not.

Bug #44780:

timezone_name_from_abbr() will return false on some time zone
offsets. In particular - Hawaii, which has a -10 from GMT offset, -36000
seconds.

References:

  • timezone_name_from_abbr
  • date_default_timezone_set
  • date

Setting timezone offset in PHP

I got this sorted in the end. This bit of info from the PHP manual tipped me off:

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).

So my eventual solution was to extend the DateTime class and override the __construct() method. My modified class is as follows:

<?php

class timezone extends DateTime {

// Override our __construct method
function __construct($date = "now", $offset = null) {
// If we've not specified an offset
if(is_null($offset)) {
// Assume UTC
$offsetFormat = "+00:00";
$offset = 0;
// Otherwise..
} else {
// Create a new DateTime, and get the difference between that, and another new DateTime that has $offset minutes subtracted from it. Format the results as something like +11:00 or -03:00
$offsetFormat = (new DateTime($date, new DateTimeZone("UTC")))->diff((new DateTime($date, new DateTimeZone("UTC")))->sub(DateInterval::createFromDateString($offset . " minutes")))->format("%R%H:%I");
}

// Next, we get the offset from our $date. If this offset (divided by 60, as we're working in minutes, not in seconds) does NOT equal our offset
if((new DateTime($date))->getOffset() / 60 !== $offset) {
// Overwrite $date, and set it to a new DateTime with $offset minutes subtracted from it
$date = (new DateTime($date, new DateTimeZone("UTC")))->sub(DateInterval::createFromDateString($offset . " minutes"));
// If $date's offset equals $offset
} else {
// An offset has already been applied (we know this because all our pre-offset dates will be in UTC), and we don't need to do it again
$date = (new DateTime($date));
}

// Finally, hand this back to the original DateTime class. This format works out to be something like: 2016-03-10T23:16:37+11:00
parent::__construct($date->format("Y-m-d\TH:i:s") . $offsetFormat, null);
}

}

echo (new timezone())->format("c") . "<br />"; // Will output something like 2016-03-10T12:17:44+00:00
echo (new timezone(null, -660))->format("c") . "<br />"; // Will output something like 2016-03-10T23:17:44+11:00
echo (new timezone("midnight", -660))->format("c") . "<br />"; // Will output 2016-03-10T11:00:00+11:00
echo (new timezone("midnight"))->format("c") . "<br />"; // Will output 2016-03-10T00:00:00+00:00
echo (new timezone("2016-01-01T00:00+00:00", -660))->format("c") . "<br />"; // Will output 2016-01-01T11:00:00+11:00
echo (new timezone("2016-01-01T00:00+11:00", -660))->format("c") . "<br />"; // Will output 2016-01-01T11:00:00+11:00. Note that the offset isn't applied twice!

?>

EDIT: This is now a library that I've open-sourced. Check it out over on GitHub

Set the User's timezone when the only info is a UTC offset number.

No. Time zones don't work that way. A time zone offset only applies to a specific point in time. Many time zones share the same offset at various times. Some are indistinguishable from others with an offset alone.

For example, -7 could be MST, or it could be PDT. It might be used with "America/Phoenix", which is on MST year-round. But it might belong to "America/Denver" which would use MST (-7) in the winter and MDT (-6) in the summer. Or it might belong to "America/Los_Angeles", using PST (-8) on the winter and PDT (-7) in the summer.

See also, the timezone tag wiki

Regarding Facebook, it's only giving you the time zone offset as of the user's last login. It is not necessarily even the correct offset for the current moment in time.

UTC Offset in PHP

  date('Z');

returns the UTC offset in seconds.

PHP - set default timezone offset for areas without timezone name (sea locations)

The time zones in PHP originate from the IANA tz database.

In particular, zones like Etc/GMT+10 originate from the etcetera file in the tz data, which says (emphasis mine):

... These days, the
tz files cover almost all the inhabited world, and the only practical
need now for the entries that are not on UTC are for ships at sea

that cannot use POSIX TZ settings.

Thus, you can indeed and should use them for the purpose you described.

Keep in mind that they only exist for whole-hour offsets from Etc/GMT-14 to Etc/GMT+12, and that the sign in the zone name is opposite from standard conventions. In other words Etc/GMT+10 is actually UTC-10.

One other note. My understanding is that it is common for ships at sea to use a land-based time zone when they are in the territorial waters near such lands, including any daylight saving time adjustment in effect. For example, a ship traveling within the territorial waters of the USA along the Pacific coast should change their clocks to use PST (UTC-8) in the winter and PDT (UTC-7) in the summer. This is modeled by America/Los_Angeles, whereas a pure longitudinal calculation would use UTC-8 year-round (Etc/GMT+8).

All of this is flexible, as the captain of the ship can basically decide the shipboard time at their discretion. See Wikipedia's article on nautical time for more specifics.

You might also want to read here about methods to use GPS coordinates to resolve an IANA time zone. Those that use the Time Zone Boundary Builder project as a data source (such as the Geo-Timezone PHP library) benefit from both nautical time and territorial waters being taken into consideration.



Related Topics



Leave a reply



Submit