保存本地日期时间将时间偏移 4 分钟

nob*_*be4 8 python django timezone python-datetime

我正在尝试通过以下方式在保存和加载时根据时区修改日期时间:

输入日期时间以及输入时区被发送到服务器,服务器应更新日期时间以反映时区。所以当它保​​存在数据库(PostregSQL)中时,保存的是UTC时间(当然是在时区引起的偏移之后)。

为了反映这一点,这里有一个以相同方式失败的简单示例:

一些进口:

>>> import datetime
>>> import pytz
>>> from apps.myapp.models import Project
Run Code Online (Sandbox Code Playgroud)

创建两个输入:

>>> input_date = timezone.now()
>>> input_date
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<UTC>)
>>> current_tz = pytz.timezone('America/New_York')
>>> current_tz
<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>
Run Code Online (Sandbox Code Playgroud)

如您所见,时区不是5h( 24 - 19 = 5),而是4h56. 在这个阶段我认为没关系,它可能与夏令时有关。

现在我正在替换输入日期的时区:

>>> input_date = input_date.replace(tzinfo=current_tz)
>>> input_date
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>)
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,时间没有改变,但时区改变了,这很好。

我将这个值分配给一个项目(launch_date是一种DateTimeField没有任何具体的选项):

>>> project = Project.objects.get(pk=1)
>>> project.launch_date
datetime.datetime(2017, 1, 14, 8, 53, 57, 241718, tzinfo=<UTC>)
>>> project.launch_date = input_date
>>> project.launch_date
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>)
Run Code Online (Sandbox Code Playgroud)

现在我将把它保存到(并从)数据库中刷新,让 Django/PostgreSQL 做数学:

>>> project.save()
>>> project.refresh_from_db()
>>> project.launch_date
datetime.datetime(2017, 2, 7, 21, 3, 14, 377429, tzinfo=<UTC>)
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,日期现在比前一个日期早 4 点 56 分。我现在正在尝试恢复当地时间:

>>> project.launch_date.astimezone(current_tz)
datetime.datetime(2017, 2, 7, 16, 3, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
>>> input_date
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>)
Run Code Online (Sandbox Code Playgroud)

这一次,偏移完全是 5 小时。我错过了 4 分钟。

3个问题在这里:

  • 这四分钟从哪里来?
  • 为什么astimezone不使用 4 分钟呢?
  • 如何将日期时间转换为 UTC、保存、加载并转换回本地?

Mar*_*som 7

pytz时区有点奇怪,正如您在 StackOverflow 上的多个问题中看到的那样。它们通常不会显示正确的偏移量或时区名称,除非允许datetime它们根据配对的对象进行调整。以下是文档的内容

该库仅支持两种构建本地化时间的方式。首先是使用pytz库提供的localize()方法。这用于本地化一个简单的日期时间(没有时区信息的日期时间):

构建本地化时间的第二种方法是使用标准 astimezone() 方法转换现有的本地化时间:

不幸的是,对于许多时区,使用标准日期时间构造函数的 tzinfo 参数“不适用于”pytz。

它没有这么明确地说,但是 usingreplace与使用datetime构造函数有相同的问题。

要在没有 4 分钟差异的情况下完成您的代码正在执行的操作,您可以使用localize()

>>> input_date
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<UTC>)
>>> current_tz.localize(input_date.replace(tzinfo=None))
datetime.datetime(2017, 2, 7, 16, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
Run Code Online (Sandbox Code Playgroud)

我怀疑这是一个错误,并且您确实想从 UTC 进行时区转换:

>>> input_date.astimezone(current_tz)
datetime.datetime(2017, 2, 7, 11, 7, 14, 377429, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
Run Code Online (Sandbox Code Playgroud)