获取当地时区的 Olson TZ 名称?

发布于 2024-12-08 07:19:52 字数 349 浏览 0 评论 0原文

如何获取对应于的奥尔森时区名称(例如Australia/Sydney) C 的 localtime 调用给出的值?

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

How do I get the Olson timezone name (such as Australia/Sydney) corresponding to the value given by C's localtime call?

This is the value overridden via TZ, by symlinking /etc/localtime, or setting a TIMEZONE variable in time-related system configuration files.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

︶ ̄淡然 2024-12-15 07:19:52

我知道这是一种作弊,但是从 '/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()

This is kind of cheating, I know, but getting from '/etc/localtime' doesn't work for you?
Like following:

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

Hope it helps.

Edit: I liked @A.H.'s idea, in case '/etc/localtime' isn't a symlink. Translating that into 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()
水水月牙 2024-12-15 07:19:52

我认为最好的办法是遍历所有 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',
'美国/巴伊亚班德拉斯', '美国/伯利兹', '美国/剑桥湾',
'美国/坎昆', '美国/芝加哥', '美国/奇瓦瓦州',
'美洲/珊瑚港'、'美洲/哥斯达黎加'、'美洲/萨尔瓦多'、
'美国/韦恩堡', '美国/危地马拉',
'美国/印第安纳州/印第安纳波利斯', '美国/印第安纳州/诺克斯',
'美国/印第安纳州/马伦戈', '美国/印第安纳州/马伦戈',
'美国/印第安纳州/彼得斯堡', '美国/印第安纳州/Tell_City',
'美国/印第安纳州/韦韦', '美国/印第安纳州/文森斯',
'美国/印第安纳州/威纳马克', '美国/印第安纳波利斯', '美国/伊魁特',
'美国/肯塔基州/路易斯维尔', '美国/肯塔基州/路易斯维尔',
'美国/肯塔基州/蒙蒂塞洛', '美国/Knox_IN',
'美国/路易斯维尔', '美国/路易斯维尔', '美国/马那瓜',
'美国/马塔莫罗斯'、'美国/梅诺米尼'、'美国/梅里达'、
'美国/墨西哥城', '美国/蒙特雷',
'美国/北达科他州/比尤拉', '美国/北达科他州/中心',
'美国/北达科他州/新塞勒姆', '美国/奥吉纳加',
'美国/Pangnirtung', '美国/Rainy_River', '美国/Rankin_Inlet',
'美国/雷索鲁特', '美国/雷索鲁特', '美国/特古西加尔巴',
'美国/温尼伯'、'CST6CDT'、'加拿大/中部'、'墨西哥/一般'、
“美国/中部”、“美国/东印第安纳”、“美国/印第安纳-斯塔克”]

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

更改时区后测试脚本:

$ export TZ='澳大利亚/悉尼'
$ python get_tz_names.py
['南极洲/麦格理','澳大利亚/ACT','澳大利亚/布里斯班',
'澳大利亚/堪培拉', '澳大利亚/柯里', '澳大利亚/霍巴特',
'澳大利亚/林德曼', '澳大利亚/墨尔本', '澳大利亚/新南威尔士州',
'澳大利亚/昆士兰'、'澳大利亚/悉尼'、'澳大利亚/塔斯马尼亚'、
'澳大利亚/维多利亚']

I think best bet is to go thru all pytz timezones and check which one matches local timezone, each pytz timezone object contains info about utcoffset and tzname like CDT, EST, same info about local time can be obtained from time.timezone/altzone and time.tzname, and I think that is enough to correctly match local timezone in pytz database e.g.

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

output:

['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']

In production you can create such a mapping beforehand and save it instead of iterating always.

Testing script after changing timezone:

$ 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']

淡墨 2024-12-15 07:19:52

一个问题是有多个“漂亮的名字”,例如“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']

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

One problem is that there are multiple "pretty names" , like "Australia/Sydney" , which point to the same time zone (e.g. CST).

So you will need to get all the possible names for the local time zone, and then select the name you like.

e.g.: for Australia, there are 5 time zones, but way more time zone identifiers:

     "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"

you should check if there is a library which wraps TZinfo , to handle the time zone API.

e.g.: for Python, check the pytz library:

http://pytz.sourceforge.net/

and

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

in Python you can do:

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']

but the API for Python seems to be pretty limited, e.g. it doesn't seem to have a call like Ruby's all_linked_zone_names -- which can find all the synonym names for a given time zone.

怪我闹别瞎闹 2024-12-15 07:19:52

如果评估 /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
...

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

If evaluating /etc/localtime is OK for you, the following trick might work - after translating it to 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
...

The duplicates could be filtered using only the official region names "Europe", "America" ... If there are still duplicates, you could take the shortest name :-)

情话已封尘 2024-12-15 07:19:52

安装 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 名称可能会导致 EST (GMT-5) 的 America/MonctonAmerica/MontrealAmerica/New_York )。但是,如果您所在的国家/地区是美国,则会将答案限制为 America/New_York

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

Install 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

This code will take a best-guess crack at your Olson Timezone based both on your Timezone Name (as according to Python's time module), and your Country Code (as according to Python's locale module the hostip.info project, which references your IP address and geolocates you accordingly).

For example, simply matching the Timzone Names could result in America/Moncton, America/Montreal, or America/New_York for EST (GMT-5). If your country is the US, however, it will limit the answer to America/New_York.

However, if your country is Canada, the script will simply default to the topmost Canadian result (America/Moncton). If there is a way to further refine this, please feel free to leave suggestions in comments.

逐鹿 2024-12-15 07:19:52

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

The tzlocal module for Python is aimed at exactly this problem. It produces consistent results under both Linux and Windows, properly converting from Windows time zone ids to Olson using the CLDR mappings.

羅雙樹 2024-12-15 07:19:52

这将根据 TZ 变量或本地时间文件(如果未设置)中的内容获取时区名称:

#! /usr/bin/env python

import time

time.tzset
print time.tzname

This will get you the time zone name, according to what's in the TZ variable, or localtime file if unset:

#! /usr/bin/env python

import time

time.tzset
print time.tzname
北座城市 2024-12-15 07:19:52

这是另一种可能性,使用 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 日期时间(由数据库查询返回)。

Here's another posibility, using PyICU instead; which is working for my purposes:

>>> 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'

Here it is interpreting niave datetimes (as would be returned by a database query) in the local timezone.

魂归处 2024-12-15 07:19:52

我更喜欢遵循稍微比探究 _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()

I prefer following a slightly better than poking around _xxx values

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()
心凉怎暖 2024-12-15 07:19:52

在大多数情况下,我更改了 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()

I changed tcurvelo's script to find the right form of time zone (Continent/..../City), in most of cases, but return all of them if fails

#!/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()
老子叫无熙 2024-12-15 07:19:52

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

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

This JavaScript project attempts to solve the same issue in the browser client-side. It works by playing "twenty questions" with the locale, asking for the UTC offset of certain past times (to test for summer time boundaries, etc.) and using those results to deduce what the local time zone must be. I am not aware of any equivalent Python package unfortunately, so if someone wanted to use this solution it would have to be ported to Python.

While this formula will require updating every time (at worst) the TZ database is updated, a combination of this algorithm and the solution proposed by Anurag Uniyal (keeping only possibilities returned by both methods) sounds to me like the surest way to compute the effective local timezone. As long as there is some difference between the UTC offset of at least one local time in any two time zones, such a system can correctly choose between them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文