Python 如何序列化时间对象,同时保留其时区?

Python 如何序列化时间对象,同时保留其时区?,python,datetime,timezone,Python,Datetime,Timezone,我试图将时间-对象序列化为ISO8601格式,同时使用Python 3.8保留它们的时区信息 各国: time.isoformat(timespec='auto') 以ISO 8601格式返回表示时间的字符串,可以是: HH:MM:SS.ffffff,如果微秒不是0 HH:MM:SS,如果微秒为0 如果utcoffset()未返回None HH:MM:SS+HH:MM[:SS[.ffffff]],如果微秒为0且utcoffset()未返回None 据我从该文档中了解,我只需生成一个time-

我试图将
时间
-对象序列化为ISO8601格式,同时使用Python 3.8保留它们的时区信息

各国:

time.isoformat(timespec='auto')

以ISO 8601格式返回表示时间的字符串,可以是:

  • HH:MM:SS.ffffff
    ,如果
    微秒
    不是0
  • HH:MM:SS
    ,如果
    微秒
    为0
  • 如果
    utcoffset()
    未返回
    None
  • HH:MM:SS+HH:MM[:SS[.ffffff]]
    ,如果
    微秒
    为0且
    utcoffset()
    未返回
    None
据我从该文档中了解,我只需生成一个
time
-对象,该对象的
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标准库不提供的时区,它就不再有效了。我尝试了
dateutil
pytz
,在这两种情况下得到了相同的结果:

>>> 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'

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

没有日期,时间不会给出明确的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偏移量,则代码将正常工作。引述自:

因此,在您的情况下,例如,如果您知道所有时间对象都引用EST,您可以使用UTC偏移:

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

如果没有日期,时间不会给出明确的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偏移量,则代码将正常工作。引述自:

因此,在您的情况下,例如,如果您知道所有时间对象都引用EST,您可以使用UTC偏移:

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