web-dev-qa-db-fra.com

django 1.4 - Impossible de comparer les dates / heures naïves par rapport à l'offset

Je suis en train de migrer une application de Django 1.2 à 1.4.

J'ai un objet de tâche quotidien qui contient une heure de la journée où cette tâche doit être terminée:

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

Afin de vérifier si une tâche doit encore être complétée aujourd'hui, j'ai le code suivant:

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

Cela a bien fonctionné sous 1.2, mais sous 1.4 j'ai l'erreur:

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

en raison de la ligne

if timeDue<now and timeDue>dailyTask.last_completed

et les deux clauses de comparaison jettent cette erreur.

J'ai essayé de rendre le fuseau horaire timeDue conscient en ajoutant pytz.UTC comme argument, mais cela pose toujours la même erreur.

J'ai lu certaines de ces docs sur les fuseaux horaires, mais je ne sais pas si je dois juste informer le fuseau horaire timeDue ou si je dois apporter un changement fondamental à ma base de données et à mes données existantes.

81
meepmeep

Vérifiez le document complet pour plus de détails.

Normalement, utilisez Django.utils.timezone.now Pour créer une date/heure actuelle avec décalage

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

Et Django.utils.timezone.make_aware Pour créer une date/heure avec décalage

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

Vous pouvez ensuite comparer les deux dates/heures sensibles à l'offset sans problème.

En outre, vous pouvez convertir une date/heure décalée en une date/heure naïve en supprimant les informations de fuseau horaire, puis comparer le résultat avec la fonction normale datetime.datetime.now(), sous 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 Est True 'par défaut' (en fait c'est False par défaut, mais le fichier settings.py Généré par Django-admin.py startproject L'a réglé sur True), si votre base de données prend en charge les heures prenant en compte les fuseaux horaires, les valeurs des champs de modèle temporels seront celles-ci. vous pouvez le désactiver en définissant USE_TZ=False (ou simplement en supprimant USE_TZ=True) dans les paramètres.

162
okm