Python - 从 DST 调整的本地时间到 UTC

Posted

技术标签:

【中文标题】Python - 从 DST 调整的本地时间到 UTC【英文标题】:Python - From DST-adjusted local time to UTC 【发布时间】:2011-10-11 16:48:16 【问题描述】:

某家银行在全球所有主要城市都设有分行。它们都在当地时间上午 10:00 开放。如果在使用 DST 的时区内,那么当地的开放时间当然也遵循 DST 调整的时间。那么我如何从本地时间转到UTC时间。

我需要的是这样的函数to_utc(localdt, tz)

参数:

localdt:本地时间,作为天真的日期时间对象,经过 DST 调整 tz:TZ 格式的时区,例如“欧洲/柏林”

返回:

日期时间对象,UTC,时区感知

编辑:

最大的挑战是检测本地时间是否在一个有夏令时的时段,这也意味着它是夏令时调整的。

对于夏季 +1 DST 的“欧洲/柏林”:

1 月 1 日 10:00 => 1 月 1 日 9:00 UTC 7 月 1 日 10:00 => 7 月 1 日 8:00 UTC

对于没有 DST 的“非洲/拉各斯”:

1 月 1 日 10:00 => 1 月 1 日 9:00 UTC 7 月 1 日 10:00 => 7 月 1 日 9:00 UTC

【问题讨论】:

陷阱:2011 年 3 月 27 日 01:00,时钟被调到 02:00。所以 01:00 和 02:00 之间的时间间隔是无效的。 2011 年 10 月 30 日 01:00,时钟将调回 00:00。所以 00:00 和 01:00 之间的时间间隔是不明确的。 pytz 描述了 DST 转换不适用于任何具有时区的时区。如果专门为帮助处理时区而构建的软件包不支持这一点,那么您自己做正确的工作就太多了。你必须满足于几乎正确。 【参考方案1】:

使用pytz,尤其是它的localize method:

import pytz
import datetime as dt

def to_utc(localdt,tz):
    timezone=pytz.timezone(tz)
    utc=pytz.utc
    return timezone.localize(localdt).astimezone(utc)

if __name__=='__main__':
    for tz in ('Europe/Berlin','Africa/Lagos'):
        for date in (dt.datetime(2011,1,1,10,0,0),
                 dt.datetime(2011,7,1,10,0,0),
                 ):
            print('tz:15 l --> u'.format(
                tz=tz,
                l=date.strftime('%b %d %H:%M'),
                u=to_utc(date,tz).strftime('%b %d %H:%M %Z')))

产量

Europe/Berlin   Jan 01 10:00 --> Jan 01 09:00 UTC
Europe/Berlin   Jul 01 10:00 --> Jul 01 08:00 UTC
Africa/Lagos    Jan 01 10:00 --> Jan 01 09:00 UTC
Africa/Lagos    Jul 01 10:00 --> Jul 01 09:00 UTC

【讨论】:

注意:有些当地时间是不明确的。尽管在 DST 过渡期间银行不太可能同时开张;你可以使用is_dst=None 参数.localize() 来断言。【参考方案2】:
from datetime import datetime, tzinfo, timedelta

class GMT1(tzinfo):
    def utcoffset(self, dt):
        return timedelta(hours=1)
    def dst(self, dt):
        return timedelta(0)
    def tzname(self,dt):
        return "Europe/Prague"
year, month, day = 2011, 7, 23
dt = datetime(year, month, day, 10)

class UTC(tzinfo):
    def utcoffset(self, dt):
        return timedelta(0)
    def dst(self, dt):
        return timedelta(0)
    def tzname(self,dt):
        return "UTC"

def utc(localt, tz):
    return localt.replace(tzinfo=tz).astimezone(UTC())

print utc(dt, GMT1())

新版本。这可以满足您的要求 - 采用原始日期时间和时区并返回 UTC 日期时间。

【讨论】:

您的解决方案未能解决主要挑战:自动处理夏令时。 我不确定我是否理解。如果您使用的tzinfo 有一个timedelta 用于夏令时,它应该由utcnow() 自动处理? 我现在明白了。更新了我的答案。 仍然不确定这如何解决 DST 问题。七月的布拉格应该在 UTC+2(包括 DST)。您仍然为 GMT1 中的 dst 返回 timedelta(0):确实适用于 GMT+1,但这不是“欧洲/布拉格”的时区。

以上是关于Python - 从 DST 调整的本地时间到 UTC的主要内容,如果未能解决你的问题,请参考以下文章

让 mktime() 在 C++ 中忽略 DST 和本地时区

python右手与左手时间戳和DST

org.joda.time |夏令时 (DST) 和本地时区偏移

Python,Pandas:tz_localize AmbiguousTimeError:无法用非 DST 日期推断 dst 时间

检测当前是不是启用 DST

如何确定 DST 何时在 Python 中的特定位置开始或结束? [复制]