51

如何获取与C调用给出的值相对应的Olson 时区名称(例如)?Australia/Sydneylocaltime

这是TZ通过符号链接或在与时间相关的系统配置文件中/etc/localtime设置变量覆盖的值。TIMEZONE

4

11 回答 11

18

这有点作弊,我知道,但是从那里获取'/etc/localtime'对你不起作用?如下:

>>>  import os
>>> '/'.join(os.readlink('/etc/localtime').split('/')[-2:])
'Australia/Sydney'

希望能帮助到你。

编辑:我喜欢@AH 的想法,以防 '/etc/localtime'不是符号链接。将其翻译成 Python:

#!/usr/bin/env python

from hashlib import sha224
import os

def get_current_olsonname():
    tzfile = open('/etc/localtime')
    tzfile_digest = sha224(tzfile.read()).hexdigest()
    tzfile.close()

    for root, dirs, filenames in os.walk("/usr/share/zoneinfo/"):
        for filename in filenames:
            fullname = os.path.join(root, filename)
            f = open(fullname)
            digest = sha224(f.read()).hexdigest()
            if digest == tzfile_digest:
                return '/'.join((fullname.split('/'))[-2:])
            f.close()
        return None

if __name__ == '__main__':
    print get_current_olsonname()
于 2011-10-20T19:49:20.573 回答
18

我认为最好的办法是遍历所有 pytz 时区并检查哪个时区与本地时区匹配,每个 pytz 时区对象都包含有关 utcoffset 和 tzname 的信息,例如 CDT、EST,有关本地时间的相同信息可以从time.timezone/altzoneand获得time.tzname,我认为这是足以正确匹配 pytz 数据库中的本地时区,例如

import time
import pytz
import datetime

local_names = []
if time.daylight:
    local_offset = time.altzone
    localtz = time.tzname[1]
else:
    local_offset = time.timezone
    localtz = time.tzname[0]

local_offset = datetime.timedelta(seconds=-local_offset)

for name in pytz.all_timezones:
    timezone = pytz.timezone(name)
    if not hasattr(timezone, '_tzinfos'):
        continue#skip, if some timezone doesn't have info
    # go thru tzinfo and see if short name like EDT and offset matches
    for (utcoffset, daylight, tzname), _ in timezone._tzinfos.iteritems():
        if utcoffset == local_offset and tzname == localtz:
            local_names.append(name)

print local_names

输出:

['America/Atikokan'、'America/Bahia_Banderas'、'America/Bahia_Banderas'、'America/Belize'、'America/Cambridge_Bay'、'America/Cancun'、'America/Chicago'、'America/Chihuahua'、' America/Coral_Harbour'、'America/Costa_Rica'、'America/El_Salvador'、'America/Fort_Wayne'、'America/Guatemala'、'America/Indiana/Indianapolis'、'America/Indiana/Knox'、'America/Indiana/ Marengo'、'America/Indiana/Marengo'、'America/Indiana/Petersburg'、'America/Indiana/Tell_City'、'America/Indiana/Vevay'、'America/Indiana/Vincennes'、'America/Indiana/Winamac' , '美国/印第安纳波利斯', '美国/伊魁特', '美国/肯塔基/路易斯维尔', 'America/Kentucky/Louisville'、'America/Kentucky/Monticello'、'America/Knox_IN'、'America/Louisville'、'America/Louisville'、'America/Managua'、'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/Ojinaga', ' America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute'、'America/Tegucigalpa'、'America/Winnipeg'、'CST6CDT'、'Canada/Central' , '墨西哥/一般', '美国/中部', '美国/东印第安纳州', '美国/印第安纳州-斯塔克']]]America/Kentucky/Monticello', 'America/Knox_IN', 'America/Louisville', 'America/Louisville', 'America/Managua', '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/Ojinaga'、'America/Pangnirtung'、'America/ Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute'、'America/Tegucigalpa'、'America/Winnipeg'、'CST6CDT'、'Canada/Central'、'Mexico/General'、' US/Central', 'US/East-Indiana', 'US/Indiana-Starke']America/Kentucky/Monticello', 'America/Knox_IN', 'America/Louisville', 'America/Louisville', 'America/Managua', '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/Ojinaga'、'America/Pangnirtung'、'America/ Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute'、'America/Tegucigalpa'、'America/Winnipeg'、'CST6CDT'、'Canada/Central'、'Mexico/General'、' US/Central', 'US/East-Indiana', 'US/Indiana-Starke']'America/Louisville'、'America/Louisville'、'America/Managua'、'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/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute ', 'America/Resolute', 'America/Tegucigalpa', 'America/Winnipeg', 'CST6CDT', 'Canada/Central', 'Mexico/General', 'US/Central', 'US/East-Indiana', '美国/印第安纳-斯塔克']'America/Louisville'、'America/Louisville'、'America/Managua'、'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/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute ', 'America/Resolute', 'America/Tegucigalpa', 'America/Winnipeg', 'CST6CDT', 'Canada/Central', 'Mexico/General', 'US/Central', 'US/East-Indiana', '美国/印第安纳-斯塔克']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/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute'、'America/Tegucigalpa'、'America/Winnipeg' , 'CST6CDT', '加拿大/中部', '墨西哥/一般', '美国/中部', '美国/东印第安纳州', '美国/印第安纳州-斯塔克']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/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute'、'America/Tegucigalpa'、'America/Winnipeg' , 'CST6CDT', '加拿大/中部', '墨西哥/一般', '美国/中部', '美国/东印第安纳州', '美国/印第安纳州-斯塔克']America/North_Dakota/Center'、'America/North_Dakota/New_Salem'、'America/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute' , 'America/Tegucigalpa', 'America/Winnipeg', 'CST6CDT', 'Canada/Central', 'Mexico/General', 'US/Central', 'US/East-Indiana', 'US/Indiana-Starke' ]America/North_Dakota/Center'、'America/North_Dakota/New_Salem'、'America/Ojinaga'、'America/Pangnirtung'、'America/Rainy_River'、'America/Rankin_Inlet'、'America/Resolute'、'America/Resolute' , 'America/Tegucigalpa', 'America/Winnipeg', 'CST6CDT', 'Canada/Central', 'Mexico/General', 'US/Central', 'US/East-Indiana', 'US/Indiana-Starke' ]'美国/东印第安纳','美国/印第安纳-斯塔克']'美国/东印第安纳','美国/印第安纳-斯塔克']

在生产中,您可以预先创建这样的映射并保存它而不是总是迭代。

更改时区后的测试脚本:

$ export TZ='Australia/Sydney'
$ python get_tz_names.py
['Antarctica/Macquarie', 'Australia/ACT', 'Australia/Brisbane', 'Australia/Canberra', 'Australia/Currie', 'Australia/Hobart' , 'Australia/Lindeman', 'Australia/Melbourne', 'Australia/NSW', 'Australia/Queensland', 'Australia/Sydney', 'Australia/Tasmania', 'Australia/Victoria']

于 2011-11-30T15:58:02.170 回答
13

一个问题是有多个“漂亮的名字”,例如“Australia/Sydney”,它们指向同一个时区(例如CST)。

因此,您需要获取本地时区的所有可能名称,然后选择您喜欢的名称。

例如:对于澳大利亚,有 5 个时区,但时区标识符更多:

     "Australia/Lord_Howe", "Australia/Hobart", "Australia/Currie", 
     "Australia/Melbourne", "Australia/Sydney", "Australia/Broken_Hill", 
     "Australia/Brisbane", "Australia/Lindeman", "Australia/Adelaide", 
     "Australia/Darwin", "Australia/Perth", "Australia/Eucla"

您应该检查是否有一个包含 TZinfo 的库来处理时区 API。

例如:对于 Python,请检查pytz库:

http://pytz.sourceforge.net/

http://pypi.python.org/pypi/pytz/

在 Python 中,您可以执行以下操作:

from pytz import timezone
import pytz

In [56]: pytz.country_timezones('AU')
Out[56]: 
[u'Australia/Lord_Howe',
 u'Australia/Hobart',
 u'Australia/Currie',
 u'Australia/Melbourne',
 u'Australia/Sydney',
 u'Australia/Broken_Hill',
 u'Australia/Brisbane',
 u'Australia/Lindeman',
 u'Australia/Adelaide',
 u'Australia/Darwin',
 u'Australia/Perth',
 u'Australia/Eucla']

但是 Python 的 API 似乎非常有限,例如它似乎没有像 Ruby 那样的调用all_linked_zone_names——它可以找到给定时区的所有同义词名称。

于 2011-10-25T21:57:29.540 回答
8

如果评估/etc/localtime对您来说没问题,那么以下技巧可能会起作用 - 在将其翻译为 python 之后:

> md5sum /etc/localtime
abcdefabcdefabcdefabcdefabcdefab /etc/localtime
> find /usr/share/zoneinfo -type f |xargs md5sum | grep abcdefabcdefabcdefabcdefabcdefab
abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/Europe/London
abcdefabcdefabcdefabcdefabcdefab /usr/share/zoneinfo/posix/Europe/London
...

可以仅使用官方地区名称“欧洲”、“美国”过滤重复项...如果仍有重复项,您可以取最短的名称 :-)

于 2011-10-25T22:11:40.137 回答
7

安装 pytz

import pytz
import time
#import locale
import urllib2

yourOlsonTZ = None
#yourCountryCode = locale.getdefaultlocale()[0].split('_')[1]
yourCountryCode = urllib2.urlopen('http://api.hostip.info/country.php').read()

for olsonTZ in [pytz.timezone(olsonTZ) for olsonTZ in pytz.all_timezones]:
    if (olsonTZ._tzname in time.tzname) and (str(olsonTZ) in pytz.country_timezones[yourCountryCode]):
        yourOlsonTZ = olsonTZ
        break

print yourOlsonTZ

此代码将根据您的时区名称(根据 Python 的time模块)和您的国家/地区代码(根据Python 的locale模块hostip.info项目,它引用您的 IP 地址和地理定位,对您的奥尔森时区进行最佳猜测)你相应地)。

例如,简单地匹配 Timzone 名称可能会导致America/MonctonAmerica/MontrealAmerica/New_YorkEST (GMT-5)。但是,如果您所在的国家/地区是美国,则答案将限制为America/New_York.

但是,如果您所在的国家/地区是加拿大,则脚本将简单地默认为加拿大最上面的结果 ( America/Moncton)。如果有办法进一步完善这一点,请随时在评论中留下建议。

于 2011-10-25T19:55:41.303 回答
4

Python的tzlocal模块正是针对这个问题。它在 Linux 和 Windows 下产生一致的结果,使用 CLDR 映射正确地将 Windows 时区 id 转换为 Olson。

于 2013-04-24T03:34:06.650 回答
1

这将为您提供时区名称,根据 TZ 变量中的内容,如果未设置,则为本地时间文件:

#! /usr/bin/env python

import time

time.tzset
print time.tzname
于 2011-10-06T03:50:38.043 回答
1

这是另一种可能性,使用PyICU代替;这对我的目的有用:

>>> from PyICU import ICUtzinfo
>>> from datetime import datetime
>>> datetime(2012, 1, 1, 12, 30, 18).replace(tzinfo=ICUtzinfo.getDefault()).isoformat()
'2012-01-01T12:30:18-05:00'
>>> datetime(2012, 6, 1, 12, 30, 18).replace(tzinfo=ICUtzinfo.getDefault()).isoformat()
'2012-06-01T12:30:18-04:00'

在这里,它解释本地时区中的 nave 日期时间(数据库查询将返回)。

于 2012-06-01T22:41:42.103 回答
0

我更喜欢遵循比探索 _xxx 值稍好的

import time, pytz, os

cur_name=time.tzname
cur_TZ=os.environ.get("TZ")

def is_current(name):
   os.environ["TZ"]=name
   time.tzset()
   return time.tzname==cur_name

print "Possible choices:", filter(is_current, pytz.all_timezones)

# optional tz restore
if cur_TZ is None: del os.environ["TZ"]
else: os.environ["TZ"]=cur_TZ
time.tzset()
于 2012-04-17T09:38:02.323 回答
0

在大多数情况下,我更改了 tcurvelo 的脚本以找到正确的时区形式(大陆/..../城市),但如果失败则返回所有时区

#!/usr/bin/env python

from hashlib import sha224
import os
from os import listdir
from os.path import join, isfile, isdir

infoDir = '/usr/share/zoneinfo/'

def get_current_olsonname():
    result = []
    tzfile_digest = sha224(open('/etc/localtime').read()).hexdigest()

    test_match = lambda filepath: sha224(open(filepath).read()).hexdigest() == tzfile_digest

    def walk_over(dirpath):
        for root, dirs, filenames in os.walk(dirpath):
            for fname in filenames:
                fpath = join(root, fname)
                if test_match(fpath):
                    result.append(tuple(root.split('/')[4:]+[fname]))

    for dname in listdir(infoDir):
        if dname in ('posix', 'right', 'SystemV', 'Etc'):
            continue
        dpath = join(infoDir, dname)
        if not isdir(dpath):
            continue
        walk_over(dpath)

    if not result:
        walk_over(join(infoDir))

    return result


if __name__ == '__main__':
    print get_current_olsonname()
于 2013-07-30T00:15:15.747 回答
-1

这个 JavaScript 项目试图在浏览器客户端解决同样的问题。它通过在区域设置中播放“二十个问题”来工作,询问某些过去时间的 UTC 偏移量(以测试夏季时间边界等)并使用这些结果来推断本地时区必须是什么。不幸的是,我不知道有任何等效的 Python 包,所以如果有人想使用这个解决方案,就必须将它移植到 Python。

虽然每次更新 TZ 数据库时(在最坏的情况下)这个公式都需要更新,但这个算法和 Anurag Uniyal 提出的解决方案的组合(只保留两种方法返回的可能性)在我看来是计算有效的最可靠的方法当地时区。只要任意两个时区中至少一个当地时间的UTC偏移量存在一定的差异,这样的系统就可以正确地在它们之间进行选择。

于 2013-07-30T14:57:52.780 回答