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.
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
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()
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
:
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.
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 :-)
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 das hostip.info - Projekt, das auf Ihre IP - Adresse verweist und Sie entsprechend geolokalisiert).locale
-Modul
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.
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äß.
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
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()
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()