django 1.4 - kann keine Offset-naiven und Offset-fähigen Datenzeiten vergleichen

85

Ich bin gerade dabei, eine Anwendung von Django 1.2 auf 1.4 zu migrieren.

Ich habe ein tägliches Aufgabenobjekt, das eine Tageszeit enthält, zu der die Aufgabe ausgeführt werden soll:

class DailyTask(models.Model):
    time = models.TimeField()
    last_completed = models.DateTimeField()
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    weekends = models.BooleanField()

    def __unicode__(self):
        return '%s' % (self.name)

    class Meta:
        db_table = u'dailytask'
        ordering = ['name']

Um zu überprüfen, ob eine Aufgabe heute noch erledigt werden muss, habe ich den folgenden Code:

def getDueDailyTasks():
    dueDailyTasks=[]
    now = datetime.datetime.now()
    try:
        dailyTasks = DailyTask.objects.all()
    except dailyTask.DoesNotExist:
        return None
    for dailyTask in dailyTasks:
        timeDue = datetime.datetime(now.year,now.month,now.day,dailyTask.time.hour,dailyTask.time.minute,dailyTask.time.second)
        if timeDue<now and timeDue>dailyTask.last_completed:
            if dailyTask.weekends==False and now.weekday()>4:
                pass
            else:
                dueDailyTasks.append({'id':dailyTask.id,
                            'due':timeDue,
                             'name': dailyTask.name,
                             'description':dailyTask.description})
    return dueDailyTasks

Dies funktionierte gut unter 1.2, aber unter 1.4 bekomme ich den Fehler:

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

aufgrund der Linie

if timeDue<now and timeDue>dailyTask.last_completed

und beide Vergleichsklauseln lösen diesen Fehler aus.

Ich habe versucht, timeDue timezone durch Hinzufügen von pytz.UTC als Argument bekannt zu machen, aber dies führt immer noch zu demselben Fehler.

Ich habe einige der Dokumente zu Zeitzonen gelesen, bin jedoch verwirrt darüber, ob ich nur die timeDue-Zeitzone bekannt machen muss oder ob ich meine Datenbank und die vorhandenen Daten grundlegend ändern muss.

meep Meep
quelle

Antworten:

168

Überprüfen Sie das ausführliche Dokument auf Detailinformationen.

Normalerweise verwenden Sie django.utils.timezone.nowdiese Option, um eine Offset-fähige aktuelle Datumszeit festzulegen

>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2012, 5, 18, 13, 0, 49, 803031, tzinfo=<UTC>)

Und django.utils.timezone.make_awareum eine Offset-fähige Datums- / Uhrzeitangabe zu erstellen

>>> timezone.make_aware(datetime.datetime.now(), timezone.get_default_timezone())
datetime.datetime(2012, 5, 18, 21, 5, 53, 266396, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)

Sie können dann beide Offset-fähigen Datenzeiten ohne Probleme vergleichen.

Darüber hinaus können Sie die Offset-Awared-Datumszeit in die Offset-naive Datumszeit konvertieren, indem Sie die Zeitzoneninformationen datetime.datetime.now()entfernen. Anschließend können Sie sie unter utc mit normal vergleichen.

>>> t = timezone.now() # offset-awared datetime
>>> t.astimezone(timezone.utc).replace(tzinfo=None)
datetime.datetime(2012, 5, 18, 13, 11, 30, 705324)

USE_TZist True'standardmäßig' (eigentlich ist es Falsestandardmäßig, aber die settings.pyDatei, die durch django-admin.py startprojectSetzen auf generiert wurde True). Wenn Ihre Datenbank zeitzonenbezogene Zeiten unterstützt, sind die Werte zeitbezogener Modellfelder zeitzonenabhängig. Sie können es deaktivieren, indem Sie Einstellungen vornehmen USE_TZ=False(oder einfach entfernen USE_TZ=True).

okm
quelle
4
Django speichert keine bekannten Zeiten für TimeField, sondern nur für DateTimeField. Es ist wirklich ärgerlich, da das Python-Objekt datetime.time TZINFO genau wie die Objekte datetime.datetime unterstützt. Ich frage mich, ob sie das in der nächsten Version beheben würden. Übrigens habe ich es auf postres 9.1 Datenbankserver getestet.
Tejinderss
@tejinderss: datetime.timeist falsch. Es macht keinen Sinn, die 'Asia/Shanghai'Zeitzone zu speichern, wenn Sie das Datum nicht kennen (der UTC-Offset kann für dieselbe Zeit, aber an unterschiedlichen Daten unterschiedlich sein).
JFS
@okm: make_aware(datetime.now(), get_default_timezone())schlägt fehl, wenn es get_default_timezone()von Ihrer lokalen Zeitzone abweicht (es sollte sein, aber es ist nicht vollständig zuverlässig). Verwenden Sie timezone.now()stattdessen einfach (es ist zeitzonenabhängig, wenn dies der Fall USE_TZist True).
JFS