使用 pytz 进行日期时间时区转换
Posted
技术标签:
【中文标题】使用 pytz 进行日期时间时区转换【英文标题】:Datetime Timezone conversion using pytz 【发布时间】:2015-02-16 08:42:50 【问题描述】:这只是pytz
上的另一个帖子。
有两个函数可以在两个时区之间转换日期时间对象。第二个功能适用于所有情况。第一个函数在两种情况下失败,(3)和(4)。类似的SO post 没有这样的问题。任何基于localize(datetime.datetime)
和replace(tzinfo)
之间差异的解释都会有很大帮助。
>>> from dateutil.parser import parse
>>> import pytz
第一个功能(越野车)
下面的函数使用datetime.datetime.replace(tzinfo)
。
def buggy_timezone_converter(input_dt, current_tz='UTC', target_tz='US/Eastern'):
'''input_dt is a datetime.datetime object'''
current_tz = pytz.timezone(current_tz)
target_tz = pytz.timezone(target_tz)
target_dt = input_dt.replace(tzinfo=current_tz).astimezone(target_tz)
return target_tz.normalize(target_dt)
现在注意四个日期时间转换。
(1) 从 UTC 到 EST -- OK
>>> buggy_timezone_converter(parse('2013-02-26T04:00:00'))
Out[608]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>)
(2) 从 UTC 到 EDT -- OK
>>> buggy_timezone_converter(parse('2013-05-26T04:00:00'))
Out[609]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
(3) 从 EST 到 UTC - 不正确。时间偏移为 4 小时 56 分钟。应该是5小时
>>> buggy_timezone_converter(parse('2013-02-26T04:00:00'), target_tz='UTC', current_tz='US/Eastern')
Out[610]: datetime.datetime(2013, 2, 26, 8, 56, tzinfo=<UTC>)
(4) 从 EDT 到 UTC——不正常。时间偏移为 4 小时 56 分钟。应该是4小时。不考虑夏令时。
>>> buggy_timezone_converter(parse('2013-05-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
Out[611]: datetime.datetime(2013, 5, 26, 8, 56, tzinfo=<UTC>)
第二个功能(完美运行)
下面的函数使用pytz.timezone.localize(datetime.datetime)
。效果很好
def good_timezone_converter(input_dt, current_tz='UTC', target_tz='US/Eastern'):
current_tz = pytz.timezone(current_tz)
target_tz = pytz.timezone(target_tz)
target_dt = current_tz.localize(input_dt).astimezone(target_tz)
return target_tz.normalize(target_dt)
(1) 从 UTC 到 EST -- OK
>>> good_timezone_converter(parse('2013-02-26T04:00:00'))
Out[618]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=<DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD>)
(2) 从 UTC 到 EDT -- OK
>>> good_timezone_converter(parse('2013-05-26T04:00:00'))
Out[619]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
(3) 从 EST 到 UTC -- 好的。
>>> good_timezone_converter(parse('2013-02-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
Out[621]: datetime.datetime(2013, 2, 26, 9, 0, tzinfo=<UTC>)
(4) 从 EDT 到 UTC -- 好的。
>>> good_timezone_converter(parse('2013-05-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
Out[620]: datetime.datetime(2013, 5, 26, 8, 0, tzinfo=<UTC>)
【问题讨论】:
无法重现:>>> timezone_converter(datetime.datetime(2013,02,26,4,0,0,0), target_tz='UTC', current_tz='US/Eastern')
datetime.datetime(2013, 2, 26, 9, 0, tzinfo=<UTC>)
抱歉,忘记添加导入行 >>> from dateutil.parser import parse >>> import pytz
您的问题与pytz localize vs datetime replace 重复,或者如果您对现有答案不满意,您应该提出更具体的问题 (update the current question)。请为第一个和第二个函数使用不同的名称,例如 convert_tz_replace()
和 convert_tz()
。
@MarkRansom:再次检查(更新pytz
)。 timezone_converter_replace(datetime(2013,2,26,4,0,0,0), target_tz='UTC', current_tz='US/Eastern')
-> datetime.datetime(2013, 2, 26, 8, 56, tzinfo=<UTC>)
即 .replace()
失败,如记录。
@J.F.Sebastian 这是我测试的直接复制/粘贴。我不知道为什么我得到了不同的结果,但我做到了。也许这是某种线索。
【参考方案1】:
我假设您有以下问题:
为什么第一个函数适用于 UTC 时区? 为什么'US/Eastern'
时区(DstTzInfo
实例)失败?
为什么第二个函数对所有提供的示例都有效?
第一个函数不正确,因为它使用d.replace(tzinfo=dsttzinfo_instance)
而不是dsttzinfo_instance.localize(d)
。
第二个函数在大多数情况下都是正确的,除了在不明确或不存在的时间(例如,在 DST 转换期间)——您可以通过将 is_dst
参数传递给 .localize()
来更改行为:False
(默认)/ True
/None
(引发异常)。
第一个函数适用于 UTC 时区,因为它对于任何日期都有固定的 UTC 偏移量(零)。其他时区,例如 America/New_York
可能在不同时间有不同的 UTC 偏移量(夏令时、战争时间、一些当地政客可能认为是个好主意的任何时间——它可以是任何东西—— tz 数据库在大多数情况下都有效)。要实现tzinfo.utcoffset(dt)
、tzinfo.tzname(dt)
、tzinfo.dst(dt)
方法pytz
使用DstTzInfo
实例的集合,每个实例具有不同的(_tzname, _utcoffset, _dst)
属性集。给定dt
(日期/时间)和is_dst
,.localize()
方法会从集合中选择一个合适的(在大多数情况下,但并非总是)DstTzInfo
实例. pytz.timezone('America/New_York')
返回一个带有(_tzname, _utcoffset, _dst)
属性的DstTzInfo
实例,这些属性对应于一些未记录 时刻(不同的pytz
版本可能返回不同的值——当前版本可能返回tzinfo
实例对应于 zoneinfo 可用的最早日期 - 大多数时候你不想要这个值:我认为选择默认值背后的动机是突出错误(将 pytz.timezone
传递给 datetime
构造函数或.replace()
方法)。
总结一下:.localize()
选择合适的 utcoffset、tzname、dst 值,.replace()
使用默认(不合适的)值。 UTC 只有一组 utcoffset、tzname、dst,因此可以使用默认值,.replace()
方法适用于 UTC 时区。您需要传递一个日期时间对象和is_dst
参数来为其他时区选择适当的值,例如'America/New_York'
。
原则上,pytz
可以调用localize()
方法来实现utcoffset()
、tzname()
、dst()
方法,即使dt.tzinfo == self
:它会使这些方法在时间为 O(log n) 其中@ 987654360@ 是具有不同 (utcoffset, tzname, dst) 值的间隔数,但 datetime
构造函数和 .replace()
将按原样工作,即显式 localize()
调用仅需要传递 is_dst
。
【讨论】:
以上是关于使用 pytz 进行日期时间时区转换的主要内容,如果未能解决你的问题,请参考以下文章
python 使用`pytz`将时间和日期对话转换为其他时区。
Python pytz 时区转换返回的值与不同日期的时区偏移量不同