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

时间:2017-02-07 16:28:47

标签: python django timezone python-datetime

我试图在保存和加载时根据时区修改日期时间,方法如下:

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

为了反映这一点,这是一个更简单的例子,以同样的方式失败:

部分导入:

>>> import datetime
>>> import pytz
>>> from apps.myapp.models import Project

创建两个输入:

>>> 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>

如您所见,时区不是5h24 - 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>)

正如预期的那样,时间没有变化,但是时区已经很好了。

我将此值分配给项目(launch_dateDateTimeField,没有任何特定选项):

>>> 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>)

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

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

正如预期的那样,日期比前一个日期提前4h56。我现在正试着回到当地时间:

>>> 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>)

这次,偏移量完全是5h。我错过了4分钟。

这里有3个问题:

  • 这4分钟来自哪里?
  • 为什么astimezone也没有使用4分钟?
  • 如何将日期时间转换为UTC,保存,加载并转换回本地?

1 个答案:

答案 0 :(得分:1)

pytz个时区有点奇怪,正如您可以通过StackOverflow上的多个问题看到的那样。他们通常不会显示正确的偏移或时区名称,除非允许他们自己调整到与他们配对的datetime。以下是the documentation所说的内容:

  

此库仅支持两种构建本地化时间的方法。第一种是使用pytz库提供的localize()方法。这用于本地化一个天真的日期时间(没有时区信息的日期时间):

     

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

     

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

它没有明确说明,但使用replace与使用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>)

我怀疑这是一个错误,你真的想从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>)