首页 > 解决方案 > 如何在保留时区的同时序列化时间对象?

问题描述

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

状态的文档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为 0utcoffset()且不返回None

据我从该文档中了解到,我只需要生成一个time-object,utcoffset()它不会None将时区信息作为 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'

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

标签: pythondatetimetimezone

解决方案


没有日期,时间不会给出明确的 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 偏移量,您的代码就可以工作。引用文档

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'

推荐阅读