2013-03-09 9 views
61

sto cercando di confrontare la data e l'ora correnti con le date e gli orari specificati nei modelli utilizzando gli operatori di confronto:non si può paragonare datetime.now ingenuo e consapevoli() <= challenge.datetime_end

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

Lo script errori fuori con:

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

I modelli simile a questa:

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

devo anche Django utilizzando locale data e orari

Quello che non è stato possibile trovare è il formato che django utilizza per DateTimeField(). È ingenuo o consapevole? E come posso ottenere datetime.now() per riconoscere le impostazioni locali del datetime?

+2

http://stackoverflow.com/questions/10652819/django-1-4-cant-compare-offset-naive-and-offset-aware-datetimes – catherine

+2

possibile duplicato del [non può sottrarre Offset- datazioni naive e offset-aware] (http://stackoverflow.com/questions/796008/cant-subtract-offset-naive-and-offset-aware-datetimes) – user1023979

risposta

46

Per impostazione predefinita, l'oggetto datetime è naive in Python, quindi è necessario rendere entrambi ingenui o consapevoli datetime oggetti. Questo può essere fatto utilizzando:

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: Questo potrebbe sollevare un ValueError se tzinfo è già impostato. Se non sei sicuro di questo, basta usare

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

BTW, è possibile formattare un timestamp di UNIX in datetime.datetime oggetto con informazioni fuso orario come segue

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

Dice: ValueError: Non datetime datetime (tzinfo è già impostato) quando tenta di calcolare: datetimeStart = utc.localize (challenge.datetime_start) – Scott

+0

sì, solleva ValueError. –

+0

Ho aggiornato la risposta –

49

datetime.datetime.now non è a conoscenza di fuso orario.

Django è dotato di un aiuto per questo, che richiede pytz

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

Si dovrebbe essere in grado di confrontare now-challenge.datetime_start

+1

Se 'USE_TZ = True',' timezone.now() 'restituisce un oggetto datetime timezone-aware anche se' pytz' non è installato (sebbene potrebbe essere consigliato l'installazione per altri motivi). – jfs

2

Quindi il modo vorrei risolvere questo problema è quello di assicurarsi che i due datetimes sono nel giusto fuso orario.

Vedo che si sta usando datetime.now() che restituirà l'ora corrente ai sistemi, senza set tzinfo.

tzinfo è l'informazione associata a un datetime per informarlo sul fuso orario in cui si trova. Se si utilizza Datatime naive è necessario essere coerenti attraverso il proprio sistema. Consiglio vivamente di utilizzare solo datetime.utcnow()

visto che da qualche parte si sta creando un datetime a cui è associato tzinfo, è necessario assicurarsi che siano localizzati (con tzinfo associato) al fuso orario corretto.

Dai uno sguardo allo Delorean, è molto più semplice gestire questo genere di cose.

+3

Si vede anche questo problema con utcnow. –

22

Una linea di soluzione di codice

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

spiegato versione:

# 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 

Sommario:
È necessario aggiungere le informazioni fuso orario al vostro now() datetime.
Tuttavia, è necessario aggiungere lo stesso fuso orario della variabile di riferimento; questo è il motivo per cui leggo per la prima volta l'attributo tzinfo.

0

Disabilitare il fuso orario. Usa challenge.datetime_start.replace(tzinfo=None);

È inoltre possibile utilizzare replace(tzinfo=None) per altri datetime.

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