Co muszę zrobić
Mam obiekt datetime nieświadomy strefy czasowej, do którego muszę dodać strefę czasową, aby móc ją porównać z innymi obiektami datetime rozpoznającymi strefę czasową. Nie chcę przekonwertować całej aplikacji na strefę czasową, nieświadoma tego jednego starszego przypadku.
Co próbowałem
Po pierwsze, aby zademonstrować problem:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
Najpierw spróbowałem astimezonu:
>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>
Nic dziwnego, że to się nie powiodło, ponieważ tak naprawdę próbuje dokonać konwersji. Zastąpienie wydawało się lepszym wyborem (jak w Pythonie: jak uzyskać wartość datetime.today (), która jest „świadoma strefy czasowej”? ):
>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
Ale jak widać, zamień wydaje się ustawiać tzinfo, ale nie uświadamia obiektu. Przygotowuję się do powrotu do sprawdzania łańcucha wejściowego, aby mieć strefę czasową przed analizowaniem (używam dateutil do analizowania, jeśli to ma znaczenie), ale to wydaje się niesamowicie niewyraźne.
Próbowałem tego również w Pythonie 2.6 i Pythonie 2.7, z tymi samymi wynikami.
Kontekst
Piszę parser dla niektórych plików danych. Jest stary format, który muszę obsługiwać, gdy ciąg daty nie ma wskaźnika strefy czasowej. Naprawiłem już źródło danych, ale nadal muszę obsługiwać starszy format danych. Jednorazowa konwersja starszych danych nie jest opcją z różnych powodów biznesowych BS. Chociaż ogólnie nie podoba mi się pomysł zaprogramowania domyślnej strefy czasowej, w tym przypadku wydaje się to najlepsza opcja. Wiem z wystarczającą pewnością, że wszystkie starsze dane, o których mowa, znajdują się w UTC, więc jestem gotów zaakceptować ryzyko niedotrzymania tego w tym przypadku.
unaware.replace()
powróciłby,None
gdyby modyfikowałunaware
obiekt w miejscu. REPL pokazuje, że.replace()
zwraca tutaj nowydatetime
obiekt.import datetime; datetime.datetime.now(datetime.timezone.utc)
tz
arg, aby był bardziej czytelny:datetime.datetime.now(tz=datetime.timezone.utc)
Odpowiedzi:
Ogólnie rzecz biorąc, aby naiwna strefa czasowa uwzględniała strefę czasową, skorzystaj z metody localize :
W strefie czasowej UTC nie jest tak naprawdę konieczne,
localize
ponieważ nie ma obliczenia czasu letniego do obsługi:Pracuje. (
.replace
zwraca nowy czas danych; nie zmienia sięunaware
).źródło
aware = datetime(..., tz)
użyj.localize()
zamiast tego.tz.localize(..., is_dst=None)
twierdzi, że tak nie jest.Wszystkie te przykłady wykorzystują moduł zewnętrzny, ale możesz osiągnąć ten sam wynik, korzystając tylko z modułu datetime, jak również przedstawiono w tej odpowiedzi SO :
Mniej zależności i brak problemów z pytz.
UWAGA: Jeśli chcesz używać tego z python3 i python2, możesz również użyć tego do importu strefy czasowej (na stałe dla UTC):
źródło
pytz
problemom, cieszę się, że przewinąłem trochę w dół! Naprawdę nie chciałem się zmagać zpytz
moimi zdalnymi serwerami :)from datetime import timezone
działa w py3, ale nie py2.7.dt.replace(tzinfo=timezone.utc)
zwraca nową datę i godzinę, nie zmienia siędt
w miejscu. (Będę edytować, aby to pokazać).tz = pytz.timezone('America/Chicago')
Korzystałem z dt_aware do dt_unaware
i dt_unware do dt_aware
ale odpowiedź wcześniej jest również dobrym rozwiązaniem.
źródło
localtz.localize(dt_unware, is_dst=None)
aby zgłosić wyjątek, jeślidt_unware
reprezentuje nieistniejący lub niejednoznaczny czas lokalny (uwaga: w poprzedniej wersji Twojej odpowiedzi nie było takiego problemu, gdzielocaltz
był UTC, ponieważ UTC nie ma przejść DSTUżywam tego oświadczenia w Django do konwersji nieświadomego czasu na świadomą:
źródło
Zgadzam się z poprzednimi odpowiedziami i jest w porządku, jeśli możesz zacząć od UTC. Ale myślę, że jest to również częsty scenariusz dla ludzi pracujących z wartością świadomą tz, która ma datę / godzinę, która ma lokalną strefę czasową inną niż UTC.
Gdybyś po prostu używał nazwy, prawdopodobnie można by wywnioskować, że funkcja replace () będzie miała zastosowanie i utworzy odpowiedni obiekt uwzględniający datę i godzinę. Nie o to chodzi.
replace (tzinfo = ...) wydaje się zachowywać losowo . Jest więc bezużyteczny. Nie używaj tego!
localize to właściwa funkcja do użycia. Przykład:
Lub bardziej kompletny przykład:
daje mi wartość strefy czasowej dla aktualnego czasu lokalnego:
źródło
replace(tzinfo=...)
w strefie czasowej innej niż UTC zepsuje twoją datę i godzinę . Mam na przykład-07:53
zamiast-08:00
. Zobacz stackoverflow.com/a/13994611/1224827replace(tzinfo=...)
nieoczekiwanego zachowania?Użyj,
dateutil.tz.tzlocal()
aby uzyskać strefę czasową w użyciudatetime.datetime.now()
idatetime.datetime.astimezone()
:Zauważ, że
datetime.astimezone
najpierw przekształci Twójdatetime
obiekt w UTC, a następnie w strefę czasową, co jest równoznacznedatetime.replace
z wywołaniem z oryginalną informacją o strefie czasowejNone
.źródło
.replace(tzinfo=dateutil.tz.UTC)
.replace(tzinfo=datetime.timezone.utc)
Ten ujednolica @ Sergio i @ unutbu za odpowiedzi . Będzie „po prostu działał” z
pytz.timezone
obiektem lub ciągiem strefy czasowej IANA .Wygląda na to, co należy zrobić
datetime.localize()
(lub.inform()
lub.awarify()
), zaakceptować zarówno łańcuchy, jak i obiekty strefy czasowej dla argumentu tz i ustawić domyślnie na UTC, jeśli nie określono strefy czasowej.źródło
Python 3.9 dodaje
zoneinfo
moduł, więc teraz potrzebna jest tylko standardowa biblioteka!Dołącz strefę czasową:
Dołącz lokalną strefę czasową systemu:
Następnie jest poprawnie konwertowany na inne strefy czasowe:
Lista dostępnych stref czasowych w Wikipedii
Istnieje backport pozwalający na użycie w Pythonie od 3.6 do 3.8 :
Następnie:
źródło
W formie odpowiedzi Unutbu; Stworzyłem moduł narzędziowy, który obsługuje takie rzeczy, z bardziej intuicyjną składnią. Może być instalowany z pipem.
źródło
dla tych, którzy chcą po prostu utworzyć strefę czasową uwzględniającą strefę czasową
źródło
całkiem nowy w Pythonie i napotkałem ten sam problem. Uważam to rozwiązanie za dość proste i dla mnie działa dobrze (Python 3.6):
źródło
Przełączanie między strefami czasowymi
źródło