获取当地时区的Olson TZ名称?
如何获得与C的localtime
呼叫给定的值相对应的Olson时区名称 (如Australia/Sydney
)?
这是通过TZ
覆盖的值,通过symlinking /etc/localtime
,或在时间相关的系统configuration文件中设置TIMEZONE
variables。
我认为最好的select是通过所有pytz时区,并检查哪个匹配本地时区,每个pytz时区对象包含有关utcoffset和tzname的信息,如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
输出:
美洲/ Atikokan,美洲/ Bahia_Banderas,America / Bahia_Banderas,America / Belize,America / Cambridge_Bay,America / Cancun,America / Chicago,America / Chihuahua,美洲/印度尼西亚/印第安纳波利斯“,”美洲/印第安纳/诺克斯“,”美洲/印第安纳州/美国/美国/印第安纳/马龙戈','美国/印第安纳州/彼得斯堡','美国/印第安纳州/ Tell_City','美国/印第安纳州/维维','美国/印第安纳州/ Vincennes','America / Indiana / Winamac' ,美国/印第安纳波利斯,美国/ Iqaluit,美国/肯塔基/路易斯维尔,美国/肯塔基/路易斯维尔,美国/肯塔基/蒙蒂塞洛,美国/诺克斯IN,美国/路易斯维尔,美洲/马那瓜“,”美洲/马塔莫罗斯“,”美洲/梅诺米尼“,”美洲/梅里达“,”美国/墨西哥城“,”美国/蒙特雷“,”美洲/美洲/北达科他/中心“,”美洲/北达科他/新萨勒姆“,”美洲/ Ojinaga“,”美洲/ Pangnirtung“,”上午 埃里卡/ Rainy_River','America / Rankin_Inlet','America / Resolute','America / Resolute','America / Tegucigalpa','America / Winnipeg','CST6CDT','Canada / Central','Mexico / General' ,“美国/中环”,“美国/东印第安纳州”,“美国/印第安纳州 – 斯塔克”]
在生产中,您可以预先创build这样的映射,并保存它,而不是总是迭代。
更改时区后testing脚本:
$ export TZ ='澳大利亚/悉尼'
$ python get_tz_names.py
澳大利亚/澳大利亚/澳大利亚/澳大利亚/澳大利亚/澳大利亚/堪培拉,澳大利亚/澳大利亚/澳大利亚/澳大利亚/澳大利亚/澳大利亚/新南威尔士州,澳大利亚/昆士兰州,澳大利亚/悉尼,澳大利亚/塔斯马尼亚州,澳大利亚/维多利亚州]
这是一种作弊,我知道,但从'/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()
一个问题是,有多个“漂亮的名字”,如“澳大利亚/悉尼”,指向同一时区(如CST)。
因此,您需要获取当地时区的所有可能名称,然后select您喜欢的名称。
例如:对于澳大利亚,有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
这样的all_linked_zone_names
– 它可以find给定时区的所有同义词名称。
如果评估/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 ...
重复只能使用官方地区名称“欧洲”,“美国”进行过滤…如果仍有重复,可以采取最短的名称:-)
安装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的 hostip.info项目,它引用您的IP地址并相应地理定位)。 locale
模块
例如,简单地匹配Timzone域名可能导致America/Moncton
, America/Montreal
或America/New_York
的EST(GMT-5)。 但是,如果你的国家是美国,它将限制America/New_York
的答案。
但是,如果您的国家是加拿大,那么剧本将简单地默认为加拿大最高的结果( America/Moncton
)。 如果有进一步完善的方法,请在评论中留下build议。
Python的tzlocal模块正是针对这个问题。 它在Linux和Windows下生成一致的结果,使用CLDR映射从Windows时区id正确转换为Olson。
这将根据TZvariables中的内容或本地时间文件(如果未设置)为您提供时区名称:
#! /usr/bin/env python import time time.tzset print time.tzname
这是另一个可能性,用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'
这里是在本地时区中解释niave的date(就像数据库查询所返回的那样)。
我更喜欢跟随_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()
在大多数情况下,我更改了tcurvelo的脚本以find正确的时区forms(Continent /…./ City),但是如果失败
#!/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()
这个JavaScript项目试图在浏览器客户端解决同样的问题。 它通过在区域设置中播放“二十个问题”来工作,请求某些过去时间的UTC偏移量(用于testing夏令时边界等),并使用这些结果来推断当地时区必须是什么。 我不知道任何等效的Python包,所以如果有人想使用这个解决scheme,它将不得不被移植到Python。
虽然这个公式需要每次更新(最坏的情况)TZ数据库被更新,但是这个algorithm和Anurag Uniyal提出的解决scheme的组合(只保留两种方法返回的可能性)听起来像是计算有效的最可靠的方法当地时区。 只要在任何两个时区中至less有一个本地时间的UTC时差存在差异,这样的系统就可以在它们之间进行正确的select。