web-dev-qa-db-fra.com

Impossible de comparer datetime.now () naïf et conscient () <= challenge.datetime_end

J'essaie de comparer la date et l'heure actuelles avec les dates et heures spécifiées dans les modèles à l'aide d'opérateurs de comparaison:

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

Le script fait une erreur avec:

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

Les modèles ressemblent à ceci:

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

J'ai aussi Django en utilisant la date et l'heure locales.

Ce que je n'ai pas réussi à trouver, c'est le format utilisé par Django pour DateTimeField (). Est-ce naïf ou conscient? Et comment puis-je obtenir que datetime.now () reconnaisse les paramètres régionaux datetime?

111
Scott

Par défaut, l'objet datetime est naive en Python. Vous devez donc définir les deux objets naïfs ou conscients datetime. Cela peut être fait en utilisant:

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

Remarque: Cela déclencherait une ValueError si tzinfo est déjà défini. Si vous n'êtes pas sûr de cela, utilisez simplement

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

En passant, vous pouvez formater un horodatage UNIX dans l'objet datetime.datetime avec les informations de fuseau horaire comme suit

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)
89
Viren Rajput

datetime.datetime.now n'est pas sensible au fuseau horaire.

Django vient avec une aide pour cela, ce qui nécessite pytz

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

Vous devriez pouvoir comparer now à challenge.datetime_start

73
Alfredo Aguirre

ne ligne de solution de code

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

Version expliquée:

# 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

Sommaire:
Vous devez ajouter les informations de fuseau horaire à votre now() datetime.
Cependant, vous devez ajouter le fuseau horaire identique de la variable de référence; c'est pourquoi j'ai d'abord lu l'attribut tzinfo.

35
ePi272314

Désactiver le fuseau horaire. Utiliser challenge.datetime_start.replace(tzinfo=None);

Vous pouvez également utiliser replace(tzinfo=None) pour d'autres date/heure.

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

Donc, la façon dont je réglerais ce problème est de m'assurer que les deux dates sont dans le bon fuseau horaire.

Je peux voir que vous utilisez datetime.now() qui renverra l'heure actuelle du système, sans définir tzinfo.

tzinfo est l’information attachée à une date/heure pour lui permettre de savoir dans quel fuseau horaire il se trouve. Si vous utilisez une date/heure naïve, vous devez être cohérent sur l'ensemble de votre système. Je recommande fortement d'utiliser uniquement datetime.utcnow()

étant donné que tzinfo est associé à certains moments de la création de l'heure-heure, veillez à ce que ceux-ci soient localisés (avec tzinfo associé) dans le fuseau horaire correspondant.

Jetez un oeil à Delorean , cela facilite beaucoup le travail avec ce genre de chose.

3
myusuf3

Cela fonctionne de moi. Ici, je vais chercher la table créée datetime et ajouter 10 minutes à la date/heure. plus tard, en fonction de l'heure actuelle, les opérations d'expiration sont effectuées.

from datetime import datetime, time, timedelta
import pytz

Ajout de 10 minutes sur la base de données datetime

table_datetime = '2019-06-13 07: 49: 02.832969' (exemple)

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

Cela a fonctionné pour moi.

0
Chandan Sharma