it-swarm.com.de

Python: Finde die lokale Zeitzone heraus

Ich möchte UTC-Zeitstempel aus einer Protokolldatei mit lokalen Zeitstempeln vergleichen. Beim Erstellen des lokalen datetime-Objekts verwende ich Folgendes:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0, 
                                 tzinfo=pytz.timezone('Israel'))

Ich möchte ein automatisches Werkzeug finden, das die tzinfo=pytz.timezone('Israel') durch die aktuelle lokale Zeitzone ersetzt.

Irgendwelche Ideen?

45
Adam Matan

Versuchen Sie dateutil , der einen tzlocal Typ hat, der das tut, was Sie brauchen.

29
Steven

In Python 3.x kann die lokale Zeitzone folgendermaßen ermittelt werden:

import datetime
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo

Es ist eine knifflige Verwendung von datetimes code .

43
vbem

vergleichen von UTC-Zeitstempeln aus einer Protokolldatei mit lokalen Zeitstempeln.

Es ist schwierig, den Namen von Olson TZ für eine lokale Zeitzone herauszufinden auf tragbare Weise. Glücklicherweise brauchen Sie es nicht, um den Vergleich durchzuführen.

tzlocal module gibt eine Pytz-Zeitzone zurück, die der lokalen Zeitzone entspricht:

from datetime import datetime

import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal

tz = get_localzone()
local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc) #NOTE: utc.normalize() is unnecessary here

Im Gegensatz zu anderen bisher vorgestellten Lösungen werden durch den obigen Code folgende Probleme vermieden:

  • Ortszeit kann mehrdeutig sein d. h., ein genauer Vergleich kann für einige Ortszeiten unmöglich sein
  • der utc-Versatz kann für denselben lokalen Zeitzonennamen für vergangene Datumsangaben unterschiedlich sein. Einige Bibliotheken, die zeitzonenorientierte Datetime-Objekte unterstützen (z. B. dateutil), können dies nicht berücksichtigen

Hinweis: Um ein Zeitzonen-kompatibles Datetime-Objekt von einem naiven Datetime-Objekt zu erhalten, sollten Sie es verwenden*:

local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None)

anstatt:

#XXX fails for some timezones
local_dt = datetime(2010, 4, 27, 12, 0, 0, 0, tzinfo=tz)

*is_dst=None erzwingt eine Ausnahme, wenn die Ortszeit mehrdeutig oder nicht vorhanden ist.

Wenn Sie sicher sind, dass alle lokalen Zeitstempel denselben (aktuellen) UTC-Offset für die lokale Zeitzone verwenden, können Sie den Vergleich nur mit stdlib durchführen:

# convert a naive datetime object that represents time in local timezone to Epoch time
timestamp1 = (datetime(2010, 4, 27, 12, 0, 0, 0) - datetime.fromtimestamp(0)).total_seconds()

# convert a naive datetime object that represents time in UTC to Epoch time
timestamp2 = (datetime(2010, 4, 27, 9, 0) - datetime.utcfromtimestamp(0)).total_seconds()

timestamp1 und timestamp2 können direkt verglichen werden.

Hinweis: 

  • Die timestamp1-Formel funktioniert nur, wenn der UTC-Offset in Epoch (datetime.fromtimestamp(0)) derselbe ist wie jetzt
  • fromtimestamp() erstellt ein naives datetime-Objekt in der aktuellen lokalen Zeitzone
  • utcfromtimestamp() erstellt ein naives datetime-Objekt in UTC.
26
jfs

Ich habe das auch von mir selbst gefragt, und ich habe die Antwort in 1 gefunden:

Schauen Sie sich Abschnitt 8.1.7 an: das Format "% z" (Kleinbuchstaben, das Z-Großbuchstaben gibt auch die Zeitzone zurück, jedoch nicht im 4-stelligen Format, sondern in Form von Zeitzonen-Abkürzungen, wie in [3]). von strftime gibt das in E-Mail-Headern übliche Formular "+/- 4DIGIT" zurück (siehe Abschnitt 3.3 von RFC 2822, siehe [2], wodurch die anderen Möglichkeiten zur Angabe der Zeitzone für E-Mail-Header außer Kraft gesetzt werden).

Wenn Sie Ihre Zeitzone in diesem Format haben möchten, verwenden Sie: 

time.strftime("%z")

[1] http://docs.python.org/2/library/datetime.html

[2] http://tools.ietf.org/html/rfc2822#section-3.3

[3] Abkürzungen für Zeitzonen: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations , nur als Referenz.

11
David L

Zuerst erhalten Sie pytz- und tzlocal-Module

pip install pytz tzlocal

dann

from tzlocal import get_localzone
local = get_localzone()

dann kannst du so etwas machen

from datetime import datetime
print(datetime.now(local))
5
aminalid

Basierend auf J. F. Sebastians Antwort können Sie dies mit der Standardbibliothek machen:

import time, datetime
local_timezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone))

In 3.4 getestet, sollte auf 3.4+ funktionieren

3
Gilly

Hier ist eine etwas prägnantere Version der @ vbem-Lösung:

from datetime import datetime as dt

dt.utcnow().astimezone().tzinfo

Der einzige wesentliche Unterschied ist, dass ich datetime.datetime.now(datetime.timezone.utc) durch datetime.datetime.utcnow() ersetzt habe. Der Kürze halber habe ich auch datetime.datetime als dt gealtert.

Für meine Zwecke möchte ich den UTC-Offset in Sekunden. So sieht das aus:

dt.utcnow().astimezone().utcoffset().total_seconds()
3
David Marx

So können Sie die lokale Zeitzone nur über die Standardbibliothek erhalten (funktioniert nur in einer * nix-Umgebung):

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

Sie können dies verwenden, um eine pytz-Zeitzone zu erstellen:

>>> import pytz
>>> my_tz_name = '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:])
>>> my_tz = pytz.timezone(my_tz_name)
>>> my_tz
<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>

... die Sie dann auf eine datetime anwenden können:

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059)

>>> now.replace(tzinfo=my_tz)
>>> now
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059, tzinfo=<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>)
3
amorphic

Basierend auf Thokus Antwort oben, hier eine Antwort, die die Zeitzone auf die nächste halbe Stunde auflöst (was für einige Zeitzonen relevant ist, z. B. in South Australia):

from datetime import datetime
round((round((datetime.now()-datetime.utcnow()).total_seconds())/1800)/2)
2
user2380550

Nicht-Standard-Modul vermeiden (scheint eine fehlende Methode des Datum-Uhrzeit-Moduls zu sein):

from datetime import datetime
utcOffset_min = int(round((datetime.now() - datetime.utcnow()).total_seconds())) / 60   # round for taking time twice
utcOffset_h = utcOffset_min / 60
assert(utcOffset_min == utcOffset_h * 60)   # we do not handle 1/2 h timezone offsets

print 'Local time offset is %i h to UTC.' % (utcOffset_h)
2
thoku

Für einfache Dinge kann die folgende tzinfo-Implementierung verwendet werden, die das Betriebssystem nach Zeitzonenoffsets abfragt:

import datetime
import time

class LocalTZ(datetime.tzinfo):
    _unixEpochOrdinal = datetime.datetime.utcfromtimestamp(0).toordinal()

    def dst(self, dt):
        return datetime.timedelta(0)

    def utcoffset(self, dt):
        t = (dt.toordinal() - self._unixEpochOrdinal)*86400 + dt.hour*3600 + dt.minute*60 + dt.second + time.timezone
        utc = datetime.datetime(*time.gmtime(t)[:6])
        local = datetime.datetime(*time.localtime(t)[:6])
        return local - utc


print datetime.datetime.now(LocalTZ())
print datetime.datetime(2010, 4, 27, 12, 0, 0, tzinfo=LocalTZ())

# If you're in the EU, the following datetimes are right on the DST change.
print datetime.datetime(2013, 3, 31, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 3, 31, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is invalid, as the clock moves directly from
# 01:59:59 standard time to 03:00:00 daylight savings time.
print datetime.datetime(2013, 3, 31, 2, 0, 0, tzinfo=LocalTZ())

print datetime.datetime(2013, 10, 27, 0, 59, 59, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 0, 0, tzinfo=LocalTZ())
print datetime.datetime(2013, 10, 27, 1, 59, 59, tzinfo=LocalTZ())

# The following datetime is ambigous, as 02:00 can be either DST or standard
# time. (It is interpreted as standard time.)
print datetime.datetime(2013, 10, 27, 2, 0, 0, tzinfo=LocalTZ())
1
Søren Løvborg

Beachten Sie zunächst, dass die Frage eine falsche Initialisierung eines bekannten Datumsobjekts darstellt:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0,
...                                  tzinfo=pytz.timezone('Israel'))

erstellt eine ungültige Instanz. Man kann das Problem erkennen, indem man den UTC-Offset des resultierenden Objekts berechnet:

>>> print(local_time.utcoffset())
2:21:00

(Beachten Sie das Ergebnis, das einen ungeraden Bruchteil einer Stunde darstellt.)

Um eine bewusste Datetime korrekt mit pytz zu initialisieren, sollte die localize()-Methode wie folgt verwendet werden:

>>> local_time=pytz.timezone('Israel').localize(datetime.datetime(2010, 4, 27, 12))
>>> print(local_time.utcoffset())
3:00:00

Wenn Sie als neue tzinfo eine lokale pytz-Zeitzone benötigen, sollten Sie das tzlocal-Paket wie von anderen erläutert verwenden. Wenn Sie jedoch nur eine Instanz mit einem korrekten lokalen Zeitzonen-Offset und einer entsprechenden Abkürzung benötigen, können Sie mit Python 3.3 beginnen Rufen Sie die astimezone()-Methode ohne Argumente auf, um eine bewusste datetime-Instanz in Ihre lokale Zeitzone zu konvertieren:

>>> local_time.astimezone().strftime('%Y-%m-%d %H:%M %Z %z')
'2010-04-27 05:00 EDT -0400'

Sie sind vielleicht zufrieden mit Pendel

>>> pendulum.datetime(2015, 2, 5, tz='local').timezone.name
'Israel'

Pendulum verfügt über eine gut entwickelte API zur Bearbeitung von Datumsangaben. Alles ist TZ-bewusst.

0
Étienne Bersac
now_dt = datetime.datetime.now()
utc_now = datetime.datetime.utcnow()
now_ts, utc_ts = map(time.mktime, map(datetime.datetime.timetuple, (now_dt, utc_now)))
offset = int((now_ts - utc_ts) / 3600)

hoffe das wird dir helfen.

0
宝城 p