gue*_*tli 8 python django datetime django-timezone
到目前为止,我认为创建时区感知日期时间的两种方法是相同的。
但他们不是:
import datetime
from django.utils.timezone import make_aware, get_current_timezone
make_aware(datetime.datetime(1999, 1, 1, 0, 0, 0), get_current_timezone())
datetime.datetime(1999, 1, 1, 0, 0, 0, tzinfo=get_current_timezone())
Run Code Online (Sandbox Code Playgroud)
datetime.datetime(1999, 1, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
datetime.datetime(1999, 1, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin' LMT+0:53:00 STD>)
Run Code Online (Sandbox Code Playgroud)
在 Django 管理 GUI 中,第二种方式创建此(德语日期格式 dd.mm.YYYY):
01.01.1999 00:07:00
Run Code Online (Sandbox Code Playgroud)
如果我使用这个,为什么会有 7 分钟的差异:
datetime.datetime(1999, 1, 1, 0, 0, 0, tzinfo=get_current_timezone())
Run Code Online (Sandbox Code Playgroud)
sol*_*oke 10
这种情况发生在依赖pytz库的 Django 3.2 及更低版本上。在 Django 4 中(除非您启用设置以使用已弃用的库),您给出的两个示例的输出是相同的。
\n在 Django 3.2 及更低版本中,会出现差异,因为本地化时间是以两种不同的方式构建的。使用时make_aware
,它是通过调用localize()
时区实例上的方法来完成的pytz
。在第二个版本中,它是通过将tzinfo
对象直接传递给datetime
构造函数来完成的。
这篇博文很好地说明了两者之间的区别:
\n\n\n人们在使用 pytz 时犯的最大错误就是简单地将其时区附加到构造函数,因为这是在 Python 中向日期时间添加时区的标准方法。如果你尝试这样做,最好的情况是你会得到一些明显荒谬的东西:
\nRun Code Online (Sandbox Code Playgroud)\nimport pytz\nfrom datetime import datetime\n\nNYC = pytz.timezone(\'America/New_York\')\ndt = datetime(2018, 2, 14, 12, tzinfo=NYC)\nprint(dt)\n# 2018-02-14 12:00:00-04:56\n
为什么时间偏移是 -04:56 而不是 -05:00?因为那是采用标准化时区之前纽约当地的太阳平均时间,因此是该时
\nAmerica/New_York
区的第一个条目。pytz 为什么返回这个?因为与标准库的延迟计算时区信息模型不同,pytz 采用急切的计算方法。每当你从一个简单的日期时间构造一个感知的日期时间时,你需要调用它的 localize 函数:
\nRun Code Online (Sandbox Code Playgroud)\ndt = NYC.localize(datetime(2018, 2, 14, 12))\nprint(dt)\n# 2018-02-14 12:00:00-05:00\n
你的例子也发生了完全相同的事情Europe/Berlin
。pytz
正在急切地获取其数据库中的第一个条目,该条目是 1983 年之前的太阳时,比格林威治标准时间 (GMT)早 53 分 28 秒。考虑到日期,这显然是不合适的 - 但tzinfo
除非您将其传递给 ,否则它不知道您正在使用的日期localize()
。
这就是您的两种方法之间的区别。make_aware
正确使用localize()
对象上的调用。然而,直接将 分配tzinfo
给datetime
对象则不会,并且会导致pytz
使用(错误的)时区信息,因为它只是数据库中该区域的第一个条目。
pytz 文档也间接提到了这一点:
\n\n\n该库仅支持两种构建本地化时间的方法。第一种是使用 pytz 库提供的 localize() 方法。这用于本地化原始日期时间(没有时区信息的日期时间)...构建本地化时间的第二种方法是使用标准 astimezone() 方法转换现有的本地化时间...不幸的是使用标准日期时间构造函数 \xe2\x80\x98\xe2\x80\x99 不适用于许多时区的 pytz。
\n
实际上,正是由于这些以及实现中的其他几个错误pytz
,Django放弃了它,转而使用 Python 的内置zoneinfo
模块。
该博客文章的更多内容:
\n\n\n在其创建时,
\npytz
它被巧妙地设计为优化性能和正确性,但随着 PEP 495 引入的更改和 dateutil 的性能改进,使用它的理由正在减少。\n... 使用它的最大原因dateutil 优于 pytz 的事实是,dateutil 使用标准接口,而 pytz 不使用,因此很容易错误地使用 pytz。
将pytz
tzinfo
对象直接传递给datetime
构造函数是不正确的。你必须拜访localize()
班级tzinfo
,并传递日期。在第二个示例中初始化日期时间的正确方法是:
> berlin = get_current_timezone()\n> berlin.localize(datetime.datetime(1999, 1, 1, 0, 0, 0))\ndatetime.datetime(1999, 1, 1, 0, 0, tzinfo=<DstTzInfo \'Europe/Berlin\' CET+1:00:00 STD>)\n
Run Code Online (Sandbox Code Playgroud)\n...与make_aware
产生的结果相匹配。
归档时间: |
|
查看次数: |
2172 次 |
最近记录: |