82 votes

django 1.4 - Impossible de comparer les dates offset-naive et offset-aware

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

J'ai un objet de tâche quotidienne qui contient une heure de la journée à laquelle la tâche doit être effectué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 effectué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 la version 1.2, mais sous la version 1.4, j'obtiens l'erreur suivante :

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 provoquent cette erreur.

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

J'ai lu une partie de la documentation sur les fuseaux horaires, mais je ne sais pas si je dois simplement faire en sorte que timeDue tienne compte des fuseaux horaires, ou si je dois apporter un changement fondamental à ma base de données et aux données existantes.

Aide appréciée !

165voto

okm Points 12374

Vérifiez le document de fond pour des informations détaillées.

Normalement, il faut utiliser django.utils.timezone.now pour faire une date courante sensible au 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 faire une date sensible au 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 pourriez alors comparer sans problème les deux datations avec décalage.

De plus, vous pourriez convertir une date décalée par rapport à l'année précédente en une date décalée par rapport à l'année précédente en supprimant l'information sur le fuseau horaire, puis la comparer avec une date 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 es True par défaut" (en fait, c'est False par défaut, mais le settings.py généré par django-admin.py startproject le régler sur True ), si votre base de données prend en charge la prise en compte du fuseau horaire, les valeurs des champs de modèle liés à l'heure seront prises en compte dans le fuseau horaire. Vous pouvez le désactiver en définissant le paramètre USE_TZ=False (ou simplement supprimer USE_TZ=True ) dans les paramètres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X