最近在做项目时发现存储的时间比本地时间慢了八小时,查了很多文章,感觉都没有讲的很明白,本文根据自己的理解和如何解决的详细的记录下来,但也参考了一些文章和官网介绍。
datetime.now() 永远获取的是你本地的时间,和你配置无任何关系,并且是不带时区属性的。
from datetime import datetime
>>> datetime.now()
datetime.datetime(2021, 11, 11, 15, 20, 50, 742399)
datetime.utcnow() 获取的标准时间,即 UTC 时间。
from datetime import datetime
>>> datetime.utcnow()
datetime.datetime(2021, 11, 11, 7, 58, 32, 919602)
timezone.now() 如果 settings.py 中的 USE_TZ 为 True 则获取的时间是 UTC 时间,False 就是本地时间和 datetime.now() 完全相同。
from django.utils import timezone
>>> USE_TZ=True
>>> timezone.now()
datetime.datetime(2021, 11, 11, 8, 2, 14, 825261, tzinfo=<UTC>)
USE_TZ=Fasle
>>> timezone.now()
datetime.datetime(2021, 11, 11, 16, 19, 20, 426752)
如果 settings.py 中的 USE_TZ 为 True 则存储的永远是 UTC 时间,这也是合理的,在 django 1.4 之前对时区是不做处理的,通常都是本地时间,都是 naive time,即不带时区的时间,但是这样会带来一个问题,如果用户居住在多个时区时,时间就会很乱,所以在django 1.4 之后启用了时区支持,全部统一使用 UTC存储日期信息,在内部使用一些感知对象去转换时间。这样即便用户在多个时区也不会有时间问题。
上述提到 django 内部使用一些方法去感知用户时区对象,在 datetime 对象中有一个 tzinfo 属性,它用来存储时区信息,表示为 datetime.tzinfo 子类的实例,当 USE_TZ 为 True 时日期对象就是 Aware 的,否则就是 Naive 的。
from django.utils import timezone
>>> USE_TZ=True
>>> timezone.now()
datetime.datetime(2021, 11, 11, 8, 2, 14, 825261, tzinfo=<UTC>) // 带时区:Aware
USE_TZ=Fasle
>>> timezone.now()
datetime.datetime(2021, 11, 11, 16, 19, 20, 426752) // 不带时区:Naive
怎么知道当前时间是否带时区和不带时区,你可以使用 is_aware() 和 is_naive() 来决定日期是 aware 还是 naive 的。
from django.utils import timezone
>>> timezone.now()
datetime.datetime(2021, 11, 11, 8, 35, 11, 360384, tzinfo=<UTC>)
>>> now = timezone.now()
>>> timezone.is_aware(now)
True
>>> timezone.is_naive(now)
False
make_aware():返回一个本地化的时间,根据 TIME_ZONE 参数。
make_naive():返回一个不带时区的时间,根据 TIME_ZONE 的值作为时间,否则就是当前时区。
>>> from django.utils import timezone
>>> now = timezone.now()
>>> timezone.is_aware(now) // 判断是否带时区
True
>>> now
datetime.datetime(2021, 11, 11, 8, 51, 26, 327845, tzinfo=<UTC>)
>>> timezone.make_naive(now) // 去除时区,根据 tzinfo 中的时区属性使用 pytz 进行时区定义
datetime.datetime(2021, 11, 11, 16, 51, 26, 327845)
>>> sh = timezone.make_naive(now)
>>> sh
datetime.datetime(2021, 11, 11, 16, 51, 26, 327845)
>>> t = timezone.make_aware(sh) // 增加时区,转换成设置的 TIME_ZONE 时区的时间
>>> t
datetime.datetime(2021, 11, 11, 16, 51, 26, 327845, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
pytz: http://pytz.sourceforge.net/
is_aware、is_naive、make_aware、make_naive: https://docs.djangoproject.com/en/3.2/ref/utils/#django.utils.timezone.is_aware
django 时区官网:https://docs.djangoproject.com/en/3.2/topics/i18n/timezones/