如何将一个来自任意时区的日期时间转换成另一个任意时区的日期时间

3

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

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

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


3
注意,纯粹的数字偏移量无法告诉你夏令时是否生效。你需要了解更多有关时间生成方式的信息,才能推断出“-04:00”是来自美国东部时区而不是巴西等其他地方。不过这只是个细节——我认为你的问题很有趣。回答的一部分是:“从源时区转换到UTC;从UTC转换到目标时区”。然后,还存在如何准确进行这些转换的问题。 - Jonathan Leffler
从 iso8601 格式无法判断,它会显示 EDT 为 -0400,EST 为 -0500,但 -0400 也可能是 AMT。 - scope
@范围:嗯,有方法可以确定夏令时-但这很复杂,我想知道是否已经有现成的东西可以完成这项工作。尽管我还没有找到它。 - slashdottir
1
@slashdottir,你可以使用pytz从时区获取时间,但不能从UTC偏移量获取。 - scope
2个回答

3

要将带时区的 datetime 对象转换为不同的时区,请使用 datetime.astimezone() 方法

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

通常来说,pytz文档建议在结果上调用pytz.timezone('US/Pacific').normalize(),但是这里不需要,因为ests1时区具有固定的UTC偏移量。

0

我想这次我做对了:

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接