【问题标题】:How to convert a datetime from one arbitrary timezone to another arbitrary timezone如何将日期时间从一个任意时区转换为另一个任意时区
【发布时间】:2016-07-21 14:49:11
【问题描述】:

假设我在请求中收到一个任意日期时间对象,就像这样,它可能来自任何可能的时区 - 我不知道是哪个时区。 举个例子,假装它来自东海岸

import pytz
from colander import iso8601
...
    ests1 = iso8601.parse_date('2016-04-01T00:00:00.0000-04:00')

假装ests1是进来的对象

使用 pytz,我可以了解一下它的时区

    etz = ests1.timetz()  # 00:00:00-04:00
    etzi = ests1.tzinfo   # <FixedOffset '-04:00' datetime.timedelta(-1, 72000)>
    etzn = ests1.tzname() # '-04:00'  # EST
    edst = ests1.dst()    #  '0:00:00'

请注意,无论 ests1 是什么日期 - dst() 似乎总是返回相同的值

我想做这样的事情:

    psts1 = pytz.timezone(etzn
                     ).localize(dtime.datetime.fromtimestamp(ests1)
                     ).astimezone(pytz.timezone('US/Pacific'))

但这只会导致

UnknownTimeZoneError: '-04:00'

我也试过这个:

def convert_dt_to_pstz(dt):
    pstoffset = -25200 # -7 * 60 * 60   - but what about DST?  how do we tell which offset to use? -8 or -7
    return dt.astimezone(tzoffset(None,pstoffset)) # convert to PST

但问题是我不知道如何判断日期是否需要针对夏令时进行调整。

我也试过这个:

    utc_date = ests1.astimezone(pytz.utc)   # 2016-04-01T04:00:00+00:00
    ptz = pytz.timezone('US/Pacific')
    new_date = utc_date.replace(tzinfo=ptz) # 2016-04-01T04:00:00-07:53

但是看看 new_date 的奇怪结果:-07:53 ??

请注意,我不能使用任何与“现在”或服务器位置相对应的信息,因为它可能在任何地方

【问题讨论】:

  • 请注意,纯数字偏移不会为您提供有关夏令时是否有效的信息。您必须了解有关如何生成时间的更多信息,才能推断出-04:00 来自美国/东部时区,而不是来自巴西。然而,这是一个细节——我认为你的问题很有趣。答案的一部分是“从源时区转换为 UTC;从UTC'转换为目标时区。那么如何精确地进行这些转换就会出现问题。
  • 从 iso8601 格式你无法分辨,它会说 EDT 为 -0400,EST 为 -0500,但 -0400 也可能是 AMT
  • @scope:嗯,有一些方法可以确定夏令时 - 但它很复杂,我想知道是否已经建立了可以完成这项工作的东西。我还没找到呢
  • @slashdottir,你可以从时区(使用 pytz),但不能从 UTC 偏移量

标签: python datetime timezone pytz colander


【解决方案1】:

要将可识别时区的datetime 对象转换为不同的时区use datetime.astimezone() method

pacific_time = ests1.astimezone(pytz.timezone('US/Pacific'))

一般情况下,pytz docs 建议在结果上调用pytz.timezone('US/Pacific').normalize(),但这里不需要它,因为ests1 时区有固定的 UTC 偏移量。

【讨论】:

    【解决方案2】:

    我想我这次做对了:

    from datetime import datetime as dtime
    import pytz
    from colander import iso8601
    
    ests1 = iso8601.parse_date('2016-04-01T00:00:00.0000-04:00')
    epoch = dtime(1970, 1, 1, tzinfo=pytz.UTC)          # 1970-01-01T00:00:00+00:00
    ept = (ests1 - epoch).total_seconds()               # 1459483200.0
    
    utc_date = dtime.fromtimestamp(ept, tz=pytz.UTC)    # 2016-04-01T04:00:00+00:00
    ptz = pytz.timezone('US/Pacific')
    pst_date = dtime.fromtimestamp(ept, tz=ptz)         # 2016-03-31T21:00:00-07:00
    
    ests2 = iso8601.parse_date('2016-02-01T00:00:00.0000-04:00')
    ept2 = (ests2 - epoch).total_seconds()              # 1454299200.00
    
    utc_date2 = dtime.fromtimestamp(ept2, tz=pytz.UTC)  # 2016-02-01T04:00:00+00:00
    pst_date2 = dtime.fromtimestamp(ept2, tz=ptz)       # 2016-01-31T20:00:00-08:00
    

    所以,看起来就这么简单

    def convert_to_tz(dt,tz_new):
       seconds = (dt - epoch).total_seconds()
       return dtime.fromtimestamp(seconds, tz=tz_new)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-23
      • 2015-11-05
      • 2015-02-21
      • 2010-11-26
      • 2018-02-19
      相关资源
      最近更新 更多