python datetime.astimezone 行为不正确?

python datetime.astimezone behavior incorrect?

这是首先从 IST 中的字符串解析时间然后将其转换为 UTC 的代码。因此,当印度 4:00 下午时,格林威治标准时间/UTC 时间是 10:30 上午。而以下代码将其打印为 9:30 pm。因此,不是减去偏移量,而是添加偏移量。从 python 文档 https://docs.python.org/2/library/datetime.html#datetime.datetime.astimezone astimezone 的示例实现来看,如果偏移量为负,它似乎会添加偏移量,但这似乎与它应该做的相反。文档说它调整时间,使 UTC 时间保持不变,但在过去的时区本地时间,这与示例实现相反。

from dateutil.parser import parse
from pytz import timezone

d = parse('Tue Sep 01 2015 16:00:00 GMT+0530')

# Prints datetime.datetime(2015, 9, 1, 16, 0, tzinfo=tzoffset(None, -19800))
print d

utc = timezone('UTC')

# Prints datetime.datetime(2015, 9, 1, 21, 30, tzinfo=<UTC>)
print d.astimezone(utc)

我不确定哪里出了问题。是 astimezone 的实现还是文档或偏移量本身的符号颠倒了?

以下代码片段工作正常。

>>> d = parse('Tue Sep 01 2014 16:00:00 GMT+0530')
>>> ind = timezone('Asia/Kolkata')
>>> d=d.replace(tzinfo=ind)
>>> d
datetime.datetime(2015, 9, 1, 16, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' LMT+5:53:00 STD>)
>>> utc = timezone('UTC')
>>> d.astimezone(utc)
datetime.datetime(2015, 9, 1, 10, 7, tzinfo=<UTC>)

这里我把tzinfo改成了pytz格式。确保所有时区都采用 pytz 格式。

不过,我不确定为什么 IST 是 LMT+5:53:00。发现多年来偏移量发生变化,很久以前就使用 +5:53,但现在我们使用 +5:30。但坦率地说,我对此没有太多想法。

astimezone() 是正确的。 parse() 不正确或输入不明确。 parse()GMT+0530 解释为已弃用的 POSIX 样式 GMT+h 时区格式,其中 utc 偏移符号被反转。参见 Timezone offset sign reversed by Python dateutil?

要修复它,请使用相反的符号:

>>> from dateutil.parser import parse
>>> d = parse('Tue Sep 01 2015 16:00:00 GMT+0530')
>>> utc = d.replace(tzinfo=None) + d.utcoffset() #NOTE: the opposite sign
>>> utc
datetime.datetime(2015, 9, 1, 10, 30)

如果输入可能是明确的(当 parse() returns 正确结果时)那么您不应该手动更改 utc 偏移符号。您可以去除时区并重新应用它:

>>> import pytz
>>> tz = pytz.timezone('Asia/Kolkata')
>>> tz.localize(parse('Tue Sep 01 2015 16:00:00 GMT+0530').replace(tzinfo=None), is_dst=None)
datetime.datetime(2015, 9, 1, 16, 0, tzinfo=<DstTzInfo 'Asia/Kolkata' IST+5:30:00 STD>)
>>> _.astimezone(pytz.utc)
datetime.datetime(2015, 9, 1, 10, 30, tzinfo=<UTC>)

它可能会因不明确或不存在的时间而失败(在 DST 转换期间)。如果您知道输入是 GMT+h 格式,则使用第一个代码示例并手动转换为 UTC。