wake-up-neo.net

Bekomme den Olson TZ-Namen für die lokale Zeitzone?

Wie erhalte ich den Olson-Zeitzonen-Namen (z. B. Australia/Sydney), der dem von C localtime angegebenen Wert entspricht?

Dies ist der Wert, der durch TZ, durch Symlinking von /etc/localtime oder durch Setzen einer TIMEZONE-Variable in zeitbezogenen Systemkonfigurationsdateien überschrieben wird.

47
Matt Joiner

Ich denke, die beste Wette ist, alle Pytz-Zeitzonen durchzugehen und zu prüfen, welche mit der lokalen Zeitzone übereinstimmt. Jedes Pytz-Zeitzonenobjekt enthält Informationen zu UTC-Offset und TZ-Namen wie CDT, EST. Dieselben Informationen zur Ortszeit können von time.timezone/altzone und time.tzname abgerufen werden das reicht aus, um die lokale Zeitzone in der Pytz-Datenbank korrekt abzugleichen, z.

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

ausgabe:

['Amerika/Atikokan', 'Amerika/Bahia_Banderas', 'Amerika/Bahia_Banderas', 'Amerika/Belize', 'Amerika/Cambridge_Bay', 'Amerika/Cancún', 'Amerika/Chicago', 'Amerika/Chihuahua', ' Amerika/Coral_Harbour ',' Amerika/Costa_Rica ',' Amerika/El_Salvador ',' Amerika/Fort_Wayne ',' Amerika/Guatemala ',' Amerika/Indiana/Indianapolis ',' Amerika/Indiana/Knox ',' Amerika/Indiana/Marengo ',' Amerika/Indiana/Marengo ',' Amerika/Indiana/Petersburg ',' Amerika/Indiana/Tell_City ',' Amerika/Indiana/Vevay ',' Amerika/Indiana/Vincennes ',' Amerika/Indiana/Winamac ' , "Amerika/Indianapolis", "Amerika/Iqaluit", "Amerika/Kentucky/Louisville", "Amerika/Kentucky/Louisville", "Amerika/Kentucky/Monticello", "Amerika/Knox_IN", "Amerika/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 ',' Am erica/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 der Produktion können Sie ein solches Mapping im Voraus erstellen und speichern, anstatt es immer zu iterieren.

Testen des Skripts nach Änderung der Zeitzone:

$ export TZ = 'Australien/Sydney'
$ python get_tz_names.py
["Antarktis/Macquarie", "Australien/ACT", "Australien/Brisbane", "Australien/Canberra", "Australien/Currie", "Australien/Hobart", "Australien/Lindeman", "Australien"/Melbourne, Australien/New South Wales, Australien/Queensland, Australien/Sydney, Australien/Tasmanien, Australien/Victoria

17
Anurag Uniyal

Das ist eine Art Schummeln, ich weiß, aber von '/etc/localtime' zu bekommen, funktioniert für Sie nicht? Wie folgt:

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

Ich hoffe es hilft.

Edit : Ich mochte die Idee von @A. H., falls '/etc/localtime' kein Symlink ist. Das in Python übersetzen:

#!/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 __== '__main__':
    print get_current_olsonname()
16
Thiago Curvelo

Ein Problem ist, dass es mehrere "hübsche Namen" gibt, wie "Australien/Sydney", die auf dieselbe Zeitzone (z. B. CST) zeigen.

Sie müssen also alle möglichen Namen für die lokale Zeitzone abrufen und dann den gewünschten Namen auswählen.

für Australien gibt es beispielsweise 5 Zeitzonen, jedoch weit mehr Zeitzonen-IDs:

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

sie sollten prüfen, ob es eine Bibliothek gibt, die TZinfo einschließt, um die Zeitzonen - API zu verarbeiten.

beispiel: Überprüfen Sie für Python die Bibliothek pytz:

http://pytz.sourceforge.net/

und

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

in Python können Sie Folgendes tun:

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

die API für Python scheint jedoch ziemlich begrenzt zu sein, z. Es scheint keinen Anruf wie all_linked_zone_names von Ruby zu geben, der alle Synonymnamen für eine bestimmte Zeitzone findet.

13
Tilo

Wenn die Auswertung von /etc/localtime für Sie in Ordnung ist, kann der folgende Trick funktionieren - nachdem Sie ihn in Python übersetzt haben:

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

Die Duplikate könnten nur mit den offiziellen Regionsnamen "Europa", "Amerika" gefiltert werden ... Wenn es noch Duplikate gibt, können Sie den kürzesten Namen verwenden :-)

8
A.H.

pytz installieren

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

Mit diesem Code wird Ihre Olson - Zeitzone auf der Grundlage Ihres Timezonennamens (gemäß Pythons time - Modul) und Ihres Ländercodes (gemäß Pythons locale-Modul das hostip.info - Projekt, das auf Ihre IP - Adresse verweist und Sie entsprechend geolokalisiert).

Ein einfaches Abgleichen der Timzone-Namen kann beispielsweise America/Moncton, America/Montreal oder America/New_York für EST (GMT-5) ergeben. Wenn Ihr Land jedoch die USA ist, beschränkt sich die Antwort auf America/New_York.

Wenn Ihr Land jedoch Kanada ist, wird das Skript einfach auf das oberste kanadische Ergebnis (America/Moncton) gesetzt. Wenn Sie die Möglichkeit haben, dies weiter zu verfeinern, können Sie in Kommentaren Vorschläge machen.

6
Patrick Perini

Das tzlocal Modul für Python zielt genau auf dieses Problem ab. Unter Linux und Windows werden konsistente Ergebnisse erzielt. Die Konvertierung von Windows-Zeitzonen-IDs in Olson mithilfe der CLDR-Zuordnungen erfolgt ordnungsgemäß.

4
Matt Johnson

Dadurch erhalten Sie den Zeitzonennamen, je nachdem, was in der TZ-Variablen enthalten ist, oder die Ortszeit-Datei, wenn sie nicht festgelegt ist:

#! /usr/bin/env python

import time

time.tzset
print time.tzname
2

Hier ist eine andere Möglichkeit, stattdessen PyICU zu verwenden; was für meine Zwecke arbeitet:

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

Hier werden niave datetime (wie sie von einer Datenbankabfrage zurückgegeben würden) in der lokalen Zeitzone interpretiert.

Ich bevorzuge es, etwas besser zu folgen, als nach _xxx-Werten zu suchen

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()
0
korc

Ich habe das Skript von tcurvelo geändert, um in den meisten Fällen die richtige Form der Zeitzone (Continent /..../ City) zu finden, aber alle zurückgeben, falls dies fehlschlägt

#!/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 __== '__main__':
    print get_current_olsonname()
0
saeedgnu