【问题标题】:How to serialize time objects while preserving their timezone?如何在保留时区的同时序列化时间对象?
【发布时间】:2020-10-23 19:40:21
【问题描述】:

我正在尝试将time-objects 序列化为 ISO8601 格式,同时使用 Python 3.8 保留它们的时区信息。

documentation for time.isoformat 声明:

time.isoformat(timespec='auto')

返回一个以 ISO 8601 格式表示时间的字符串,其中之一:

  • HH:MM:SS.ffffff,如果microsecond 不为0
  • HH:MM:SS,如果microsecond 为 0
  • HH:MM:SS.ffffff+HH:MM[:SS[.ffffff]],如果utcoffset() 不返回None
  • HH:MM:SS+HH:MM[:SS[.ffffff]],如果 microsecond 为 0 且 utcoffset() 不返回 None

据我从该文档中了解到的,我只需要生成一个utcoffset() 不是Nonetime-object,即可将时区信息作为ISO8601 格式字符串的一部分。使用datetime.timezone.utc 作为时区时效果很好:

>>> from datetime import time, timezone
>>> t = time(1, 2, 3, tzinfo=timezone.utc)
>>> t
datetime.time(1, 2, 3, tzinfo=datetime.timezone.utc)
>>> t.utcoffset()
datetime.timedelta(0)
>>> t.isoformat()
'01:02:03+00:00'

但是,一旦我想使用 Python 标准库未提供的时区,这似乎不再适用。我尝试了dateutilpytz,在这两种情况下都得到了相同的结果:

>>> from datetime import time
>>> from dateutil.tz import gettz
>>> t = time(1, 2, 3, tzinfo=gettz("US/Eastern"))
>>> t
datetime.time(1, 2, 3, tzinfo=tzfile('/usr/share/zoneinfo/US/Eastern'))
>>> t.utcoffset()
>>> t.isoformat()
'01:02:03'

>>> from datetime import time
>>> from pytz import timezone
>>> t = time(1, 2, 3, tzinfo=timezone("US/Eastern"))
>>> t
datetime.time(1, 2, 3, tzinfo=<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>)
>>> t.utcoffset()
>>> t.isoformat()
'01:02:03'

我也尝试改用time.strftime(),但这也不能解决我的问题:

>>> from datetime import time
>>> from dateutil.tz import gettz
>>> t = time(1, 2, 3, tzinfo=gettz("US/Eastern"))
>>> t.strftime("%H:%M:%S%z")
'01:02:03'

为什么会这样?我该如何解决这个问题?

【问题讨论】:

    标签: python datetime timezone


    【解决方案1】:

    没有日期,时间不会给出明确的 UTC 偏移量。例如,在您的情况下,时区“美国/东部”在一年中部分采用夏令时,UTC 偏移量为EST(UTC-5)和EDT(UTC-4)。 Python在那里有点安静,没有告诉你它,例如在警告中。

    如果您添加日期,strftime 有效:

    import datetime as dt
    from dateutil.tz import gettz
    
    t_est = dt.datetime.combine(dt.date(2020,1,1), dt.time(1, 2, 3, tzinfo=gettz("US/Eastern")))
    t_est.strftime("%H:%M:%S%z")
    # '01:02:03-0500'
    t_edt = dt.datetime.combine(dt.date(2020,6,6), dt.time(1, 2, 3, tzinfo=gettz("US/Eastern")))
    t_edt.strftime("%H:%M:%S%z")
    # '01:02:03-0400'
    

    另一方面,如果您提供 tzinfo 作为纯 UTC 偏移量,您的代码就可以工作。引用the docs:

    t = dt.time.fromisoformat('04:23:01+04:00')
    # datetime.time(4, 23, 1, tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
    t.isoformat()
    # '04:23:01+04:00'
    

    例如,如果您知道所有时间对象都引用 EST,则可以使用相应的 UTC 偏移量:

    t = dt.time(1, 2, 3, tzinfo=dt.timezone(dt.timedelta(seconds=3600*-5)))
    t.isoformat()
    # '01:02:03-05:00'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 2016-06-23
      • 1970-01-01
      • 2017-09-10
      • 1970-01-01
      相关资源
      最近更新 更多