Get the Olson TZ name for the local timezone?
如何获得与C的
这是通过
我认为最好的选择是通过所有pytz时区并检查哪一个匹配当地时区,每个pytz时区对象包含有关utcoffset和tzname的信息,如CDT,EST,有关当地时间的相同信息可以从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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']
我知道,这是一种作弊行为,但从
如下:
1 2 3 | >>> import os >>> '/'.join(os.readlink('/etc/localtime').split('/')[-2:]) 'Australia/Sydney' |
希望能帮助到你。
编辑:我喜欢@ A.H.的想法,以防
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/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() |
一个问题是有多个"漂亮的名字",如"澳大利亚/悉尼",它指向同一时区(例如CST)。
因此,您需要获取本地时区的所有可能名称,然后选择您喜欢的名称。
例如:对于澳大利亚,有5个时区,但更多的时区标识符:
1 2 3 4 | "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,请检查
http://pytz.sourceforge.net/
和
http://pypi.python.org/pypi/pytz/
在Python中你可以做到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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的
如果评估
1 2 3 4 5 6 | > 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 ... |
只使用官方地区名称"欧洲","美国"过滤重复项...如果仍有重复项,您可以使用最短的名称:-)
安装pytz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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的 Python的
例如,简单地匹配Timzone名称可能导致EST(GMT-5)的
但是,如果您的国家/地区是加拿大,则该脚本将默认为加拿大最顶级的结果(
Python的tzlocal模块正是针对这个问题。它在Linux和Windows下产生一致的结果,使用CLDR映射从Windows时区ID正确转换为Olson。
这将根据TZ变量中的内容或未设置的本地时间文件获取时区名称:
1 2 3 4 5 6 | #! /usr/bin/env python import time time.tzset print time.tzname |
这是另一个可能性,使用PyICU代替;这符合我的目的:
1 2 3 4 5 6 | >>> 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' |
这里是在本地时区解释niave日期时间(由数据库查询返回)。
在大多数情况下,我更改了tcurvelo的脚本以找到正确的时区形式(Continent /..../ City),但如果失败则返回所有时区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #!/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() |
我更喜欢跟随_xxx值稍微好一些
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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() |
此JavaScript项目尝试在浏览器客户端解决相同的问题。 它的工作原理是使用语言环境播放"二十个问题",询问某些过去时间的UTC偏移量(测试夏令时间界限等),并使用这些结果推断出当地时区必须是什么。 遗憾的是,我不知道任何等效的Python包,所以如果有人想要使用这个解决方案,则必须将其移植到Python。
虽然这个公式需要每次更新(最差)更新TZ数据库,但是这个算法和Anurag Uniyal提出的解决方案的组合(只保留两种方法返回的可能性)听起来像是计算有效性的最可靠方法 当地时区。 只要在任何两个时区中至少一个本地时间的UTC偏移之间存在一些差异,这样的系统就可以在它们之间正确地进行选择。