django 1.4 - 无法比较 offset-naive 和 offset-aware 日期时间

Posted

技术标签:

【中文标题】django 1.4 - 无法比较 offset-naive 和 offset-aware 日期时间【英文标题】:django 1.4 - can't compare offset-naive and offset-aware datetimes 【发布时间】:2012-05-26 00:56:25 【问题描述】:

我正在将应用程序从 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

两个比较子句都会抛出这个错误。

我尝试通过添加 pytz.UTC 作为参数来识别 timeDue 时区,但这仍然会引发相同的错误。

我已经阅读了一些关于时区的文档,但对于我是否只需要让 timeDue 时区感知,或者我是否需要对我的数据库和现有数据进行根本性更改感到困惑。

【问题讨论】:

【参考方案1】:

查看the thorough document了解详细信息。

通常,使用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>)

然后,您可以比较两个可感知偏移的日期时间而不会遇到麻烦。

此外,您可以通过剥离时区信息将偏移感知日期时间转换为偏移天真日期时间,然后可以在 UTC 下与普通 datetime.datetime.now() 进行比较。

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

USE_TZTrue '默认' (实际上它默认是False,但是django-admin.py startproject 生成的settings.py 文件将它设置为True),那么如果您的数据库支持时区感知次,与时间相关的模型字段的值将是时区感知的。您可以通过在设置中设置USE_TZ=False(或简单地删除USE_TZ=True)来禁用它。

【讨论】:

Django 不为 TimeField 存储感知时间,它只为 DateTimeField 存储。它真的很烦人,因为 python datetime.time 对象确实支持 TZINFO,就像 datetime.datetime 对象一样。我想知道他们会在下一个版本中修复它。顺便说一句,我已经在 postres 9.1 数据库服务器上对其进行了测试。 @tejinderss:datetime.time 是错误的。如果您不知道日期,则没有必要存储 'Asia/Shanghai' 时区(同一时间但在不同日期的 utc 偏移量可能不同)。 @okm: make_aware(datetime.now(), get_default_timezone()) 失败,如果get_default_timezone() 与您当地的时区不同(应该是,但它不是完全可靠的)。只需使用timezone.now() 代替(如果USE_TZTrue,则可以识别时区)。

以上是关于django 1.4 - 无法比较 offset-naive 和 offset-aware 日期时间的主要内容,如果未能解决你的问题,请参考以下文章

ngInit 无法与 AngularJS 和 Django 一起正常工作

无法将 Django 从 1.7 迁移到 1.8

装饰所有 django 管理视图 (1.4+)

无法在 Django 模板文件的 for 循环中使用条件标签

自定义Django登录,无法比较密码

用户注册后Django自动登录(1.4)