django 1.4: no se pueden comparar fechas y horas con compensación ingenua y con compensación

85

Estoy en el proceso de migrar una aplicación de django 1.2 a 1.4.

Tengo un objeto de tarea diaria que contiene una hora del día en la que se debe completar la tarea:

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

Para verificar si aún se requiere completar una tarea hoy, tengo el siguiente código:

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

Esto funcionó bien en 1.2, pero en 1.4 aparece el error:

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

debido a la linea

if timeDue<now and timeDue>dailyTask.last_completed

y ambas cláusulas de comparación arrojan este error.

He intentado hacer que timeDue sea consciente de la zona horaria agregando pytz.UTC como argumento, pero esto aún genera el mismo error.

He leído algunos de los documentos sobre zonas horarias, pero estoy confundido sobre si solo necesito hacer que la zona horaria timeDue sea consciente, o si necesito hacer un cambio fundamental en mi base de datos y los datos existentes.

meepmeep
fuente

Respuestas:

168

Consulte el documento completo para obtener información detallada.

Normalmente, se usa django.utils.timezone.nowpara hacer una fecha y hora actual con reconocimiento de compensación

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

Y django.utils.timezone.make_awarepara hacer una fecha y hora que tenga en cuenta la compensación

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

A continuación, puede comparar ambas fechas y horas conscientes de la compensación sin problemas.

Además, podría convertir la fecha y hora compensada en una fecha y hora ingenua eliminando la información de la zona horaria, luego podría compararse con normal datetime.datetime.now(), en utc.

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

USE_TZes True'por defecto' (en realidad lo es Falsepor defecto, pero el settings.pyarchivo generado por django-admin.py startprojectestablecerlo en True), entonces si su base de datos admite horas con reconocimiento de zona horaria, los valores de los campos del modelo relacionados con el tiempo serían conscientes de la zona horaria. puede deshabilitarlo configurándolo USE_TZ=False(o simplemente eliminándolo USE_TZ=True) en la configuración.

OK M
fuente
4
Django no almacena tiempos de reconocimiento para TimeField, solo lo hace para DateTimeField. Es realmente molesto, ya que el objeto python datetime.time admite TZINFO al igual que los objetos datetime.datetime. Me pregunto si lo arreglarían en la próxima versión. Por cierto, lo he probado en el servidor de base de datos postres 9.1.
tejinderss
@tejinderss: datetime.timeestá mal. No tiene sentido almacenar la 'Asia/Shanghai'zona horaria si no conoce la fecha (el desplazamiento de utc puede ser diferente para la misma hora pero en fechas diferentes).
jfs
@okm: make_aware(datetime.now(), get_default_timezone())falla si get_default_timezone()difiere de su zona horaria local (debería serlo, pero no es completamente confiable). Simplemente use timezone.now()en su lugar (es consciente de la zona horaria si lo USE_TZes True).
jfs