【问题标题】:Python: All possible Timezone Abbreviations for given Timezone Name (and vise versa)Python:给定时区名称的所有可能的时区缩写(反之亦然)
【发布时间】:2016-07-04 05:14:35
【问题描述】:

使用pytz,我知道如何获得一个时区名称的列表,但我想获得所有可能的时区缩写对于每个时区名称:

import pytz
list(pytz.common_timezones)
['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa',...]

我正在寻找的是任何 时区缩写,例如 PSTPDT,忽略当前日期时间(例如现在),返回所有可能的时区名称,在本例中是一个包含America/Los_Angeles的列表。

谢谢

【问题讨论】:

    标签: python datetime timezone pytz


    【解决方案1】:

    我使用datetime 模块的strftime 函数来完成此操作,因为它具有返回时区缩写的%Z 格式说明符。这是一个 filter 语句,可以满足您的需要:

    >>> filter(lambda x: datetime.datetime.now(pytz.timezone(x)).strftime("%Z") == "PDT", pytz.common_timezones)
    ['America/Dawson',
    'America/Los_Angeles',
    'America/Tijuana',
    'America/Vancouver',
    'America/Whitehorse',
    'Canada/Pacific',
    'US/Pacific']
    

    您可以将"PDT" 替换为您需要的任何时区。请记住,您还需要导入 datetime

    【讨论】:

    • 感谢您的回复。但是,这是使用datetime.now(),它只会给那些当前匹配的时区名称提供时区缩写。例如,America/Los_Angeles 当前匹配 PST,但不匹配 PDT
    • >>> list(filter(lambda x: datetime.now(pytz.timezone(x)).strftime("%Z") == "PDT", pytz.common_timezones)) ['America/Dawson', 'America/Los_Angeles', 'America/Tijuana', 'America/Vancouver', 'America/Whitehorse', 'Canada/Pacific', 'US/Pacific']
    • >>> list(filter(lambda x: datetime.now(pytz.timezone(x)).strftime("%Z") == "PST", pytz.common_timezones)) ['Pacific/Pitcairn']
    【解决方案2】:
    import pytz
    for tzname in list(pytz.common_timezones):
        print(pytz.timezone(tzname)._tzname)
    

    Similar question

    【讨论】:

      【解决方案3】:

      由于您希望忽略当前日期时间,听起来您想查找 在任何时间使用给定缩写的任何时区 过去。该信息位于 Olson 数据库中,可通过 皮茨。但是,pytz 将此信息存储在 private 属性中, tzone._transition_info:

      import collections
      import datetime as DT
      import pytz
      
      tzones = collections.defaultdict(set)
      abbrevs = collections.defaultdict(set)
      
      for name in pytz.all_timezones:
          tzone = pytz.timezone(name)
          for utcoffset, dstoffset, tzabbrev in getattr(
                  tzone, '_transition_info', [[None, None, DT.datetime.now(tzone).tzname()]]):
              tzones[tzabbrev].add(name)
              abbrevs[name].add(tzabbrev)
      

      gettattr 的第三个(默认)参数的原因是为了处理一些 时区,例如Africa/Bujumbura,它从来没有任何转换。所以 在这些情况下,缩写是当前的缩写。


      In [94]: tzones['PST']
      Out[94]: 
      {'America/Bahia_Banderas',
       'America/Boise',
       'America/Creston',
       'America/Dawson',
       'America/Dawson_Creek',
       'America/Ensenada',
       'America/Hermosillo',
       'America/Inuvik',
       'America/Juneau',
       'America/Los_Angeles',
       'America/Mazatlan',
       'America/Metlakatla',
       'America/Santa_Isabel',
       'America/Sitka',
       'America/Tijuana',
       'America/Vancouver',
       'America/Whitehorse',
       'Canada/Pacific',
       'Canada/Yukon',
       'Mexico/BajaNorte',
       'Mexico/BajaSur',
       'PST8PDT',
       'Pacific/Pitcairn',
       'US/Pacific',
       'US/Pacific-New'}
      

      In [95]: tzones['PDT']
      Out[95]: 
      {'America/Boise',
       'America/Dawson',
       'America/Dawson_Creek',
       'America/Ensenada',
       'America/Juneau',
       'America/Los_Angeles',
       'America/Metlakatla',
       'America/Santa_Isabel',
       'America/Sitka',
       'America/Tijuana',
       'America/Vancouver',
       'America/Whitehorse',
       'Canada/Pacific',
       'Canada/Yukon',
       'Mexico/BajaNorte',
       'PST8PDT',
       'US/Pacific',
       'US/Pacific-New'}
      

      In [97]: abbrevs['America/Los_Angeles']
      Out[97]: {'LMT', 'PDT', 'PPT', 'PST', 'PWT'}
      

      作为Paul points out,请注意时区缩写是不明确的——它们不一定映射到具有相同utcoffset 的时区。例如,Asia/ShanghaiUS/Central 都使用 CST 时区缩写。

      In [242]: 'Asia/Shanghai' in tzones['CST']
      Out[242]: True
      
      In [243]: 'US/Central' in tzones['CST']
      Out[243]: True
      

      【讨论】:

      • @J.F.Sebastian:非常感谢改进。
      • 值得注意的是,这些并不一定都指的是同一个区域。考虑tzones['CST'] 包括'Cuba''Asia/Shanghai''US/Central'
      【解决方案4】:

      我喜欢 unutbu 的回答,这让我找到了对我有用的答案。我有用户的语言环境,所以我发现我可以用它来消除时区缩写之间的歧义。

      换句话说,这解决了以下问题:

      In [242]: 'Asia/Shanghai' in tzones['CST']
      Out[242]: True
      
      In [243]: 'US/Central' in tzones['CST']
      Out[243]: True
      

      此函数需要两个字母的国家代码:

      def GetTimeZoneName(timezone, country_code):
      
          #see if it's already a valid time zone name
          if timezone in pytz.all_timezones:
              return timezone
      
          #if it's a number value, then use the Etc/GMT code
          try:
              offset = int(timezone)
              if offset > 0:
                  offset = '+' + str(offset)
              else:
                  offset = str(offset)
              return 'Etc/GMT' + offset
          except ValueError:
              pass
      
          #look up the abbreviation
          country_tzones = None
          try:
              country_tzones = pytz.country_timezones[country_code]
          except:
              pass
      
          set_zones = set()
          if country_tzones is not None and len(country_tzones) > 0:
              for name in country_tzones:
                  tzone = pytz.timezone(name)
                  for utcoffset, dstoffset, tzabbrev in getattr(tzone, '_transition_info', [[None, None, datetime.datetime.now(tzone).tzname()]]):
                      if tzabbrev.upper() == timezone.upper():
                          set_zones.add(name)
      
              if len(set_zones) > 0:
                  return min(set_zones, key=len)
      
              # none matched, at least pick one in the right country
              return min(country_tzones, key=len)
      
      
          #invalid country, just try to match the timezone abbreviation to any time zone
          for name in pytz.all_timezones:
              tzone = pytz.timezone(name)
              for utcoffset, dstoffset, tzabbrev in getattr(tzone, '_transition_info', [[None, None, datetime.datetime.now(tzone).tzname()]]):
                  if tzabbrev.upper() == timezone.upper():
                      set_zones.add(name)
      
          return min(set_zones, key=len)
      

      这将返回 CST 的正确时区:

      >>> GetTimeZoneName('CST','CN')
      'Asia/Shanghai'
      
      >>> GetTimeZoneName('CST','US')
      'America/Detroit'
      

      【讨论】:

      • 您的示例提出了一个有趣的问题,如果在上海机器和底特律机器中调用,date +%Z 命令返回的值是否都是 CST?
      • @intijk 我不是 100% 确定我理解你的问题。我没有使用日期 +%Z 时间。我从设备中获得了缩写的时区。我从上海机器和底特律机器都得到“CST”。我正在尝试使用它来获取正确的 pytz 时区。
      【解决方案5】:

      更新 py3.9+(如 PEP615 中所述),新的 zoneinfo 模块可能会有所帮助:

      from collections import defaultdict
      from datetime import datetime as dt
      from zoneinfo import available_timezones, ZoneInfo
      
      now = dt.utcnow()
      tz_key = lambda tz: ZoneInfo(tz).tzname(now)
      tz_map = defaultdict(list)
      
      for tz in available_timezones():
          tz_map[tz_key(tz)].append(tz)
      tz_map = {k: sorted(v) for k, v in tz_map.items()}
      

      例如,print(tz_map['PDT']) 将产生:['America/Ensenada', 'America/Los_Angeles', 'America/Santa_Isabel', 'America/Tijuana', 'America/Vancouver', 'Canada/Pacific', 'Mexico/BajaNorte', 'PST8PDT', 'US/Pacific', 'US/Pacific-New']

      注意:时区取自本地安装的时区数据。您还可以添加第一方 tzdata 库(不在标准库中,但由 python 的核心开发人员维护:使用pip install tzdata)。

      【讨论】:

      • 注意:对于给定的地理时区,由于 DST 处于活动状态或不活动状态,一年中可能会应用不同的 UTC 偏移量。因此,使用datetime.now()(不需要使用utcnow 顺便说一句。)只为您提供完整图片的一部分(因此只是所有缩写的一部分)。
      猜你喜欢
      • 1970-01-01
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-23
      • 2014-07-05
      • 2013-07-05
      相关资源
      最近更新 更多