I've got a database full of users that each have a timezone
column stored as a string (e.g. America/New_York
). (And I know that storing them as offsets in the database makes way more sense, but cannot be done for this project) I've got a form where the user is able to change their timezone. Here was my first approach :
I have this populating a drop down (value
=> display
):
protected $timezones = [
'+00:00' => '(UTC +00:00) Western European Time',
'+01:00' => '(UTC +01:00) Central European Time',
'+02:00' => '(UTC +02:00) Eastern European Time',
'+03:00' => '(UTC +03:00) Further-Eastern European Time',
'+04:00' => '(UTC +04:00) Gulf Standard Time',
'+05:00' => '(UTC +05:00) Pakistan Standard Time',
'+05:30' => '(UTC +05:30) Indian Standard Time',
'+05:45' => '(UTC +05:45) Nepal Time',
'+06:00' => '(UTC +06:00) British Indian Ocean Time',
'+07:00' => '(UTC +07:00) Thailand Standard Time',
'+08:00' => '(UTC +08:00) Australian Western Standard Time',
'+09:00' => '(UTC +09:00) Japan Standard Time',
'+10:00' => '(UTC +10:00) Australian Eastern Standard Time',
'+10:30' => '(UTC +10:30) Australian Central Daylight Savings Time',
'+11:00' => '(UTC +11:00) Australian Eastern Daylight Savings Time',
'+12:00' => '(UTC +12:00) New Zealand Standard Time',
'+13:00' => '(UTC +13:00) New Zealand Daylight Time',
'-01:00' => '(UTC -01:00) Eastern Greenland Time',
'-02:00' => '(UTC -02:00) Brasilia Summer Time',
'-03:00' => '(UTC -03:00) Atlantic Daylight Time',
'-04:00' => '(UTC -04:00) Atlantic Standard Time',
'-05:00' => '(UTC -05:00) Central Daylight Time',
'-06:00' => '(UTC -06:00) Central Standard Time',
'-07:00' => '(UTC -07:00) Pacific Daylight Time',
'-08:00' => '(UTC -08:00) Pacific Standard Time',
'-09:00' => '(UTC -09:00) Alaska Standard Time',
'-10:00' => '(UTC -10:00) Hawaii-Aleutian Standard Time',
'-11:00' => '(UTC -11:00) Niue Time',
];
This function to convert timezone string to offset :
/**
* convert timezone string to offset
* e.g. "America/New_York" to "-04:00"
*
* @param string $timezone time zone represented as a string
*
* @return mixed string or null
*/
protected function convertStringToOffset($timezone)
{
$time = new \DateTime('now', new DateTimeZone($timezone));
if ($time) {
return $time->format('P');
}
}
And this function to convert an offset to a string :
/**
* convert timezone offset to string
* e.g. "-04:00" to "America/New_York"
*
* @param string $offset time zone represented as a numerical offset
*
* @return string time zone represented as a string
*/
protected function convertOffsetToString($offset)
{
// 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);
}
return $tz;
}
So on page load, I would pull the timezone from the database and convert it to it's offset. For example
America/New_York
would be converted to-04:00
and the(UTC -04:00) Atlantic Standard Time
would be selected.Now the user would select a different timezone and submit the form. I would then convert the offset into a string and then store that into the database.
I ran into a problem :
-
$this->convertOffsetToString('+03:00');
returnsEurope/Helsinki
-
$this->convertOffsetToString('+04:00');
returnsEurope/Moscow
but!
-
$this->convertStringToOffset('Europe/Moscow');
returns+03:00
-
$this->convertStringToOffset('Europe/Helsinki');
returns+03:00
So if a user came to the form and had the timezone Europe/Moscow
in the database, we would convert the string to it's offset getting +03:00
and the '(UTC +03:00) Further-Eastern European Time'
would be selected.
Problem : two different offsets (e.g. +03:00
and +04:00
) will be converted into two different string time zones. Those two different string timezones would be converted into the same offset! (e.g. +03:00
). Can anyone come up with a safe scale-able solution to tackle this problem?