Kann naive und bewusste datetime.now () <= herausfordern.datetime_end nicht vergleichen

153

Ich versuche, das aktuelle Datum und die aktuelle Uhrzeit mit den in Modellen angegebenen Datums- und Uhrzeitangaben mithilfe von Vergleichsoperatoren zu vergleichen:

if challenge.datetime_start <= datetime.now() <= challenge.datetime_end:

Das Skript fehlerhaft mit:

TypeError: can't compare offset-naive and offset-aware datetimes

Die Modelle sehen folgendermaßen aus:

class Fundraising_Challenge(models.Model):
    name = models.CharField(max_length=100)
    datetime_start = models.DateTimeField()
    datetime_end = models.DateTimeField()

Ich habe auch Django mit Datum und Uhrzeit des Gebietsschemas.

Was ich nicht finden konnte, ist das Format, das Django für DateTimeField () verwendet. Ist es naiv oder bewusst? Und wie kann ich datetime.now () dazu bringen, das Gebietsschema datetime zu erkennen?

sccrthlt
quelle
1
Es gibt eine sehr schöne Bibliothek, mit der man spielen kann: Pendel (ich bin nicht verbunden)
Thomas Decaux

Antworten:

135

Standardmäßig befindet sich das datetimeObjekt naivein Python, daher müssen Sie beide datetimeObjekte entweder naiv oder bewusst machen . Dies kann erfolgen mit:

import datetime
import pytz

utc=pytz.UTC

challenge.datetime_start = utc.localize(challenge.datetime_start) 
challenge.datetime_end = utc.localize(challenge.datetime_end) 
# now both the datetime objects are aware, and you can compare them

Hinweis: Dies würde ein ValueErrorif tzinfoauslösen, das bereits gesetzt ist. Wenn Sie sich nicht sicher sind, verwenden Sie einfach

start_time = challenge.datetime_start.replace(tzinfo=utc)
end_time = challenge.datetime_end.replace(tzinfo=utc)

Übrigens können Sie einen UNIX-Zeitstempel im Objekt datetime.datetime mit den folgenden Zeitzoneninformationen formatieren

d = datetime.datetime.utcfromtimestamp(int(unix_timestamp))
d_with_tz = datetime.datetime(
    year=d.year,
    month=d.month,
    day=d.day,
    hour=d.hour,
    minute=d.minute,
    second=d.second,
    tzinfo=pytz.UTC)
Viren Rajput
quelle
Es heißt: ValueError: Nicht naive Datumszeit (tzinfo ist bereits festgelegt), wenn versucht wird zu berechnen: datetimeStart = utc.localize (herausfordern.datetime_start)
sccrthlt
Ja, es wird ValueError ausgelöst.
Dmitrii Mikhailov
4
Das Ersetzen des tzinfoführt keine Konvertierung durch, wodurch der Vergleich falsch wird.
OrangeDog
+1 dafür. Und mit utc = pytz.utc, um den Pylint-Fehler zu verhindern No value for argument 'dt' in unbound method call (no-value-for-parameter). Pytz Link
Sam
90

datetime.datetime.now ist nicht zeitzonenbewusst.

Django kommt mit einem Helfer dafür, was erfordert pytz

from django.utils import timezone
now = timezone.now()

Sie sollten vergleichen können nowzuchallenge.datetime_start

Alfredo Aguirre
quelle
3
If gibt USE_TZ=Truedann timezone.now()ein zeitzonenbewusstes datetime-Objekt zurück, auch wenn pytzes nicht installiert ist (obwohl die Installation aus anderen Gründen empfohlen werden kann).
JFS
49

Eine Codezeilösung

if timezone_aware_var <= datetime.datetime.now(timezone_aware_var.tzinfo):
    pass #some code

Erklärte Version

# Timezone info of your timezone aware variable
timezone = your_timezone_aware_variable.tzinfo

# Current datetime for the timezone of your variable
now_in_timezone = datetime.datetime.now(timezone)

# Now you can do a fair comparison, both datetime variables have the same time zone
if your_timezone_aware_variable <= now_in_timezone:
    pass #some code

Zusammenfassung

Sie müssen die Zeitzoneninformationen zu Ihrer now()Datumszeit hinzufügen.
Sie müssen jedoch dieselbe Zeitzone der Referenzvariablen hinzufügen . Deshalb habe ich zuerst das tzinfoAttribut gelesen .

ePi272314
quelle
18

Zeitzone deaktivieren. Verwendenchallenge.datetime_start.replace(tzinfo=None);

Sie können auch replace(tzinfo=None)für andere Datums- / Uhrzeitangaben verwenden .

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):
Amin Fathi
quelle
2

Die Art und Weise, wie ich dieses Problem lösen würde, besteht darin, sicherzustellen, dass die beiden Datumszeiten in der richtigen Zeitzone liegen.

Ich kann sehen, dass Sie verwenden, datetime.now()wodurch die aktuelle Uhrzeit des Systems zurückgegeben wird, ohne dass tzinfo eingestellt ist.

tzinfo sind die Informationen, die an eine Datumszeit angehängt sind, um sie über die Zeitzone zu informieren. Wenn Sie eine naive Datumszeit verwenden, müssen Sie im gesamten System konsistent sein. Ich würde nur empfehlen, nur zu verwendendatetime.utcnow()

Da Sie irgendwo eine Datums- und Uhrzeitangabe erstellen, mit der tzinfo verknüpft ist, müssen Sie sicherstellen, dass diese mit der richtigen Zeitzone lokalisiert sind (mit tzinfo verknüpft ist).

Werfen Sie einen Blick auf Delorean , es erleichtert den Umgang mit solchen Dingen erheblich.

myusuf3
quelle
8
Sie sehen dieses Problem auch bei utcnow.
Andy Hayden
0

Es funktioniert von mir. Hier geete ich die erstellte Tabelle datetime und füge 10 Minuten zur datetime hinzu. Später werden abhängig von der aktuellen Zeit Ablaufvorgänge ausgeführt.

from datetime import datetime, time, timedelta
import pytz

10 Minuten zur Datenbank-Datumszeit hinzugefügt

table_datetime = '2019-06-13 07: 49: 02.832969' (Beispiel)

# Added 10 minutes on database datetime
# table_datetime = '2019-06-13 07:49:02.832969' (example)

table_expire_datetime = table_datetime + timedelta(minutes=10 )

# Current datetime
current_datetime = datetime.now()


# replace the timezone in both time
expired_on = table_expire_datetime.replace(tzinfo=utc)
checked_on = current_datetime.replace(tzinfo=utc)


if expired_on < checked_on:
    print("Time Crossed)
else:
    print("Time not crossed ")

Es hat bei mir funktioniert.

Chandan Sharma
quelle
0

Gerade:

dt = datetimeObject.strftime(format) # format = your datetime format ex) '%Y %d %m'
dt = datetime.datetime.strptime(dt,format)

Also mach das:

start_time = challenge.datetime_start.strftime('%Y %d %m %H %M %S')
start_time = datetime.datetime.strptime(start_time,'%Y %d %m %H %M %S')

end_time = challenge.datetime_end.strftime('%Y %d %m %H %M %S')
end_time = datetime.datetime.strptime(end_time,'%Y %d %m %H %M %S')

und dann benutze start_timeundend_time

Harispy
quelle