One*_*anh 1 php time timezone datetime zone
我有一个充满用户的数据库,每个用户都有一个timezone存储为字符串的列(例如America/New_York).(而且我知道将它们作为偏移存储在数据库中会更有意义,但不能为此项目完成)我有一个表单,用户可以更改其时区.这是我的第一个方法:
我有这个填充下拉(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',
];
Run Code Online (Sandbox Code Playgroud)
此函数将时区字符串转换为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');
}
}
Run Code Online (Sandbox Code Playgroud)
这个函数将偏移量转换为字符串:
/**
* 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;
}
Run Code Online (Sandbox Code Playgroud)
所以在页面加载时,我会从数据库中提取时区并将其转换为它的偏移量.例如,America/New_York将被转换为-04:00和(UTC -04:00) Atlantic Standard Time将被选中.
现在,用户将选择不同的时区并提交表单.然后我将偏移量转换为字符串,然后将其存储到数据库中.
我遇到了一个问题:
$this->convertOffsetToString('+03:00'); 回报 Europe/Helsinki$this->convertOffsetToString('+04:00'); 回报 Europe/Moscow但!
$this->convertStringToOffset('Europe/Moscow'); 回报 +03:00$this->convertStringToOffset('Europe/Helsinki'); 回报 +03:00因此,如果用户来到表单并Europe/Moscow在数据库中有时区,我们会将字符串转换为它的偏移量,+03:00并且'(UTC +03:00) Further-Eastern European Time'将被选中.
问题:两个不同的偏移量(例如+03:00和+04:00)将转换为两个不同的字符串时区.这两个不同的字符串时区将被转换为相同的偏移量!(例如+03:00).任何人都可以提出一个安全的可扩展解决方案来解决这个问题吗?
首先,
我知道将它们作为偏移存储在数据库中会更有意义
不,它没有.抵消变化.许多时区在一年中的部分时间应用夏令时,并且它们更改的日期/时间会有所不同.
您应该将用户时区存储为此列表中的字符串,然后使用该时区创建\ DateTimeZone的实例.例如:-
$tzString = 'Europe/London';
$tz = new \DateTimeZone($tzString);
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用以下内容随时获得正确的偏移量: -
$tz->getOffset(new \DateTime());
Run Code Online (Sandbox Code Playgroud)
例子.请注意,示例中生成的偏移量将在0到3600之间变化,具体取决于您查看的日期和时间.
当您存储用户时区时,您永远不必面对尝试将偏移转换为正确时区的麻烦.
我建议这是解决问题的"安全可扩展解决方案".