2013-03-09 2 views
61

Я пытаюсь сравнить текущую дату и время с датой и времени, указанная в моделях с использованием операторов сравнения:Не может сравнить наивный и осведомленный DateTime.Now() <= challenge.datetime_end

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

Сценарий ошибки с помощью:

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

модели выглядят следующим образом:

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

Я также Джанго, используя локаль дату и время.

То, что я не смог найти, - это формат, используемый django для DateTimeField(). Это наивно или известно? И как мне получить datetime.now() для распознавания даты и времени локали?

+2

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

+2

возможно дубликат [Не можете вычесть offset- наивные и средние значения времени] (http://stackoverflow.com/questions/796008/cant-subtract-offset-naive-and-offset-aware-datetimes) – user1023979

ответ

46

По умолчанию объект datetime является naive в Python, поэтому вам нужно сделать обе из них либо наивными, либо известными datetime объектов. Это может быть сделано с помощью:

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 

Примечание: Это приподнять ValueError если tzinfo уже установлен. Если вы не уверены в том, что, просто использовать

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

BTW, вы можете форматировать метку времени UNIX в datetime.datetime объекта с временной зоны информации следующим образом

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

В нем говорится: ValueError: не наивное datetime (tzinfo уже установлен), когда он пытается вычислить: datetimeStart = utc.localize (challenge.datetime_start) – Scott

+0

yep, он вызывает ValueError. –

+0

Я обновил ответ –

49

datetime.datetime.now не TIMEZONE известно.

Django поставляется с помощником для этого, который требует pytz

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

Вы должны быть в состоянии сравнить now с challenge.datetime_start

+1

Если 'USE_TZ = True', то' timezone.now() 'возвращает объект datetime, соответствующий периоду времени, даже если' pytz' не установлен (хотя его можно было бы установить по другим причинам). – jfs

2

Так как я бы решить эту проблему, чтобы убедиться, что два DateTimes находятся в правильном часовом поясе.

Я вижу, что вы используете datetime.now(), который вернет системное время, без набора tzinfo.

tzinfo - это информация, привязанная к дате времени, чтобы сообщить ей, в какой временной зоне она находится. Если вы используете наивное datetime, вам нужно быть последовательным в вашей системе. Я бы очень рекомендовал использовать только datetime.utcnow()

Как видите, где-то вы создаете дату и время, связанное с ними tzinfo, то, что вам нужно сделать, это убедиться, что они локализованы (привязаны tzinfo) к правильному часовому поясу.

Взгляните на Delorean, он делает сделку с таким видом намного проще.

+3

Вы также видите эту проблему с utcnow. –

22

Одна строка кода решения

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

Разъяснения версия:

# 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 

Резюме:
Вы должны добавить информацию временной зоны для вашей now() DateTime.
Тем не менее, вы должны добавить тот же самый часовой пояс ссылочной переменной; поэтому я сначала прочитал атрибут tzinfo.

0

Отключить часовой пояс. Использование challenge.datetime_start.replace(tzinfo=None);

Вы также можете использовать replace(tzinfo=None) для других DateTime.

if challenge.datetime_start.replace(tzinfo=None) <= datetime.now().replace(tzinfo=None) <= challenge.datetime_end.replace(tzinfo=None): 
Смежные вопросы