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',
];
此函数将时区字符串转换为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');
    }
}
这个函数将偏移量转换为字符串:
/**
 * 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;
}
所以在页面加载时,我会从数据库中提取时区并将其转换为它的偏移量.例如,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);
然后,您可以使用以下内容随时获得正确的偏移量: -
$tz->getOffset(new \DateTime());
例子.请注意,示例中生成的偏移量将在0到3600之间变化,具体取决于您查看的日期和时间.
当您存储用户时区时,您永远不必面对尝试将偏移转换为正确时区的麻烦.
我建议这是解决问题的"安全可扩展解决方案".