Warum enthält datetime.datetime.utcnow () keine Zeitzoneninformationen?

285
datetime.datetime.utcnow()

Warum gibt es datetimehier keine Zeitzoneninformationen, da es sich explizit um eine UTC handelt datetime?

Ich würde erwarten, dass dies enthalten würde tzinfo.

Vitaly Babiy
quelle
Wie konvertiere ich ein normales Datumsfeld im ISO-Format vom Typ string in das utc-Format?
Navi

Antworten:

192

Das heißt, es ist zeitzonennaiv, sodass Sie es nicht mit verwenden können datetime.astimezone

Sie können ihm eine Zeitzone wie diese geben

import pytz  # 3rd party: $ pip install pytz

u = datetime.utcnow()
u = u.replace(tzinfo=pytz.utc) #NOTE: it works only with a fixed utc offset

Jetzt können Sie die Zeitzonen ändern

print(u.astimezone(pytz.timezone("America/New_York")))

Um die aktuelle Zeit in einer bestimmten Zeitzone abzurufen, können Sie tzinfo datetime.now()direkt an Folgendes übergeben :

#!/usr/bin/env python
from datetime import datetime
import pytz # $ pip install pytz

print(datetime.now(pytz.timezone("America/New_York")))

Es funktioniert für jede Zeitzone, einschließlich derer, die die Sommerzeit (DST) einhalten, dh es funktioniert für Zeitzonen, die zu unterschiedlichen Zeiten unterschiedliche UTC-Offsets aufweisen können (nicht fester UTC-Offset). Nicht verwenden tz.localize(datetime.now())- es kann während des Übergangs am Ende der Sommerzeit fehlschlagen, wenn die Ortszeit nicht eindeutig ist.

John La Rooy
quelle
216
Aber es gibt keinen guten Grund dafür, dass es zeitzonennaiv ist - es ist UTC. Warum müssen Sie eine Bibliothek eines Drittanbieters durchsuchen, damit sie ordnungsgemäß funktioniert?
Mark Ransom
4
Genau; Für mich sind "naive" Zeiten völlig nutzlos. Derzeit wird auf der Python-Liste diskutiert, ob der stdlib Pytz hinzugefügt werden soll. Das Problem ist nicht die Lizenzierung, sondern die Tatsache, dass die Zeitzonendaten so oft aktualisiert werden (was Python selbst nicht sein kann). Außerdem implementiert pytz die tzinfo-Schnittstelle nicht in der erwarteten Weise, sodass Fehler auftreten können, wenn Sie versuchen, einige der Zeitzonen der Stadt zu verwenden astimezone. Datetime hat also nicht nur keine nativen Zeitzonen, sondern die einzige weit verbreitete Implementierung von tzinfo entspricht nicht dem vermeintlichen Standard.
Bobince
5
@bobince Warum funktionieren Pytz und die Standard-Datetime-Bibliotheken nicht für Sie? Der Python-Kern und der Pytz, die sich als unabhängige Projekte entwickeln, reduzieren die logistische Komplexität für das Kernteam. Ja, die Reduzierung der Komplexität für das Python-Kernteam erhöht die Komplexität für alle Python-Benutzer, die sich mit Zeitzonen befassen müssen. Ich vertraue jedoch darauf, dass sie diese Entscheidung aus gutem Grund getroffen haben. Die Regel "Die Standardbibliothek hat keine tzinfo-Instanzen ..." ist großartig, weil es einfach ist. Warum hier eine Ausnahme machen?
Derek Litz
15
Wie wäre es nuru=datetime.now(pytz.utc)
Craig McQueen
4
@bain: nicht benutzen tz.localize(datetime.now()); Verwenden Sie datetime.now(tz)stattdessen.
JFS
142

Beachten Sie, dass das datetimeModul ab Python 3.2 enthält datetime.timezone. Die Dokumentation für datetime.utcnow()sagt:

Eine bekannte aktuelle UTC-Uhrzeit kann durch Aufrufen abgerufen werden .datetime.now(timezone.utc)

So können Sie tun:

>>> import datetime
>>> datetime.datetime.now(datetime.timezone.utc)
datetime.datetime(2014, 7, 10, 2, 43, 55, 230107, tzinfo=datetime.timezone.utc)
Craig McQueen
quelle
2
Welches ist bevorzugt? datetime.now(timezone.utc)oder datetime.utcnow(timezone.utc)?
Jesse Webb
8
datetime.utcnow()nimmt keine Argumente. So müsste es sein datetime.now(timezone.utc).
Craig McQueen
1
datetime.now()gibt die Maschinenzeit zurück, datetime.utcnow()gibt aber die tatsächliche UTC-Zeit zurück.
Babu
13
@Babu: Zeigt datetime.utcnow()nicht tzinfoan, dass es sich um UTC handelt. Gibt datetime.now(datetime.timezone.utc)aber die UTC-Zeit mit tzinfo set zurück.
Craig McQueen
@CraigMcQueen Wenn wir also ein tzObjekt im now-Konstruktor übergeben, wird die Zeit dieser Zeitzone zurückgegeben? OK! Vielen Dank für den Hinweis.
Babu
71

Die Standard-Python-Bibliotheken enthalten keine tzinfo-Klassen ( siehe jedoch S. 431 ). Ich kann nur die Gründe erraten. Persönlich denke ich, dass es ein Fehler war, keine tzinfo-Klasse für UTC aufzunehmen, da diese unumstritten genug ist, um eine Standardimplementierung zu haben.

Bearbeiten: Obwohl es keine Implementierung in der Bibliothek gibt, wird in der tzinfoDokumentation eine als Beispiel angegeben .

from datetime import timedelta, tzinfo

ZERO = timedelta(0)

# A UTC class.

class UTC(tzinfo):
    """UTC"""

    def utcoffset(self, dt):
        return ZERO

    def tzname(self, dt):
        return "UTC"

    def dst(self, dt):
        return ZERO

utc = UTC()

So verwenden Sie es, um die aktuelle Uhrzeit als bewusstes Datum / Uhrzeit-Objekt abzurufen:

from datetime import datetime 

now = datetime.now(utc)

Es gibt datetime.timezone.utcin Python 3.2+:

from datetime import datetime, timezone 

now = datetime.now(timezone.utc)
Mark Ransom
quelle
8
Finden Sie heraus, warum diese Klasse überhaupt nicht bereitgestellt wurde (und, was noch wichtiger ist, für datetimeObjekte verwendet wurde, die von erstellt wurden utcnow()) ...
André Caron
17
Das Zeitzonenobjekt timezone.utcwurde schließlich zu Python 3.2 hinzugefügt. Gibt aus Gründen der Abwärtskompatibilität utcnow()immer noch ein zeitzonenloses Zeitobjekt zurück, aber Sie können das, was Sie möchten, durch Aufrufen erhalten now(timezone.utc).
Mhsmith
4
@rgove, das ist die Art der Korrektur von Fehlern, die für Python 3 ein faires Spiel sein sollte. Sie hätten sich keine Sorgen um die Abwärtskompatibilität machen sollen. Es gibt ein weiteres Beispiel, das ich in den letzten Tagen gelesen habe: Das structModul hat automatische Konvertierungen von Unicode zu Bytestring durchgeführt, und die endgültige Entscheidung war, die Kompatibilität mit früheren Python 3-Versionen zu unterbrechen, um zu verhindern, dass eine schlechte Entscheidung getroffen wird.
Mark Ransom
2
Ich bin verblüfft, dass die Python- tzinfoDokumentation Beispiele für Code zur Implementierung enthält, aber diese Funktionalität ist in datetime selbst nicht enthalten! docs.python.org/2/library/datetime.html#datetime.tzinfo.fromutc
LS
1
@ LS ja, pytzist eine großartige Ressource. Als ich meine Antwort bearbeitet hatte, um sie in den Beispielcode einzufügen, hatte es bereits jemand anderes vorgeschlagen, und ich wollte ihren Donner nicht stehlen.
Mark Ransom
20

Das pytzModul ist eine Option, und es gibt eine andere python-dateutil, die zwar ebenfalls ein Paket eines Drittanbieters ist, jedoch abhängig von Ihren anderen Abhängigkeiten und Ihrem Betriebssystem möglicherweise bereits verfügbar ist.

Ich wollte diese Methode nur als Referenz aufnehmen. Wenn Sie sie bereits python-dateutilfür andere Zwecke installiert haben , können Sie sie verwenden, tzinfoanstatt sie zu duplizierenpytz

import datetime
import dateutil.tz

# Get the UTC time with datetime.now:
utcdt = datetime.datetime.now(dateutil.tz.tzutc())

# Get the UTC time with datetime.utcnow:
utcdt = datetime.datetime.utcnow()
utcdt = utcdt.replace(tzinfo=dateutil.tz.tzutc())

# For fun- get the local time
localdt = datetime.datetime.now(dateutil.tz.tzlocal())

Ich stimme eher zu, dass Anrufe an utcnowdie UTC-Zeitzoneninformationen enthalten sollten. Ich vermute, dass dies nicht enthalten ist, da die native datetime-Bibliothek aus Gründen der Kreuzkompatibilität standardmäßig naive datetimes verwendet.

bbengfort
quelle
1
NameError: Name 'dt' ist nicht definiert
xApple
Ich habe den Aufruf datetime.datetime.utcfromtimestamp () verwendet und musste tzinfo hinzufügen. Die zweite Lösung hat für mich funktioniert: utcdt = datetime.datetime.utcfromtimestamp(1234567890).replace(dateutil.tz.tzutc())
Ian Lee
1
Hinweis: im Gegensatz dazu datetime.now(pytz_tz)funktioniert immer; datetime.now(dateutil.tz.tzlocal())kann während der Sommerzeitübergänge fehlschlagen . PEP 495 - Lokale Zeitdisambiguierung könnte die dateutilSituation in Zukunft verbessern .
JFS
@IanLee: Sie könnten verwenden utc_dt = datetime.fromtimestamp(1234567890, dateutil.tz.tzutc())(Hinweis: dateutilWenn ein nicht fester utc-Offset (z. B. dateutil.tz.tzlocal()) hier fehlschlägt , verwenden Sie stattdessen eine pytzLösung auf Basis ).
JFS
Da mein Programm bereits den Import dateutilfür dateutil.parsermochte ich diese Lösung am besten. Es war so einfach wie : utcCurrentTime = datetime.datetime.now(tz=dateutil.tz.tzutc()). Viola!!
LS
11

Julien Danjou hat einen guten Artikel geschrieben, in dem erklärt wird, warum Sie sich niemals mit Zeitzonen befassen sollten . Ein Ausschnitt:

In der Tat gibt die Python-Datetime-API immer unbekannte Datetime-Objekte zurück, was sehr unglücklich ist. Sobald Sie eines dieser Objekte erhalten, können Sie die Zeitzone nicht mehr kennen. Daher sind diese Objekte für sich genommen ziemlich "nutzlos".

Leider utcnow()werden die Zeitzoneninformationen, wie Sie festgestellt haben , auch dann nicht angezeigt, wenn Sie sie verwenden .

Empfehlungen:

  • Verwenden Sie immer bewusste datetimeObjekte, dh mit Zeitzoneninformationen. Dadurch wird sichergestellt, dass Sie sie direkt vergleichen können (bewusste und unbewusste datetime Objekte sind nicht vergleichbar) und sie korrekt an Benutzer zurückgeben. Leverage pytz zu Zeitzone Objekte.

  • Verwenden Sie ISO 8601 als Eingabe- und Ausgabezeichenfolgenformat. Verwenden Sie datetime.datetime.isoformat()diese Option, um Zeitstempel als Zeichenfolge zurückzugeben, die mit diesem Format formatiert ist, das die Zeitzoneninformationen enthält.

  • Wenn Sie Zeichenfolgen mit ISO 8601-formatierten Zeitstempeln analysieren müssen, können Sie sich darauf verlassen iso8601, dass Zeitstempel mit korrekten Zeitzoneninformationen zurückgegeben werden. Dies macht Zeitstempel direkt vergleichbar.

Joe D'Andrea
quelle
1
Dies ist eine leicht irreführende Empfehlung. Als Faustregel gilt: Niemals mit Zeitzonen umgehen. Speichern und übertragen Sie immer tz unware utc-Objekte (Epochenobjekte). Die Zeitzone sollte nur zum Zeitpunkt der Darstellung in der Benutzeroberfläche berechnet werden
nehem
1
Das hört sich so an, als würde es schon ganz gut zu Juliens Gedanken passen. Welche seiner spezifischen Empfehlungen (wie oben erwähnt) sind irreführend?
Joe D'Andrea
10

So fügen Sie timezoneInformationen in Python 3.2+ hinzu

import datetime

>>> d = datetime.datetime.now(tz=datetime.timezone.utc)
>>> print(d.tzinfo)
'UTC+00:00'
nordborn
quelle
1
AttributeError: 'module' object has no attribute 'timezone' Python 2.7.13 (Standard, 19. Januar 2017, 14:48:08)
Marcin Owsiany
-6
from datetime import datetime 
from dateutil.relativedelta import relativedelta
d = datetime.now()
date = datetime.isoformat(d).split('.')[0]
d_month = datetime.today() + relativedelta(months=1)
next_month = datetime.isoformat(d_month).split('.')[0]
Mrudula Athuluri
quelle
-13

UTC-Daten benötigen keine Zeitzoneninformationen, da sie UTC sind, was per Definition bedeutet, dass sie keinen Versatz haben.

Ignacio Vazquez-Abrams
quelle
10
Soweit ich aus docs.python.org/library/datetime.html ersehen kann , ist eine Datumszeit ohne tzinfo eine Zeit, in der die Zeitzone nicht angegeben ist. Hier ist die Zeitzone hat angegeben, so logisch sollte vorhanden sein. Es gibt einen großen Unterschied zwischen einem Datum / einer Uhrzeit ohne zugehörige Zeitzone und einem Datum, das definitiv in UTC angegeben ist. (Idealerweise sollten sie verschiedene IMO-Typen sein, aber das ist eine andere Sache ...)
Jon Skeet
@ JonSkeet Ich denke, Sie vermissen Ignacios Argument, dass UTC keine Zeitzone ist. Erstaunlich, dass diese Antwort -9 Punkte hat, während ich dies
CS
3
@CS: Nun, Ignacio hat das nie gesagt ... und obwohl UTC streng genommen keine Zeitzone ist, wird es normalerweise als eine Zeitzone behandelt , um das Leben erheblich zu vereinfachen (auch in Python, z pytz.utc. B. mit ). Beachten Sie, dass es einen großen Unterschied zwischen einem Wert gibt, dessen Versatz von UTC unbekannt ist, und einem Wert, bei dem bekannt ist, dass er 0 ist. Letzteres utcnow() sollte IMO zurückgeben. Dies würde gemäß der Dokumentation zu "Ein bewusstes Objekt wird verwendet, um einen bestimmten Zeitpunkt darzustellen, der nicht interpretiert werden kann" passen.
Jon Skeet