“美国/太平洋”时区的 Python Django 时区转换时间不正确

Posted

技术标签:

【中文标题】“美国/太平洋”时区的 Python Django 时区转换时间不正确【英文标题】:Python Django Time Zone Conversion Incorrect Time for 'US/Pacific' Time Zone 【发布时间】:2015-12-31 00:13:35 【问题描述】:

虽然我阅读了几乎所有与时区转换相关的帖子,但我仍然遇到一些问题,而且我的转换时间不正确

settings.py

TIME_ZONE = 'UTC'
USE_TZ = True

views.py

utc = datetime.utcnow()
instance_time_zone = pytz.timezone(instance.timezone) # 'US/Pacific'
start_date = instance_time_zone.localize(datetime.utcnow(), is_dst=None)

template.html

utc: Oct. 2, 2015, 5:32 p.m. #correct time
start_date: Oct. 3, 2015, 1:32 a.m. #incorrect time

由于某种原因,转换后的时间有误,比太平洋时间早 15 小时,比 UTC 时间早 8 小时。

【问题讨论】:

【参考方案1】:

timezone.localize() 应该用于naive datetime 对象(没有自己的时区的对象)。时区附加到datetime,就好像日期和时间对于那个时区是正确的。因此,在您的情况下,您将 UTC 本地化,就好像它是没有 DST 的本地时间一样,将它朝错误的方向移动 8 小时。

但是,您使用的是 UTC 时间戳,因此您需要将 UTC 时区附加到该时间戳,然后将时间戳移动到所需的时区:

utc = pytz.utc.localize(datetime.utcnow())
instance_time_zone = pytz.timezone(instance.timezone) # 'US/Pacific'
start_date = utc.astimezone(instance_time_zone)

请注意,utc 值现在是带有时区的 datetime 对象,因此您可以使用 datetime.astimezone() method 从中生成所需目标时区的值。

演示:

>>> from datetime import datetime
>>> utc = pytz.utc.localize(datetime.utcnow())
>>> utc
datetime.datetime(2015, 10, 2, 17, 58, 10, 168575, tzinfo=<UTC>)
>>> instance_time_zone = pytz.timezone('US/Pacific')
>>> utc.astimezone(instance_time_zone)
datetime.datetime(2015, 10, 2, 10, 58, 10, 168575, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)

现在生成的datetime 与 UTC 相差 5 小时。

但是,如果您将这些值输出到 Django 模板中,请注意 Django 也会转换时区。请参阅Django timezone documentation,特别是section on using aware datetime objects in templates:

当您启用时区支持时,当它们在模板中呈现时,Django 会将可感知的日期时间对象转换为 current time zone。这与格式本地化非常相似。

来自current time zone section:

您应该使用activate() 将当前时区设置为最终用户的实际时区。否则,使用默认时区。

然后,您将datetime 对象移动到哪个时区并不重要;它将使用当前时区来显示该值。您通常希望在 UTC 时区中使用有意识的 datetime 对象,然后使用 activate() 切换显示所有内容的时区。

所以在 Django 中,只需在任何地方使用 timezone.now(),然后让模板系统担心将其转换为给定的时区。

【讨论】:

感谢您的反馈!出于某种原因,当我运行您的代码时,我确实得到了 2015 年 10 月 2 日下午 6:03。有什么建议吗? @WayBehind: 你的电脑时区配置正确吗? @WayBehind:您的datetime.utcnow 输出看起来确实是正确的,所以说实话,我不确定您的系统发生了什么。 utc 输出是否与我的匹配(或至少几分钟后)?如果您得到 2015 年 10 月 2 日下午 6:03,是 UTC 输出还是 start_date 输出? 下午 6:10。毕竟现在是UTC。 是的,这就是我得到的。下午 6:03 甚至我的服务器也显示错误的时间。有什么想法吗? 这是 UTC 时间。你有多确定instance.timezone 确实是US/Pacific,并且你不是不小心使用了utc 值而不是utc.astimezone() 的返回值?【参考方案2】:

要在 django 中获取当前时间,请使用timezone.now()

from django.utils import timezone

start_date = timezone.now()

如果instance.timezone 指代与timezone.get_current_timezone() (default is TIME_ZONE) 相同的时区,那么这就是您所需要的(timezone.now() 以UTC 格式返回一个感知的日期时间对象(如果USE_TZ=True),该对象在渲染到当前时区期间被转换) .

否则,您可以拨打timezone.activate(instance.timezone)设置当前时区。

如果你想(你不需要)你可以明确地转换时区:

import pytz
from django.utils import timezone

now = timezone.localtime(timezone.now(), pytz.timezone(instance.timezone))

在 django 代码之外,您可以通过显式传递 tzinfo 来获取给定时区的当前时间:

from datetime import datetime
import pytz

start_date = datetime.now(pytz.timezone('America/Los_Angeles'))

It works even during ambiguous local times.

转换一个现有的、表示给定 pytz 时区时间的简单日期时间对象:

start_date = instance_time_zone.localize(datetime_in_instance_time_zone,
                                         is_dst=None)

此代码会引发实例时区中不明确/不存在的时间的异常(例如,在 DST 转换期间)。如果在某些情况下可以返回不精确的结果而不是异常,则不要传递is_dst=None

tz = instance_time_zone
start_date = tz.normalize(tz.localize(datetime_in_instance_time_zone))

有关is_dst的更多详细信息,请参阅"Can I just always set is_dst=True?" section。

【讨论】:

感谢您的反馈!

以上是关于“美国/太平洋”时区的 Python Django 时区转换时间不正确的主要内容,如果未能解决你的问题,请参考以下文章

Python Pytz美国/太平洋时区问题[重复]

导入 pytz 失败时如何获取太平洋时区的当前时间?

美国和中国的时差是多少?

美国现在时间是几点几分几秒?

请问美国与中国时间时差多少?

PostgreSQL 更新时区偏移量