【Django】Django 中的时间获取与相关问题

Posted by 西维蜀黍 on 2019-10-19, Last Modified on 2021-10-02

Background

在 Django1.4以后,存在两个概念:Naive time 与 Active time:

  • Naive time就是不包含时区信息的时间,
  • Active time就是包含时区信息(time-zone-aware)的时间

举例来说,使用datetime.datetime.utcnow()或者datetime.datetime.now()输出的类似2015-05-11 09:10:33.080451,就是不带时区信息的时间(Naive time)。而使用django.util.timezone.now()输出的类似2015-05-11 09:05:19.936835+00:00的时间就是带时区信息的时间(Active time),其中+00:00表示的就是时区相对性。

时区问题

首先需要注意的是,在 Django Project 中,我们定义了时区:

# settings.py
TIME_ZONE = 'UTC'
USE_TZ = True

因此,个人推荐使用django.utils下的timezone模块来获取 Django 中涉及的任何时间,和处理 Django 中任何关于时间的问题。

另外,USE_TZ一定要设置为 True,否则会出现各种因为时区导致时间不一致的问题。

TIME_ZONE参数意义

当 TIME_ZONE = ‘UTC’

>>> from django.utils import timezone

# 获取 UTC 时间
>>> timezone.now()
datetime.datetime(2019, 10, 19, 10, 9, 56, 505152, tzinfo=<UTC>)

# 获取当前在 Django 中设置的时区对应的本地时间
>>> timezone.localtime()
datetime.datetime(2019, 10, 19, 10, 10, 11, 912144, tzinfo=<UTC>)

>>> import datetime
>>> datetime.datetime.today()       # 不包含时区信息的当前时间(Naive time)
datetime.datetime(2019, 10, 19, 10, 23, 38, 117425)

>>> datetime.datetime.now()         # 不包含时区信息的当前时间(当不传入 tz 参数时,和datetime.today()没有区别)
datetime.datetime(2019, 10, 19, 10, 23, 38, 117425)

>>> datetime.datetime.utcnow()      # 不包含时区信息的当前 UTC 时间
datetime.datetime(2019, 10, 20, 5, 7, 23, 190797)

当 TIME_ZONE = ‘America/Chicago’

>>> from django.utils import timezone
>>> import datetime

# 获取 UTC 时间
>>> timezone.now()									
datetime.datetime(2019, 10, 19, 9, 40, 49, 253695, tzinfo=<UTC>)   

# 获取当前在 Django 中设置的时区对应的本地时间
>>> timezone.localtime()					
datetime.datetime(2019, 10, 19, 4, 41, 18, 503013, tzinfo=<DstTzInfo 'America/Chicago' CDT-1 day, 19:00:00 DST>)

>>> import datetime
>>> datetime.datetime.today()       # 不包含时区信息的当前时间(Naive time)
datetime.datetime(2019, 10, 19, 10, 23, 38, 117425)

>>> datetime.datetime.now()         # 不包含时区信息的当前时间(当不传入 tz 参数时,和datetime.today()没有区别)
datetime.datetime(2019, 10, 19, 10, 23, 38, 117425)

USE_TZ参数意义

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.

再次强调,我们尽量将USE_TZ 设置为 True,这样 Django 就可以尽可能帮我们处理一些因为访问用户的所在时区不一致进而导致的时间不一致问题。

获取当前时区的时间

>>> from django.utils import timezone
>>> timezone.now()

Util

# 将 datatime对象转换为特定格式的 string
>>> timezone.localtime().strftime("%Y-%m-%d %H:%M:%S")
'2019-10-19 04:43:28'
>>> type(timezone.localtime())
<type 'datetime.datetime'>

可能出的问题

上面的本地时间(datetime.datetime.today()),从底层 API实现来说,它会获取本地机器的时间。

而 UTC 时间(datetime.datetime.utcnow()),从底层 API实现来说,其实是在获取本地机器的时间后,根据当前机器设置的时区信息,计算出 UTC 时间。

这意味着,如果你直接修改了本地机器的时间,则通过 Python API 获取到的时间就会是错误的。

总结

  • 在 Django Project 中,设置:
# settings.py
TIME_ZONE = 'UTC'
USE_TZ = True
  • 使用django.utils下的timezone模块来获取 Django 中涉及的任何时间,和处理 Django 中任何关于时间的问题。

  • USE_TZ一定要设置为 True。

  • 不要使用任何不包含时区信息的 API(比如,datetime.datetime.today()datetime.datetime.now()

  • 使用timezone.now()来获取时间

  • 全局统一使用 UTC 时间来处理(包括数据库中的时间存储和调用 API 时返回的时间结果),至于前端想用什么时区的时间来展示数据,由前端来处理。

Reference