如何获得与Olson timezone name来电所提供的值相对应的localtime
(例如Australia/Sydney
)?
这是通过TZ
覆盖的值,通过符号链接/etc/localtime
或在与时间相关的系统配置文件中设置TIMEZONE
变量。
答案 0 :(得分:17)
我认为最好的选择是通过所有pytz时区并检查哪一个匹配当地时区,每个pytz时区对象包含有关utcoffset和tzname的信息,如CDT,EST,可以从{{1}获取有关当地时间的相同信息}和time.timezone/altzone
,我认为这足以正确匹配pytz数据库中的本地时区,例如
time.tzname
输出:
['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','加拿大/中环','墨西哥/将军', '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 / Queensland','Australia / Sydney','Australia / Tasmania', '澳大利亚/维多利亚']
答案 1 :(得分:16)
这是一种作弊,我知道,但从'/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()
答案 2 :(得分:13)
一个问题是有多个“漂亮的名字”,比如“澳大利亚/悉尼”,它指向同一时区(例如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
这样的调用 - 它可以找到给定时区的所有同义词名称。
答案 3 :(得分: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
...
可以仅使用官方地区名称“Europe”,“America”过滤重复项...如果仍有重复项,您可以使用最短的名称: - )
答案 4 :(得分:7)
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的{{1)对您的Olson Timezone进行最佳猜测。模块 hostip.info项目,它引用您的IP地址并相应地对您进行地理定位。)
例如,只需匹配Timzone名称就可以为EST(GMT-5)生成locale
,America/Moncton
或America/Montreal
。但是,如果您的国家/地区是美国,则会将答案限制为America/New_York
。
但是,如果您的国家/地区是加拿大,则该脚本将默认为加拿大最顶级的结果(America/New_York
)。如果有办法进一步完善这一点,请随时在评论中留下建议。
答案 5 :(得分:4)
Python的tzlocal模块正是针对这个问题。它在Linux和Windows下产生一致的结果,使用CLDR映射正确地从Windows时区ID转换为Olson。
答案 6 :(得分:2)
这将根据TZ变量中的内容或未设置的本地时间文件获取时区名称:
#! /usr/bin/env python
import time
time.tzset
print time.tzname
答案 7 :(得分: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'
这里是解释当地时区的niave日期时间(由数据库查询返回)。
答案 8 :(得分: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()
答案 9 :(得分:0)
在大多数情况下,我更改了tcurvelo的脚本以找到正确的时区形式(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()
答案 10 :(得分:-1)
This JavaScript project尝试在浏览器客户端解决同样的问题。它的工作原理是使用语言环境播放“二十个问题”,询问某些过去时间的UTC偏移量(测试夏令时间界限等),并使用这些结果推断出当地时区必须是什么。遗憾的是,我不知道任何等效的Python包,所以如果有人想要使用这个解决方案,那么就必须将它移植到Python。
虽然这个公式需要每次更新(最坏的情况下)更新TZ数据库,但是这个算法和Anurag Uniyal提出的解决方案的组合(只保留两种方法返回的可能性)听起来像是最可靠的方法计算有效的本地时区。只要在任意两个时区的至少一个本地时间的UTC偏移之间存在一些差异,这样的系统就可以在它们之间正确选择。