将 UTC 偏移量转换为时区或日期

2022-01-14 00:00:00 timezone timezone-offset geolocation php

给你一个头疼的东西.

我正在从 IPInfoDB 的 API 获取地理 IP 数据,它返回与 UTC 的时区偏移量包括 DST(如果当前反映).

I am grabbing geo IP data from IPInfoDB's API and it returns a timezone offset from UTC including DST (if currently reflected).

例如,我住在 EST (-5),目前是 DST,因此地理 IP API 返回 (-04:00) 作为偏移量.

For example, I live in EST (-5) and currently it's DST, so the geo IP API returns (-04:00) as the offset.

这太棒了,因为 DST 令人头疼.但令我惊讶的是,它引起了另一个头痛.

This is wonderful since DST is a freaking headache. But to my surprise, it caused another headache.

我在 PHP 中加载这些数据以通过 AJAX 传递给应用程序.我想在应用程序上获得 IP 地址的实时本地时间.

I load this data in PHP to be passed via AJAX to the application. I would like to have the live local time of the IP address on the app.

我已经完美地设置了这一切,但我正在疯狂地试图弄清楚如何设置 PHP 时区以匹配偏移量,以便我可以获取当前时间 date('H'); 和分钟 date('i'); 通过 AJAX 传递.

I have that all set perfectly, but I am going crazy trying to figure out how to set the PHP timezone to match the offset so I can just grab the current hours date('H'); and minutes date('i'); to pass to via AJAX.

我不确定是否有一个特定的函数可以根据该偏移量给我当前的小时和分钟,或者是否有一种实用的方法可以根据偏移量设置时区(如果是,则已经应用了 DST有效).

I am unsure if there is a specific function that can just give me the current hours and minutes based on that offset or if there is a practical way to set the timezone based on the offset (which will have DST already applied if is in effect).

我一直在搜索和搜索谷歌以找到答案,但我正在做的更具体,因为 DST 已经应用.

I've been searching and searching Google to find an answer to this, but what I am doing is more specific since DST is already applied.

我在 PHP.net 上找到了一个似乎可以解决问题的函数(它适用于我的时区并返回正确的时间)尽管对于其他时区(例如 PST),即使偏移量正确(-07:00 使用 DST),它也会比应有的时间晚 1 小时返回.

I found one function on PHP.net that seems to do the trick (it works for my timezone and returns the correct time) although for other timezones such as PST, it's returning 1 hour later than it should be even though the offset is correct (-07:00 with DST).

从函数返回的时区是 Chile/EasterIsland 我觉得是原因.如果可以的话,我会让它只适用于美国,但我确实需要它在全球范围内.

The timezone returned from the function is Chile/EasterIsland which I have a feeling is the cause. If I could, I would make this only work for the USA, but I do need it to be worldwide.

这是我现在拥有的功能.请原谅非常混乱的代码.在过去的几个小时里,我一直在玩很多东西,试图找出解决方案.

This is the function I have now. Please excuse the extremely messy code. I have been playing around with tons of things over the last few hours trying to figure out a solution.

大部分功能都是在网上找到的.

Most of the functionality was found online.

function offsetToTZ($offset) {
switch((string) $offset) {
    case '-04:30' : return 'America/Caracas'; break;
    case '-03:30' : return 'Canada/Newfoundland'; break;
    case '+03:30' : return 'Asia/Tehran'; break;
    case '+04:30' : return 'Asia/Kabul'; break;
    case '+05:30' : return 'Asia/Kolkata'; break;
    case '+05:45' : return 'Asia/Kathmandu'; break;
    case '+09:30' : return 'Australia/Darwin'; break;
}
$offset = (int) str_replace(array('0',0,':00',00,'30',30,'45',45,':','+'),'', (string) $offset);

$offset = $offset*60*60;
$abbrarray = timezone_abbreviations_list(); 
foreach ($abbrarray as $abbr) { 
    foreach($abbr as $city) { 
        if($city['offset'] == $offset) { 
            return $city['timezone_id'];
        }
    }
}
return false; 
}

我为某些时区包括 :30:45 的开关/案例.可能有一种方法可以在不需要 switch/case 的情况下包含它.

I included the switch/case for certain timezones that are :30 and :45 out there. There may be a way to include that also without the need of the switch/case.

注意: 偏移量总是从 geo IP API 以 +00:00-00:00 形式返回.

NOTE: The offsets are always returned as such +00:00 or -00:00 from the geo IP API.

我将不胜感激任何帮助或正确方向的观点.我对 PHP 不是很熟悉,但偏移量对我来说是一个新故事.谢谢!

I would appreciate any help or a point in the right direction. I'm not very novice with PHP, but offsets are a new story for me. Thanks!

推荐答案

可以很简单地完成,将偏移量转换为秒并将其传递给timezone_name_from_abbr:

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');

演示

timezone_name_from_abbr的第三个参数控制是否调整夏令时.

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

错误 #44780:

timezone_name_from_abbr() 将在某个时区返回 false偏移量.特别是 - 夏威夷,从 GMT 偏移量为 -10,-36000秒.

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

参考资料:

  • timezone_name_from_abbr
  • date_default_timezone_set
  • 日期

相关文章