我试图在保存和加载时根据时区修改日期时间,方法如下:
输入日期时间和输入时区被发送到服务器,服务器应该更新日期时间以反映时区。因此,当它保存在数据库(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>
正如您所看到的,时区不是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>)
正如预期的那样,时间没有改变,但时区已经改变了,这很好。
我将把这个值分配给一个项目(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>)
现在,我将把它保存到数据库中(并从中刷新),让Django/PostgreSQL计算:
>>> project.save()
>>> project.refresh_from_db()
>>> project.launch_date
datetime.datetime(2017, 2, 7, 21, 3, 14, 377429, tzinfo=<UTC>)
不出所料,现在的日期比前一天提前了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>)
这一次,偏移完全是5小时。我错过了4分钟。
这里有3个问题:
- 这4分钟是从哪里来的
- 为什么
astimezone
没有使用这4分钟 - 如何将日期时间转换为UTC、保存、加载并转换回本地
pytz
时区有点奇怪,您可以从StackOverflow上的多个问题中看到这一点。它们通常不会显示正确的偏移量或时区名称,除非允许它们根据配对的datetime
进行调整。以下是文档的内容:
此库仅支持两种构建本地化时间的方法。第一种方法是使用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>)