保存本地日期时间将时间偏移 4 分钟
Saving a local datetime offset the time by 4 minutes
我正在尝试通过以下方式在保存和加载时基于时区修改日期时间:
输入的日期时间和输入的时区被发送到服务器,服务器应该更新日期时间以反映时区。所以当它在数据库(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>)
这一次,偏移量正好是5h。我错过了 4 分钟。
这里有 3 个问题:
- 这 4 分钟是从哪里来的?
- 为什么
astimezone
也没有使用 4 分钟?
- 如何将日期时间转换为 UTC、保存、加载并转换回本地?
pytz
时区有点奇怪,正如您在 Whosebug 上的多个问题所看到的那样。他们通常不会显示正确的偏移量或时区名称,除非允许他们调整自己以适应与之配对的 datetime
。这是 the documentation 必须要说的:
This library only supports two ways of building a localized time. The first is to use the localize() method provided by the pytz library. This is used to localize a naive datetime (datetime with no timezone information):
The second way of building a localized time is by converting an existing localized time using the standard astimezone() method:
Unfortunately using the tzinfo argument of the standard datetime constructors “does not work” with pytz for many timezones.
它没有明确说明,但是使用 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>)
我正在尝试通过以下方式在保存和加载时基于时区修改日期时间:
输入的日期时间和输入的时区被发送到服务器,服务器应该更新日期时间以反映时区。所以当它在数据库(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>)
这一次,偏移量正好是5h。我错过了 4 分钟。
这里有 3 个问题:
- 这 4 分钟是从哪里来的?
- 为什么
astimezone
也没有使用 4 分钟? - 如何将日期时间转换为 UTC、保存、加载并转换回本地?
pytz
时区有点奇怪,正如您在 Whosebug 上的多个问题所看到的那样。他们通常不会显示正确的偏移量或时区名称,除非允许他们调整自己以适应与之配对的 datetime
。这是 the documentation 必须要说的:
This library only supports two ways of building a localized time. The first is to use the localize() method provided by the pytz library. This is used to localize a naive datetime (datetime with no timezone information):
The second way of building a localized time is by converting an existing localized time using the standard astimezone() method:
Unfortunately using the tzinfo argument of the standard datetime constructors “does not work” with pytz for many timezones.
它没有明确说明,但是使用 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>)