django 1.4 - ofset-naive ve offset-duyarlı veri zamanlarını karşılaştıramaz


86

Bir uygulamayı django 1.2'den 1.4'e taşıma sürecindeyim.

Görevin tamamlanması gereken günün bir saatini içeren günlük bir görev nesnem var:

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']

Bugün hala bir görevin tamamlanması gerekip gerekmediğini kontrol etmek için aşağıdaki koda sahibim:

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

Bu, 1.2'nin altında iyi çalıştı, ancak 1.4'ün altında hatayı alıyorum:

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

hat nedeniyle

if timeDue<now and timeDue>dailyTask.last_completed

ve her iki karşılaştırma cümlesi de bu hatayı atar.

Pytz.UTC'yi argüman olarak ekleyerek timeDue saat diliminin farkına varmaya çalıştım, ancak bu yine de aynı hatayı ortaya çıkarıyor.

Saat dilimleriyle ilgili bazı dokümanları okudum, ancak sadece timeDue saat diliminden haberdar olmam gerekip gerekmediği veya db ve mevcut verilerimde temel bir değişiklik yapmam gerekip gerekmediği konusunda kafam karıştı.

Yanıtlar:


170

Ayrıntılı bilgi için kapsamlı belgeyi kontrol edin .

Normalde, django.utils.timezone.nowofsete duyarlı bir geçerli tarih saat yapmak için kullanın

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

Ve django.utils.timezone.make_awareofsete duyarlı bir tarih saat yapmak için

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

Daha sonra her iki ofsete duyarlı veri zamanını sorun olmadan karşılaştırabilirsiniz.

Ayrıca, zaman dilimi bilgisini çıkararak, uzaklık uyan tarih saatini uzaklıktan bağımsız tarih saatine dönüştürebilir, ardından datetime.datetime.now()utc altında w / normal karşılaştırılabilir .

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

USE_TZTrue"varsayılan olarak" ' dır (aslında Falsevarsayılan olarak, ancak bu şekilde ayarlanan settings.pydosya ), bu durumda DB'niz saat dilimine duyarlı zamanları destekliyorsa, zamanla ilgili model alanlarının değerleri saat dilimine duyarlı olacaktır. ayarlarda ayarlayarak (veya basitçe kaldırarak ) devre dışı bırakabilirsiniz .django-admin.py startprojectTrueUSE_TZ=FalseUSE_TZ=True


4
Django, TimeField için farkındalık süreleri depolamaz, yalnızca DateTimeField için yapar. Python datetime.time nesnesi, tıpkı datetime.datetime nesneleri gibi TZINFO'yu desteklediği için gerçekten sinir bozucu. Bir sonraki sürümde düzelteceklerini merak ediyorum. Btw bunu postres 9.1 veritabanı sunucusunda test ettim.
tejinderss

@tejinderss: datetime.timeyanlış. 'Asia/Shanghai'Tarihi bilmiyorsanız saat dilimini saklamanın bir anlamı yoktur (utc farkı aynı zaman için farklı ancak tarihlerde farklı olabilir).
jfs

@okm: yerel saat diliminizden farklıysa make_aware(datetime.now(), get_default_timezone())başarısız olur get_default_timezone()(olmalıdır, ancak tamamen güvenilir değildir). Sadece kullanmak timezone.now()yerine (bu zaman dilimi farkında eğer olduğunu USE_TZolduğunu True).
jfs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.