Django 对时区处理的核心逻辑是:
- 写入 DB 时,如果传的是 aware datetime object,转成 UTC 进行存储
- 从 DB 读取时,把 DATETIME 转成终端用户的时区
即使网站用户只有一个地区,Django 也 建议 用 UTC 存储时间,来避免有些地区使用的夏令时(DST)引起一个时间重复出现多次的问题。
USE_TZ
设置:
- 如果打开,Django 会在内部使用 aware 对象
- 如果关闭,Django 会在内部使用
TIME_ZONE
定义的的本地时区的 naive 对象(有一些不太重要的例外)
TIME_ZONE
设置的意义是一个默认的时区。它的逻辑是:
- 存储 DATETIME 对象时,如果:
USE_TZ
为False
时,Django 会把 DATETIME 对象转换到这个时区再去存储;你在 DB 中的值会是这个时区的时间(即使 DB 本身不存储时区,如 MySQL)USE_TZ
为True
时,Django 会把 DATETIME 对象转换到 UTC 再去存储;你在 DB 中的值会是 UTC 时间
- 读取 DATETIME 对象时,如果:
- DB 本身不存储时区信息(比如 MySQL),那读取出来的 DATETIME 值在不同情况下,会被认为是:
USE_TZ
为False
时,逻辑上被认为是TIME_ZONE
设定的时区(但 Django 内部仍然使用 naive object);在展示到 template 时,不会被转换时区USE_TZ
为True
时,被认为是 UTC 时间,Django 内部会使用 aware object;在展示到 template 时,会被转换为应用代码中指定的用户时区;如果代码没有指定,会被转换为TIME_ZONE
设置的时区
- DB 本身不存储时区信息(比如 MySQL),那读取出来的 DATETIME 值在不同情况下,会被认为是:
这个逻辑看起来很复杂。但是从演变的角度看就容易理解:
TIME_ZONE
设置早于USE_TZ
设置。在 Web 还没有蓬勃发展的年代,一个网站往往仅服务一个国家 / 地区的用户。因此一个TIME_ZONE
设置就足够了- Django 1.4 才引入
USE_TZ
设置。当USE_TZ
被打开时,TIME_ZONE
的含义 从网站的唯一时区,变成了 当没有给用户指定一个时区时 的默认时区