django 1.4 - ไม่สามารถเปรียบเทียบวันที่ออฟเซ็ตไร้เดียงสาและออฟเซ็ต - รับรู้ได้


86

ฉันอยู่ระหว่างการย้ายแอปพลิเคชันจาก 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 ตระหนักถึงเขตเวลาหรือไม่หรือฉันต้องทำการเปลี่ยนแปลงพื้นฐานกับฐานข้อมูลและข้อมูลที่มีอยู่

คำตอบ:


170

ตรวจสอบเอกสารอย่างละเอียดเพื่อดูข้อมูลรายละเอียด

โดยปกติใช้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 object รองรับ TZINFO เหมือนกับออบเจ็กต์ datetime.datetime ฉันสงสัยว่าพวกเขาจะแก้ไขได้ในรุ่นถัดไป Btw ฉันได้ทดสอบบนเซิร์ฟเวอร์ฐานข้อมูล 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.