Python的日期实现/Linux发行版一般使用(tz database/Olson database)1

Python中的日期

一般使用pytz库来操作日期

django中的时区使用问题

https://docs.djangoproject.com/en/2.1/topics/i18n/timezones/

Time zone support is disabled by default. To enable it, set USE_TZ = True in your settings file. Time zone support uses pytz, which is installed when you install Django.

When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms.

仅能用于template和form,如果自己写api存和取要转换咯

  1. 设置settings.py
# 使用时区设置,将tzinfo附加到datetime上面
UES_TZ = True
# 设置localtime为上海
TIME_ZONE = 'Asia/Chongqing'
  1. 以上设置使用的基础处理规则:
    • 所有存入database的时间一律先转换为utc时间再存储,通过auto_now以及auto_now_add自动生成的时间会是utc时间,而且存入model的时间再取出之后的时区并不是naive的而是已经设定时区为utc的,例如从数据库中取出时间显示如下
  2. 使用django自带模块django.utils.timezone进行时间处理

比较好的应用实例,在建表时遇到取当前时间默认值时,之前有如下写法——

from django.utils.datetime_safe import datetime
class X(models.Model):
	models.DateTimeField(null=False, default=datetime.utcnow)

而现在可以用

from django.utils import timezone
class X(models.Model):
	models.DateTimeField(null=False, default=timezone.now)

特别注意设置USE_TZ = True之后,timezone.now()得到的datetime格式时间是aware的并且是UTC时间。以上两种方式都可以使用。

后端对时间处理的一些原则

以下假设使用Django,且USE_TZ=TrueTIME_ZONE='Asia/Shanghai'

  • Django Template/Form,当启用USE_TZ并设置了正确的TIME_ZONE,会自动转成localtime
  • 需要转换成localtime的场景
    • 导出产物:比如excel
    • 调用外部API查询:需要根据对方要求进行转换或者使用unix timestamp
  • 数据库:统一使用UTC保存datetime,由对应的前端再做格式化行为
  • 内部使用API的程序(浏览器、小程序、客户端等):
    • 提交给django的datetime query parameter,在使用ORM查询的时候,需要使用datetime.strptimedate string转成datetime,并且make_aware附加timezone info,否则查询时会有警告RuntimeWarning: DateTimeField 'xxxxxxx' received a naive datetime (2018-10-05 00:00:00) while time zone support is active. ,而由于启用了时区支持,所以当传入的naive datetime是'2018-10-5’到'2018-10-10’时,ORM的raw query语句内容会在查询前转换成timezone-aware'2018-10-4 16:00:00’到'2018-10-9 16:00:00’,这点和数据库是一致的

使用utc时间来处理,可以比较无痛处理各时区的数据,但比较麻烦的大概就是“反直觉”吧,毕竟总要算上当前时区

MySQL timezone的问题

Django 在使用CONVERT_TZ函数时,会使用 tz database 所定义的时区名,比如UTCAsia/Shanghai来插入SQL,所以如果MySQL没有对应的timezone info database的数据,CONVERT_TZ函数会返回NULL值,这种情况下需要导入timezone database到MySQL里面。

可以到MySQL官网下载sql文件,解压导入,命令 mysql -u root -p mysql < sql_file_name