No se puede comparar datetime.now() ingenuo y consciente

6 minutos de lectura

avatar de usuario
sccrtlt

Estoy tratando de comparar la fecha y hora actuales con las fechas y horas especificadas en los modelos usando 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 la fecha y hora locales.

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

  • stackoverflow.com/questions/10652819/…

    – catalina

    9 de marzo de 2013 a las 5:50

  • posible duplicado de No se pueden restar las fechas y horas ingenuas y conscientes de las compensaciones

    – Fénix

    09/04/2015 a las 16:27

  • hay una biblioteca muy buena para jugar con fecha: péndulo (no estoy afiliado)

    – Thomas Decaux

    8 oct 2018 a las 10:36

avatar de usuario
viren rajput

Por defecto, el datetime el objeto es naive en Python, por lo que debe hacer que ambos sean ingenuos o conscientes datetime objetos. 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 ValueError si tzinfo ya está configurado. Si no está seguro de eso, simplemente use

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)

  • Dice: ValueError: fecha y hora no ingenua (tzinfo ya está configurado) cuando intenta calcular: datetimeStart = utc.localize(challenge.datetime_start)

    – sccrthlt

    9 de marzo de 2013 a las 6:40

  • sí, plantea ValueError.

    – Dmitrii Mikhailov

    28 de julio de 2015 a las 17:47

  • Reemplazo de la tzinfo no realiza ninguna conversión, por lo que la comparación es incorrecta.

    – perro naranja

    28 de noviembre de 2017 a las 13:25

  • +1 por esto. y, usando utc = pytz.utc para evitar el error de pylint No value for argument 'dt' in unbound method call (no-value-for-parameter). enlace pytz

    – Sam

    5 de julio de 2018 a las 19:47


  • Puedes obtener utc zona horaria de datetime‘s timezone módulo. timezone.utc.

    – mjuoperi

    20 oct 2021 a las 17:38

datetime.datetime.now no es consciente de la zona horaria.

Django viene con un ayudante para esto, que requiere pytz

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

Deberías poder comparar now a challenge.datetime_start

  • Si USE_TZ=True después timezone.now() devuelve un objeto de fecha y hora consciente de la zona horaria, incluso si pytz no está instalado (aunque podría recomendarse instalarlo por otras razones).

    – jfs

    13 de enero de 2016 a las 10:31

  • Esta debería ser la respuesta aceptada.

    – Progreso de AD

    14 abr a las 22:28

avatar de usuario
ePi272314

Una línea de solución 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, debe agregar la mismo zona horaria de la variable de referencia; por eso leí por primera vez el tzinfo atributo.

  • Este parece ser el enfoque más lógico, ¡gracias!

    – bcelery

    21 de mayo de 2021 a las 13:08

avatar de usuario
Amin Fati

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

También puedes usar replace(tzinfo=None) por otro fecha y hora.

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

sin terceros, solo el módulo nativo de fecha y hora.

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)

  • ¿Cómo harías que esto funcione con datetime.now()?

    – jtlz2

    8 de septiembre de 2021 a las 8:26

  • +muchas para librerías de terceros no requeridas!!

    – jtlz2

    2 de noviembre de 2021 a las 9:22

  • @ jtlz2, usarías datetime.now().replace(tzinfo=timezone(offset=timedelta()))

    – Jorge V. Reilly

    27 de enero a las 4:18

avatar de usuario
Chandan Sharma

Está trabajando desde mí. Aquí obtengo la fecha y hora de creación de la tabla y agrego 10 minutos en la fecha y hora. más tarde, dependiendo de la hora actual, se realizan las operaciones de caducidad.

from datetime import datetime, time, timedelta
import pytz

Se agregaron 10 minutos en la fecha y hora de la base de datos

table_datetime=”2019-06-13 07:49:02.832969″ (ejemplo)

# Added 10 minutes on database datetime
# table_datetime="2019-06-13 07:49:02.832969" (example)

table_expire_datetime = table_datetime + timedelta(minutes=10 )

# Current datetime
current_datetime = datetime.now()


# replace the timezone in both time
expired_on = table_expire_datetime.replace(tzinfo=utc)
checked_on = current_datetime.replace(tzinfo=utc)


if expired_on < checked_on:
    print("Time Crossed)
else:
    print("Time not crossed ")

Funcionó para mí.

  • ¿Cómo harías que esto funcione con datetime.now()?

    – jtlz2

    8 de septiembre de 2021 a las 8:26

  • +muchas para librerías de terceros no requeridas!!

    – jtlz2

    2 de noviembre de 2021 a las 9:22

  • @ jtlz2, usarías datetime.now().replace(tzinfo=timezone(offset=timedelta()))

    – Jorge V. Reilly

    27 de enero a las 4:18

avatar de usuario
myusuf3

Entonces, la forma en que resolvería este problema es asegurarme de que las dos fechas y horas estén en la zona horaria correcta.

Puedo ver que estás usando datetime.now() que devolverá la hora actual del sistema, sin configurar tzinfo.

tzinfo es la información adjunta a una fecha y hora para que sepa en qué zona horaria se encuentra. Si está utilizando una fecha y hora ingenua, debe ser coherente en todo su sistema. Recomiendo encarecidamente usar solo datetime.utcnow()

viendo que en algún lugar está creando una fecha y hora que tiene tzinfo asociado, lo que debe hacer es asegurarse de que estén localizados (tiene tzinfo asociado) en la zona horaria correcta.

Echa un vistazo a Deloreanhace que lidiar con este tipo de cosas sea mucho más fácil.

  • También ve este problema con utcnow.

    –Andy Hayden

    16/10/2016 a las 21:20

  • secundado. utcnow no agregará información de zona horaria

    – Kyle

    30 de agosto de 2021 a las 19:27

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad