No se puede comparar datetime.now() ingenuo y consciente (= desafío.datetime_end)

Resuelto sccrthlt asked hace 11 años • 16 respuestas

Estoy intentando comparar la fecha y hora actuales con las fechas y horas especificadas en los modelos utilizando operadores de comparación:

if challenge.datetime_start <= datetime.now() <= challenge.datetime_end:

El script falla con:

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

Los modelos se ven así:

class Fundraising_Challenge(models.Model):
    name = models.CharField(max_length=100)
    datetime_start = models.DateTimeField()
    datetime_end = models.DateTimeField()

También tengo Django usando fechas y horas locales.

Lo que no he podido encontrar es el formato que usa Django para DateTimeField(). ¿Es ingenuo o consciente? ¿Y cómo consigo que datetime.now() reconozca la fecha y hora local?

sccrthlt avatar Mar 09 '13 12:03 sccrthlt
Aceptado

De forma predeterminada, el datetimeobjeto está naiveen Python, por lo que debes convertirlos en datetimeobjetos ingenuos o conscientes. Esto se puede hacer usando:

import datetime
import pytz

utc=pytz.UTC

challenge.datetime_start = utc.localize(challenge.datetime_start) 
challenge.datetime_end = utc.localize(challenge.datetime_end) 
# now both the datetime objects are aware, and you can compare them

Nota: Esto generaría un error ValueErrorsi tzinfoya está configurado. Si no estás seguro de eso, simplemente usa

start_time = challenge.datetime_start.replace(tzinfo=utc)
end_time = challenge.datetime_end.replace(tzinfo=utc)

Por cierto, puede formatear una marca de tiempo UNIX en el objeto datetime.datetime con información de zona horaria de la siguiente manera

d = datetime.datetime.utcfromtimestamp(int(unix_timestamp))
d_with_tz = datetime.datetime(
    year=d.year,
    month=d.month,
    day=d.day,
    hour=d.hour,
    minute=d.minute,
    second=d.second,
    tzinfo=pytz.UTC)
Viren Rajput avatar Mar 09 '2013 05:03 Viren Rajput

datetime.datetime.nowno tiene en cuenta la zona horaria.

Django viene con un ayudante para esto, que requierepytz

from django.utils import timezone
now = timezone.now()

Deberías poder comparar nowconchallenge.datetime_start

Alfredo Aguirre avatar Mar 09 '2013 09:03 Alfredo Aguirre

Solución de una línea de código

if timezone_aware_var <= datetime.datetime.now(timezone_aware_var.tzinfo):
    pass #some code

Versión explicada

# Timezone info of your timezone aware variable
timezone = your_timezone_aware_variable.tzinfo

# Current datetime for the timezone of your variable
now_in_timezone = datetime.datetime.now(timezone)

# Now you can do a fair comparison, both datetime variables have the same time zone
if your_timezone_aware_variable <= now_in_timezone:
    pass #some code

Resumen

Debe agregar la información de la zona horaria a su now()fecha y hora.
Sin embargo, debes agregar la misma zona horaria de la variable de referencia; por eso leí por primera vez el tzinfoatributo.

ePi272314 avatar Oct 03 '2015 18:10 ePi272314

Desactivar zona horaria. Usarchallenge.datetime_start.replace(tzinfo=None);

También puede utilizarlo replace(tzinfo=None)para otras fechas y horas .

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None):
Amin Fathi avatar Jan 19 '2018 11:01 Amin Fathi

ningún tercero, solo el módulo de fecha y hora nativo.

from datetime import datetime, timedelta, timezone

time1 = datetime.strptime('2021-07-15T00:22:02+0000', '%Y-%m-%dT%H:%M:%S%z')
time2 = datetime(2021, 7, 15, tzinfo=timezone(offset=timedelta()))
if time1 < time2:
    print(True)
ovo avatar Jul 14 '2021 03:07 ovo