django 1.4 - non è possibile confrontare datetime offset-naive e offset-aware


86

Sto migrando un'applicazione da django 1.2 a 1.4.

Ho un oggetto attività quotidiana che contiene un'ora del giorno in cui l'attività dovrebbe essere completata:

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']

Per verificare se un'attività deve ancora essere completata oggi, ho il seguente codice:

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

Questo ha funzionato bene sotto 1.2, ma sotto 1.4 ottengo l'errore:

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

a causa della linea

if timeDue<now and timeDue>dailyTask.last_completed

ed entrambe le clausole di confronto generano questo errore.

Ho provato a rendere consapevole del fuso orario timeDue aggiungendo pytz.UTC come argomento, ma questo solleva ancora lo stesso errore.

Ho letto alcuni documenti sui fusi orari, ma sono confuso se devo solo rendere consapevole del fuso orario timeDue o se devo apportare una modifica fondamentale al mio database e ai dati esistenti.

Risposte:


170

Controllare il documento completo per informazioni dettagliate.

Normalmente, utilizzare django.utils.timezone.nowper creare un datetime corrente che riconosce lo scostamento

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

E django.utils.timezone.make_awareper creare un datetime in grado di riconoscere l'offset

>>> 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>)

È quindi possibile confrontare senza problemi entrambi i datetime in base all'offset.

Inoltre, puoi convertire datetime offset-awared in datetime offset-naive rimuovendo le informazioni sul fuso orario, quindi potrebbe essere confrontato con normale datetime.datetime.now(), sotto utc.

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

USE_TZè True'per impostazione predefinita' (in realtà è Falseper impostazione predefinita, ma il settings.pyfile generato da django-admin.py startprojectimpostarlo su True), quindi se il tuo DB supporta tempi sensibili al fuso orario, i valori dei campi del modello relativi al tempo saranno consapevoli del fuso orario. puoi disabilitarlo impostando USE_TZ=False(o semplicemente rimuovendo USE_TZ=True) nelle impostazioni.


4
Django non memorizza i tempi di rilevamento per TimeField, lo fa solo per DateTimeField. È davvero fastidioso, poiché l'oggetto datetime.time python supporta TZINFO proprio come gli oggetti datetime.datetime. Mi chiedo che lo risolveranno nella prossima versione. Btw l'ho testato sul server database Postres 9.1.
tejinderss

@tejinderss: datetime.timeè sbagliato. Non ha senso memorizzare il 'Asia/Shanghai'fuso orario se non si conosce la data (l'offset utc potrebbe essere diverso per la stessa ora ma in date diverse).
jfs

@okm: make_aware(datetime.now(), get_default_timezone())fallisce se è get_default_timezone()diverso dal tuo fuso orario locale (dovrebbe esserlo ma non è completamente affidabile). Basta usare timezone.now()invece (è consapevole del fuso orario se lo USE_TZè True).
jfs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.