注册 登录
  • 欢迎访问"运维那点事",推荐使用Google浏览器访问,可以扫码关注本站的"微信公众号"。
  • 如果您觉得本站对你有帮助,那么可以扫码捐助以帮助本站更好地发展。

Django时区问题

Python框架 彭东稳 5792次浏览 已收录 0个评论

一、概述

当开启时区支持后,在内部使用时区相关的对象时,Django将时间用UTC格式存储到数据库中;并且在模板(templates)与表单(forms)中将时间转换为终端用户所在时区的时间。当你的用户生活在多个时区,并且你希望根据他们所在的位置显示当地时间时很有用。

另外即使你的网站仅在一个时区使用,仍然以UTC时间格式存储数据到数据库中是个好习惯。主要原因是夏令时(DST),许多国家都拥有自己的一套夏令时系统,在这套系统里,春季的时间会提前,而秋季的时间便会后延。如果你只以当前时间为标准来开发,每年都会因为夏令时而引起两次错误pytz文档更详细地讨论了这些问题),这个对于你的博客可能没有什么影响,但是如果涉及到按年,按月,按小时来收费的业务,那么就会是一个问题 ,解决这个问题的方法便是在代码中使用UTC时间,仅在与最终用户进行交互的时候使用本地时间。

UTC(格林尼治时间)可以视为一个世界统一的时间,以原子时为基础,其他时区的时间都是在这个基础上增加或减少的,比如中国的时区就为UTC+8,称之为东八区时间。

DST(夏时制)则是为了充分利用夏天日照长的特点,充分利用光照节约能源而人为调整时间的一种机制。通过在夏天将时间向前加一小时,使人们早睡早起节约能源。虽然很多西方国家都采用了DST,但是中国不采用DST。(资料来源:DST百度百科

Django 1.11默认关闭时区支持, 如欲开启时区支持,则需在settings中设置USE_TZ = True 。时区支持使用pytz,它是在安装Django时安装的。在Django 1.11中被修改:为方便起见,在由django-admin startproject创建的settings.py文件中已设置USE_TZ = True。

二、naive datetime与aware datetime对象

使用Django的各位开发者在存储时间的时候可能经常会遇到这样子的错误: RuntimeWarning: DateTimeField received a naive datetime while time zone support is active.

这个错误到底是什么意思呢?什么是naive datetime object?什么又是aware datetime object?

在Django配置中开启时区后,如果将settings.TIME_ZONE设置为中国时区(Asia/Shanghai),为什么以下时间函数会得到时间相差较大的结果?

可以看到当我们把时区设置为“Asia/Shanghai”时,两个方法获取的时间相差8个小时。一个获取的是“Asia/Shanghai”时间,一个获取的是UTC时间。如果你把时区设置为“UTC”,那么同样适用datetime.now()获取的也就是UTC时间了。

Python的datetime.datetime对象有一个tzinfo属性,该属性是datetime.tzinfo子类的一个实例,它被用来存储时区信息。当某个datetime对象的tzinfo属性被设置并给出一个时间偏移量时,我们称该datetime对象是aware(已知)的,否则称其为naive(原生)的。所以简单说就是存储了时区信息的我们称之为aware datetime object,而没有存储时区信息的我们称之为naive datetime object。

当使用datetime.now()得到一个datetime对象的时候,此时该datetime对象没有任何关于时区的信息,即datetime对象的tzinfo属性为None,该datetime对象就被称为naive datetime object

在使用now函数的时候,可以指定时区,但该时区参数必须是datetime.tzinfo的子类。(tzinfo是一个抽象类,必须有一个具体的子类才能使用,在这里使用pytz.utc,在Django中的timezone源码中也实现了一个UTC类以防没有pytz库的时候timezone功能能正常使用)。

当使用timezone.now函数的时候,情况则不一样,在支持时区功能的时候,该函数返回的是一个带有UTC时区信息的aware datetime obeject,即它不受TIME_ZONE变量的影响。直接看源码:

如果关闭时区功能,就返回一个受TIME_ZONE影响的naive datetime object。

在Django中提供了几个简单的函数,如:is_aware, is_naive, make_aware和make_naive用于辨别和转换naive datetime object和aware datetime object。

建议:后端应该在数据库统一存储UTC时间并返回UTC时间给前端,前端在发送时间和接收时间的时候要把时间分别从当前时区转换成UTC发送给后端,以及接收后端的UTC时间转换成当地时区。

原文:https://juejin.im/post/5848b301128fe1006907d5ed

如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (0)or分享 (0)
关于作者:

您必须 登录 才能发表评论!