Strefa czasowa to trudny problem. Czas letni to jeszcze trudniejszy problem. Znalazłem się w problemy i problemy, kiedy zacząłem używać datetime w Pythonie poprawnie. Postanawiam więc napisać bloga, aby podzielić się swoim doświadczeniem.

„Naive” i „Aware”

pierwszą rzeczą, którą należy wiedzieć, jest to, że w Pythonie istnieją dwa typy datetime: offset-naive i offset-aware. Przesunięcie oznacza, że datetime nie ma informacji o strefie czasowej. Może to być bardzo podatne na błędy, jeśli jesteś nowy w Pythonie. Jeśli zmieszasz naiwną datetime i świadomą datetime, pojawi się błąd. Python nie ma wbudowanej obsługi strefy czasowej, musisz użyć pytz, modułu do informacji o strefie czasowej.

import pytz
from datetime import datetimetznaive_datetime = datetime(2018, 1, 1, 12, 0)
tzaware_datetime = datetime(2018, 1, 1, 12, 0, tzinfo=pytz.utc)# this will raise an error
tznaive_datetime == tzaware_datetime

aby uniknąć tego rodzaju problemów, musisz upewnić się, że Twoje obiekty datetime są zawsze offset-naiwne lub zawsze offset-świadome. Ale nie możemy uniknąć radzenia sobie z strefą czasową, więc moją najlepszą praktyką jest zawsze praca z DateTime świadomym offsetu.

domyślnie Python jest naiwny datetime. now() zwraca naiwną datetime w lokalnej strefie czasowej, a utcnow() zwraca również naiwną datetime, nawet funkcja wskazuje już strefę czasową UTC! Będziesz potrzebował modułu pytz, a także modułu tzlocal, aby wszystko było dobrze. Poniżej znajduje się sposób, w jaki uzyskuję czas z odpowiednią strefą czasową.

import datetime
import pytz
import tzlocaldef utcnow():
return pytz.utc.localize(datetime.utcnow())def now():
return tzlocal.get_localzone().localize(datetime.now())

parsowanie datetime z strefą czasową

Aktualizacja: to jest tylko problem w Pythonie 2

kolejną niespodzianką jest Python strptime parser nie działa z strefą czasową. Poniższy kod po prostu zawiedzie.

>>> from datetime import datetime
>>> datetime.strptime('2017-11-15T12:00:00-0700', '%Y-%m-%dT%H:%M:%S%z')ValueError: 'z' is a bad directive in format '%Y-%m-%dT%H:%m:%S%z'

aby przeanalizować datetime z strefą czasową, będziesz potrzebował innego modułu python-dateutil. Ten moduł dostarcza parser, który będzie działał z strefą czasową. Teraz możesz parsować datetime z strefą czasową!

>>> from dateutil import parser
>>> parser.parse('2017-11-15T12:00:00-07')datetime.datetime(2017, 11, 15, 12, 0, tzinfo=tzoffset(None, -25200))

Timedelta i DST

ostatnią rzeczą, którą musisz zachować ostrożność podczas manipulowania DateTime z uwzględnieniem offsetu. pytz pomoże Ci sprawdzić, czy data jest pod wpływem DST, sprawdzając metodę dst().

>>> import pytz
>>> pst = pytz.timezone("US/Pacific")
>>> pst.localize(datetime(2017, 10, 1)).dst()
datetime.timedelta(0, 3600)
>>> pst.localize(datetime(2017, 12, 1)).dst()
datetime.timedelta(0)

Uwaga: czas letni w 2017 roku zakończył się 5 listopada. Tak więc każda data po 5 listopada będzie miała timedelta(0)

ale informacje dst() nie są aktualizowane podczas manipulowania datetime

>>> (pst.localize(datetime(2017, 10, 1)) + timedelta(days=60)).dst()
datetime.timedelta(0, 3600)

co naprawdę możesz zrobić, to przekonwertować z powrotem na naiwną przesuniętą datetime, a następnie zastosować delta…

pst.localize(yourdate.replace(tzinfo=None) + td).dst()

podsumowanie

praca z Datetime w Pythonie jest podatna na błędy. To dlatego, że Python nie obsługuje dobrze datetime i timezone. Będziesz musiał użyć wielu dodatkowych modułów. Jednak, jest rzeczywiście srebrny pocisk, można po prostu użyć strzałki. Moduł ten stanowi zamiennik modułu DateTime Pythona i jest zawsze świadomy offsetu, a także rozwiązuje wszystkie problemy, o których wspomniałem powyżej. Jedyną rzeczą, którą mogę się martwić, jest integracja z innymi zewnętrznymi aplikacjami, takimi jak Spark.