使用pytz的Datetime时区转换

时间:2014-12-17 17:48:06

标签: python python-2.7 datetime timezone pytz

这只是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 - 好的

>>> 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 - 好的

>>> 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 - 好的

>>> 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 - 好的

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

1 个答案:

答案 0 :(得分:16)

我假设你有这些问题:

  • 为什么第一个函数适用于UTC时区?
  • 为什么'US/Eastern'时区(DstTzInfo实例)失败?
  • 为什么第二个函数适用于所有提供的示例?

第一个功能不正确,因为它使用d.replace(tzinfo=dsttzinfo_instance)代替dsttzinfo_instance.localize(d)

第二个函数在大多数情况下是正确的,除非在模糊或不存在的时间期间,例如,在DST转换期间 - 您可以通过将is_dst参数传递给.localize()来更改行为:{{1 (默认)/ False / True(引发异常)。

第一个函数适用于UTC时区,因为它对任何日期都有固定的utc偏移量(零)。其他时区如None可能在不同的时间有不同的utc偏移(夏令时,战争时间,某些当地政客可能认为是个好主意的任何时间 - 它可以是任何 - tz数据库在大多数情况下都有效)。要实施America/New_Yorktzinfo.utcoffset(dt)tzinfo.tzname(dt)方法tzinfo.dst(dt)使用pytz个实例的集合,每个实例都具有不同的DstTzInfo属性集。给定(_tzname, _utcoffset, _dst)(日期/时间)dt is_dst方法选择适当的(在大多数情况下,并非总是){来自集合的{1}}实例。 .localize()返回DstTzInfo个实例,其pytz.timezone('America/New_York')个属性对应于某些未记录的时刻(不同的DstTzInfo版本可能会返回不同的值 - 当前版本可以返回与zoneinfo可用的最早日期相对应的(_tzname, _utcoffset, _dst)实例 - 您大多数时间不需要此值:我认为选择默认值背后的动机是突出显示错误(将pytz传递给tzinfo构造函数或pytz.timezone方法)。

总结:datetime选择适当的utcoffset,tzname,dst值,.replace()使用默认(不合适)值。 UTC只有一组utcoffset,tzname,dst因此可以使用默认值,.localize()方法适用于UTC时区。您需要传递日期时间对象和.replace()参数,以便为其他时区选择适当的值,例如.replace()

原则上,is_dst可以调用'America/New_York'方法来实现pytzlocalize()utcoffset()方法,即使tzname():它会使这些方法O(log n)及时dst()是具有不同(utcoffset,tzname,dst)值的区间数,但dt.tzinfo == self构造函数和n将按原样工作,即明确的datetime调用只需要传递.replace()