【问题标题】:unexpected results converting timezones in python在python中转换时区的意外结果
【发布时间】:2015-12-17 09:05:59
【问题描述】:

我试图了解为什么在将时区转换为 UTC 时会得到这些结果:

In [74]: d1 = datetime(2007, 12, 5, 6, 30,tzinfo=pytz.timezone('US/Pacific'))
In [75]: d1
Out[75]: datetime.datetime(2007, 12, 5, 6, 30, tzinfo=<DstTzInfo 'US/Pacific' LMT-1 day, **16:07:00 STD**>)
In [76]: d1.astimezone(pytz.utc)
Out[76]: datetime.datetime(2007, 12, 5, 14, 23, tzinfo=<UTC>)

为什么早上 6:30 变成了下午 2:23?

另一方面,如果我使用以下方法,我会得到预期的结果:

In [90]: d2 = datetime(2007, 12, 5, 6, 30)
In [91]: uspac = pytz.timezone('US/Pacific')
In [92]: d2_aware = uspac.localize(d2)
In [94]: d2_aware.astimezone(pytz.utc)
Out[94]: datetime.datetime(2007, 12, 5, 14, 30, tzinfo=<UTC>)

【问题讨论】:

    标签: python pytz


    【解决方案1】:

    很遗憾,使用此方法创建时区感知日期不起作用。

    如果您使用的是 Django,它们有一个实用函数 make_aware,可以正确执行此操作。

    from django.utils.timezone import make_aware
    from pytz import timezone
    
    unaware_datetime = datetime(2007, 12, 5)
    local_datetime = make_aware(datetime(2007, 12, 5))
    specific_datetime = make_aware(datetime(2007, 12, 5), timezone("Australia/Melbourne"))
    

    如果你不使用 Django,那么 make_aware 函数的 source code 可能会给你灵感。

    【讨论】:

    • Django 的make_aware(dt) 只是调用pytz.timezone(...).localize(dt)
    【解决方案2】:

    我正在重新审视有关日期和时间的一些问题,以查看一些较新的库是否证明在这种情况下(或没有)更有帮助。 pendulum 是一种存储带有日期和时间的时区,使其在这种情况下特别有价值。

    >>> import pendulum
    >>> d1 = pendulum.datetime(2007,12,5,6,30, tzinfo='US/Pacific')
    >>> d1
    <Pendulum [2007-12-05T06:30:00-08:00]>
    >>> d1.timezone
    <Timezone [US/Pacific]>
    >>> d1.astimezone(tz='UTC')
    <Pendulum [2007-12-05T14:30:00+00:00]>
    

    还有很多其他有趣的功能。

    【讨论】:

      【解决方案3】:

      我得到的只是一种解决方法,简单的规则是永远不要使用 datetime() 创建带有时区信息的日期时间

      此示例将为您提供提示。如您所见,您可以避免意外的差异,只有您制作“天真”日期时间(即没有时区信息的日期时间)然后对其进行本地化(但在 UTC 上创建日期时间时不会应用它):

      import pytz
      from datetime import datetime
      
      # make Jan 1 on PDT -> UTC
      pdt = pytz.timezone("America/Los_Angeles")
      pdtnow1 = datetime(2014,1,1, tzinfo=pdt)
      pdtnow2 = pdt.localize(datetime(2014,1,1))
      pytz.utc.normalize(pdtnow1)
      # > datetime.datetime(2014, 1, 1, 7, 53, tzinfo=<UTC>)
      pytz.utc.normalize(pdtnow2)
      # > datetime.datetime(2014, 1, 1, 8, 0, tzinfo=<UTC>)
      
      # make Jan 1 on UTC -> PDT
      utcnow1 = datetime(2014,1,1, tzinfo=pytz.utc)
      utcnow2 = pytz.utc.localize(datetime(2014,1,1))
      pdt.normalize(utcnow1)
      # > datetime.datetime(2013, 12, 31, 16, 0, 
      # > tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
      pdt.normalize(utcnow2)
      # > datetime.datetime(2013, 12, 31, 16, 0, 
      # > tzinfo=<DstTzInfo 'America/Los_Angeles' PST-1 day, 16:00:00 STD>)
      

      【讨论】:

      • 当我看到我的结果持续几分钟时,我以为我疯了。非常感谢这个例子。
      • @punkrockpolly 我的荣幸!
      • 网络搜索 7:53 的偏移量帮助我找到了这个问题。我想,既然美国太平洋时间已经开始夏令时,七分钟不知何故被添加到偏移量中,而不是一个小时?多么奇怪!
      • 这部分 python 对我来说似乎是 pythonic 太乱了
      • 两次转换时区还是有问题pdt.localize(datetime(2014, 1, 1) \ .astimezone(other_timezone)
      【解决方案4】:

      来自部分文档: http://pytz.sourceforge.net/#localized-times-and-date-arithmetic

      不幸的是,使用标准日期时间构造函数的 tzinfo 参数对许多时区的 pytz “不起作用”。 [...] 但是对于没有夏令时转换的时区来说是安全的,例如 UTC。 [...] 处理时间的首选方式是始终以 UTC 工作,仅在生成供人类阅读的输出时转换为本地时间。

      【讨论】:

      • 谢谢!我这辈子都想不通!
      • 不幸的是,“没有夏令时转换的时区是安全的”这句话过于乐观了。对于固定偏移量多年来发生变化的时区,它也失败了。幸运的是 UTC 没有改变。
      【解决方案5】:

      .astimezone 之前打印d2_aware,您会看到PST-1(太平洋标准时间),但在第一个示例中,您有LMT-1(本地标准时间)- 并且可能会有7 分钟的差异。

      但我不知道为什么pytz 使用不同的时区。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-10-01
        • 2018-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-10
        相关资源
        最近更新 更多