获取本地时区的Olson TZ名称?
11 个回答
一个问题是,有很多“好听的名字”,比如“澳大利亚/悉尼”,它们指向同一个时区(例如,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://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
那样的调用——这个调用可以找到给定时区的所有同义名称。
我知道这有点作弊,但你试过从 '/etc/localtime'
获取时间吗?像这样:
>>> import os
>>> '/'.join(os.readlink('/etc/localtime').split('/')[-2:])
'Australia/Sydney'
希望这对你有帮助。
编辑:我觉得 @A.H. 的想法不错,如果 '/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()
我觉得最好的办法是遍历所有的pytz时区,看看哪个和本地时区匹配。每个pytz时区对象都包含关于UTC偏移量和时区名称的信息,比如CDT、EST等。而本地时间的相关信息可以通过time.timezone/altzone
和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/Indianapolis', 'America/Iqaluit', 'America/Kentucky/Louisville', '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', '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']