【问题标题】:Python Django Time Zone Conversion Incorrect Time for 'US/Pacific' Time Zone“美国/太平洋”时区的 Python Django 时区转换时间不正确
【发布时间】: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 小时。

【问题讨论】:

    标签: python django datetime pytz python-datetime


    【解决方案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

    【讨论】:

    • 感谢您的反馈!
    猜你喜欢
    • 2019-04-16
    • 1970-01-01
    • 2012-12-08
    • 2021-09-05
    • 2013-03-13
    • 2011-03-13
    • 2022-06-29
    • 1970-01-01
    • 2017-01-29
    相关资源
    最近更新 更多