django 1.4 - не вдається порівняти часові дати з урахуванням офсетних та наївних


85

Я переходжу до програми з django 1.2 до 1.4.

У мене є щоденний об’єкт завдання, який містить час доби, яке слід виконати:

class DailyTask(models.Model):
    time = models.TimeField()
    last_completed = models.DateTimeField()
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=1000)
    weekends = models.BooleanField()

    def __unicode__(self):
        return '%s' % (self.name)

    class Meta:
        db_table = u'dailytask'
        ordering = ['name']

Для того, щоб перевірити, чи потрібно ще виконувати завдання сьогодні, я маю такий код:

def getDueDailyTasks():
    dueDailyTasks=[]
    now = datetime.datetime.now()
    try:
        dailyTasks = DailyTask.objects.all()
    except dailyTask.DoesNotExist:
        return None
    for dailyTask in dailyTasks:
        timeDue = datetime.datetime(now.year,now.month,now.day,dailyTask.time.hour,dailyTask.time.minute,dailyTask.time.second)
        if timeDue<now and timeDue>dailyTask.last_completed:
            if dailyTask.weekends==False and now.weekday()>4:
                pass
            else:
                dueDailyTasks.append({'id':dailyTask.id,
                            'due':timeDue,
                             'name': dailyTask.name,
                             'description':dailyTask.description})
    return dueDailyTasks

Це працювало нормально під 1.2, але під 1.4 я отримую помилку:

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

завдяки лінії

if timeDue<now and timeDue>dailyTask.last_completed

і обидва речення порівняння викидають цю помилку.

Я намагався зробити часовий пояс timeDue, додавши pytz.UTC як аргумент, але це все одно викликає ту саму помилку.

Я прочитав деякі документи щодо часових поясів, але бентежусь щодо того, чи потрібно мені просто ознайомитись із часовим поясом timeDue, чи мені потрібно внести фундаментальні зміни в свою базу даних та наявні дані.

Відповіді:


168

Перегляньте детальний документ для отримання детальної інформації.

Зазвичай, використовуйте django.utils.timezone.nowдля створення поточного часу з урахуванням зсуву

>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2012, 5, 18, 13, 0, 49, 803031, tzinfo=<UTC>)

І django.utils.timezone.make_awareзробити компенсований час

>>> timezone.make_aware(datetime.datetime.now(), timezone.get_default_timezone())
datetime.datetime(2012, 5, 18, 21, 5, 53, 266396, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)

Потім ви можете порівняти обидва дати, визначені для компенсації, без проблем.

Крім того, ви можете перетворити час, що пробуджується на зсув, на компенсацію наївного часу, вилучивши інформацію про часовий пояс, тоді його можна порівняти з нормальним datetime.datetime.now(), під utc.

>>> t = timezone.now() # offset-awared datetime
>>> t.astimezone(timezone.utc).replace(tzinfo=None)
datetime.datetime(2012, 5, 18, 13, 11, 30, 705324)

USE_TZє True"за замовчуванням" (насправді це Falseза замовчуванням, але settings.pyфайл, згенерований django-admin.py startprojectвстановити його True), то, якщо ваша БД підтримує час, визначений часовим поясом, значення полів моделі, пов'язаних з часом, будуть з урахуванням часового поясу. Ви можете вимкнути його, встановивши USE_TZ=False(або просто видаливши USE_TZ=True) у налаштуваннях.


4
Django не зберігає відомості про час для TimeField, він зберігає лише для DateTimeField. Це справді дратує, оскільки об’єкт python datetime.time підтримує TZINFO так само, як об’єкти datetime.datetime. Цікаво, що це виправлять у наступному випуску. До речі, я протестував його на сервері баз даних postres 9.1.
tejinderss

@tejinderss: datetime.timeнеправильно. Немає сенсу зберігати 'Asia/Shanghai'часовий пояс, якщо ви не знаєте дату (зсув utc може бути різним у той самий час, але в різні дати).
jfs

@okm: make_aware(datetime.now(), get_default_timezone())не вдається, якщо він get_default_timezone()відрізняється від вашого місцевого часового поясу (він повинен бути, але на нього не можна повністю покластися). Просто використовуйте timezone.now()замість (це часовий пояс, знати , якщо USE_TZє True).
jfs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.