“美国/太平洋”时区的 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 时区转换时间不正确的主要内容,如果未能解决你的问题,请参考以下文章