给定当地时间和几何时间偏移可以“恢复”UTC时间吗?

时间:2015-08-13 13:10:50

标签: python datetime timezone

我现在有服务器本地时间和一小时转移到UTC(比如+ 5,-8等),我该如何将其恢复为UTC?

请注意,由于夏令时,它并不像它那样直观。目前我在EDT,应该是UTC + 5,但事实上,在夏天,我们只有+4。不幸的是,我不(想)知道服务器的时区,所以我不确定是否可以用给定的信息计算UTC。

我的目标语言是python,但如果存在解决方案,语言本身应该不是一个大问题。

为什么我有这样的限制,是因为this。它只是没有返回一个好的文本时区描述而不是一个数字。

以下是我服务器实践中的一个真正要素:

<RegionalSettings>
  <Language>1033</Language>
  <Locale>1033</Locale>
  <AdvanceHijri>0</AdvanceHijri>
  <CalendarType>1</CalendarType>
  <Time24>False</Time24>
  <TimeZone>300</TimeZone>
  <SortOrder>2070</SortOrder>
  <Presence>True</Presence>
</RegionalSettings>

请注意时区字段

<TimeZone>300</TimeZone>

它在几分钟内,所以它告诉我我在UTC + 5的某个地方,但不是一个诚实的UTC时间转换。

1 个答案:

答案 0 :(得分:1)

如果你不(想)知道实际的时区,那么一般情况下是不可能的,因为在使用不同的DST规则时,某些时区现在可能具有相同的utc偏移量。

可以从当地时间和“标准”utc偏移量生成候选时区列表和utc时间:

#!/usr/bin/env python
from collections import defaultdict
from datetime import datetime, timedelta
from pprint import pprint
import pytz # $ pip install pytz

local_time = datetime(2015, 8, 13, 16, 15)
# standard offset (the current offset may be different)
#NOTE: opposite sign! -- it is not POSIX-style offset
standard_utc_offset_hours = timedelta(hours=-5)

# find all timezones with the same utc offset (in the recent time ~2y)
now = datetime.utcnow()
recent = now.replace(year=now.year - 2)
timezones = defaultdict(set) # recent utc offsets -> timezones
times = set()
for tz in map(pytz.timezone, pytz.all_timezones_set):
    # bisect(_utc_transition_times, input_utc_time) -> index
    # _transition_info[index] -> (offset, dst, tzname)
    # _tzinfos[offset, dst, tzname] -> timezone as pytz tzinfo object
    d = tz.fromutc(now)
    info = d.utcoffset(), d.dst(), d.tzname()
    for i, (offset, dst, tzname) in enumerate(getattr(tz, '_transition_info', [info])):
        if offset == standard_utc_offset_hours:  # same "standard" offset
            times.add(str(tz.localize(local_time, is_dst=None)))
            # group by recent utc offsets
            if not hasattr(tz, '_utc_transition_times'):
                timezones[d.strftime("%z"),].add(tz.zone)
                break
            elif tz._utc_transition_times[i] > recent: # recent rules
                it = (tz.fromutc(t).strftime("%z") for t in tz._utc_transition_times[i:])
                timezones[tuple(set(it))].add(tz.zone)
                break
pprint(times)
pprint(timezones)

输出

{'2015-08-13 16:15:00-03:00',
 '2015-08-13 16:15:00-04:00',
 '2015-08-13 16:15:00-05:00',
 '2015-08-13 16:15:00-06:00'}
{('-0500',): {'America/Eirunepe',
              'America/Porto_Acre',
              'America/Rio_Branco',
              'Brazil/Acre',
              'EST',
              'Etc/GMT+5'},
 ('-0500', '-0400'): {'America/Cayman',
                      'America/Detroit',
                      'America/Fort_Wayne',
                      'America/Grand_Turk',
                      'America/Havana',
                      'America/Indiana/Indianapolis',
                      'America/Indiana/Marengo',
                      'America/Indiana/Petersburg',
                      'America/Indiana/Vevay',
                      'America/Indiana/Vincennes',
                      'America/Indiana/Winamac',
                      'America/Indianapolis',
                      'America/Iqaluit',
                      'America/Kentucky/Louisville',
                      'America/Kentucky/Monticello',
                      'America/Louisville',
                      'America/Montreal',
                      'America/Nassau',
                      'America/New_York',
                      'America/Nipigon',
                      'America/Pangnirtung',
                      'America/Port-au-Prince',
                      'America/Thunder_Bay',
                      'America/Toronto',
                      'Canada/Eastern',
                      'Cuba',
                      'EST5EDT',
                      'US/East-Indiana',
                      'US/Eastern',
                      'US/Michigan'},
 ('-0500', '-0600'): {'America/Bahia_Banderas',
                      'America/Cancun',
                      'America/Chicago',
                      'America/Indiana/Knox',
                      'America/Indiana/Tell_City',
                      'America/Knox_IN',
                      'America/Matamoros',
                      'America/Menominee',
                      'America/Merida',
                      'America/Mexico_City',
                      'America/Monterrey',
                      'America/North_Dakota/Beulah',
                      'America/North_Dakota/Center',
                      'America/North_Dakota/New_Salem',
                      'America/Rainy_River',
                      'America/Rankin_Inlet',
                      'America/Resolute',
                      'America/Winnipeg',
                      'CST6CDT',
                      'Canada/Central',
                      'Chile/EasterIsland',
                      'Mexico/General',
                      'Pacific/Easter',
                      'US/Central',
                      'US/Indiana-Starke'}}

根据您选择的时区,相同的本地时间和“标准”utc偏移可能有四种不同的utc时间。

可以从本地时间和相应的utc偏移量(相同的utc时间)生成候选时区列表:

#!/usr/bin/env python
from collections import defaultdict
from datetime import datetime, timedelta
from pprint import pprint
import pytz # $ pip install pytz

local_time = datetime(2015, 8, 13, 16, 15)
utc_offset_hours = -4 #NOTE: opposite sign! -- it is not POSIX-style offset

# <local time> = <utc time> + <utc offset>
utc_time = local_time - timedelta(hours=utc_offset_hours)
winter_time = datetime(2015, 1, 1) # northern hemisphere
timezones = defaultdict(list) # winter utc offset -> zones
for tz in map(pytz.timezone, pytz.all_timezones_set):
    tz_time = tz.fromutc(utc_time)
    if tz_time.replace(tzinfo=None) == local_time: # same utc offset now
        # group by winter utc offset
        timezones[tz.fromutc(winter_time).strftime("%Z%z")].append(tz.zone)
pprint(timezones)

输出

{'AMST-0300': ['America/Cuiaba', 'America/Campo_Grande'],
 'AMT-0400': ['Brazil/West',
              'America/Porto_Velho',
              'America/Boa_Vista',
              'America/Manaus'],
 'AST-0400': ['America/Anguilla',
              'America/Antigua',
              'America/Santo_Domingo',
              'America/St_Barthelemy',
              'America/St_Lucia',
              'America/Lower_Princes',
              'America/Blanc-Sablon',
              'America/Martinique',
              'America/Montserrat',
              'America/Grenada',
              'America/Curacao',
              'America/Virgin',
              'America/Kralendijk',
              'America/Puerto_Rico',
              'America/Guadeloupe',
              'America/Dominica',
              'America/Port_of_Spain',
              'America/Aruba',
              'America/Barbados',
              'America/St_Vincent',
              'America/St_Kitts',
              'America/Tortola',
              'America/Marigot',
              'America/St_Thomas'],
 'BOT-0400': ['America/La_Paz'],
 'CST-0500': ['America/Havana', 'Cuba'],
 'EST-0500': ['EST5EDT',
              'America/Fort_Wayne',
              'America/Toronto',
              'America/Kentucky/Monticello',
              'America/Indiana/Vevay',
              'America/Iqaluit',
              'US/East-Indiana',
              'America/Indiana/Vincennes',
              'America/Indiana/Petersburg',
              'US/Eastern',
              'America/Louisville',
              'America/Nassau',
              'America/Indiana/Winamac',
              'Canada/Eastern',
              'America/Nipigon',
              'America/Grand_Turk',
              'America/Port-au-Prince',
              'America/Montreal',
              'America/Thunder_Bay',
              'America/Kentucky/Louisville',
              'America/Detroit',
              'America/New_York',
              'America/Indiana/Indianapolis',
              'America/Pangnirtung',
              'America/Indiana/Marengo',
              'US/Michigan',
              'America/Indianapolis'],
 'GMT+4-0400': ['Etc/GMT+4'],
 'GYT-0400': ['America/Guyana'],
 'PYST-0300': ['America/Asuncion']}

正如您所看到的,即使某些时区今天使用相同的utc偏移量,它们也可能在不同的日期使用不同的utc偏移量。

您可以使用其他一些信息(例如国家/地区)来消除歧义。