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

标签 python django timezone python-datetime

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

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

为了反射(reflect)这一点,这里有一个以相同方式失败的更简单的示例:

一些导入:

>>> 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 时区有点奇怪,您可以通过 StackOverflow 上的多个问题看出这一点。它们通常不会显示正确的偏移量或时区名称,除非允许它们将自己调整到与之配对的 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>)

关于python - 保存本地日期时间将时间偏移 4 分钟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42095059/

相关文章:

python 在 anaconda 提示符启动时停止工作

python - 如何在 Python 3.x 中禁用 chrome webdriver 上的调试器?

HashMap 的 Python 等效项

python - Django - 保持原始方法的工作并添加新的自定义验证

python - 每个用户的 Celery PeriodicTask

android - 在android中以编程方式设置设备时间

javascript - Angularjs:有没有办法从用户选择的时区创建 timeDate 对象?

python - 区分同名的 Python 模块/安装不同的名称?

python - 自定义 Django ClearableFileInput 小部件的样式

iphone - 欧洲的 UTC 时区给出的年份是 2014 年而不是 2013 年