【问题标题】:Convert UTC datetime with timezone to local将带有时区的 UTC 日期时间转换为本地
【发布时间】:2025-12-10 04:35:01
【问题描述】:

我有一个日期为 UTC 和 tzinfo 的字符串

"Thu, 01 Oct 2015 00:02:01 +0200"

如何将其转换为本地时间以便输出

"2015-10-02 02:02:01"

我试过了

parser.parse("Thu, 01 Oct 2015 00:02:01 +0200")

但我找不到将这个 tzinfo 与时间相加的方法,以获得我的当地时间。

提前致谢

编辑:问题是不同的,因为它包括给定字符串中的时差,重点是添加或减去有时需要更改日期的时差,如提供的示例中所示。

【问题讨论】:

  • 你的意思是datetime.strptime(dte, "%a, %d %b %Y %H:%M:%S %z").astimezone(tz=None)
  • @Prune 不太一样,在这种情况下,时区本身是未知的,只有偏移量(作为字符串)。它可能仍然是重复的,但我不知道它可能在哪里。
  • @PadraicCunningham 这取决于平台 - Windows 无法识别 %z,尽管我认为他们可能已经在 Python 3 的某些版本中修复了这个问题。
  • @MarkRansom,我认为它适用于 >= 3.3,但我从不使用 Windows,所以我可能错了

标签: python python-2.7 datetime


【解决方案1】:

这是一个标准库解决方案:

#!/usr/bin/env python
from datetime import datetime
from email.utils import parsedate_tz, mktime_tz

timestamp = mktime_tz(parsedate_tz("Thu, 01 Oct 2015 00:02:01 +0200"))
print(datetime.fromtimestamp(timestamp)) # get local time

输入时间格式为rfc 5322 time formatunderstood by email module。如果datetime.fromtimestamp() 不使用给定平台上的历史时区数据库,它可能会在过去/未来日期失败。一个可移植的解决方案是使用 pytz 模块,来访问 tz 数据库:

#!/usr/bin/env python
from datetime import datetime
from email.utils import parsedate_tz, mktime_tz
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone() # return pytz tzinfo
timestamp = mktime_tz(parsedate_tz("Thu, 01 Oct 2015 00:02:01 +0200"))
print(datetime.fromtimestamp(timestamp, local_timezone))

【讨论】:

  • 输入时间格式也兼容旧的 rfc 2822 规范,这是 Python 2.x documentation 所引用的。不错的便携和简洁的答案。 +1
  • @martineau: rfc 5322 过时的 2822
  • 是的,我知道...只是指出为什么根据 rfc 2822 编写的旧代码也可以工作。
【解决方案2】:

我认为通过实现几个具体的 tzinfo 类可以满足您的要求:

from datetime import datetime, timedelta, tzinfo
import time as _time

_ZERO = timedelta(0)
_STDOFFSET = timedelta(seconds=-_time.timezone)
if _time.daylight:
    _DSTOFFSET = timedelta(seconds=-_time.altzone)
else:
    _DSTOFFSET = _STDOFFSET

_DSTDIFF = _DSTOFFSET - _STDOFFSET

class UTC(tzinfo):
    """ Concrete tzinfo time zone class for UTC
    """
    def utcoffset(self, dt):
        return _ZERO
    def tzname(self, dt):
        return "UTC"
    def dst(self, dt):
        return _ZERO

UTC = UTC()

class LocalTimezone(tzinfo):
    """ Concrete tzinfo time zone class for current timezone
    """
    def utcoffset(self, dt):
        if self._isdst(dt):
            return _DSTOFFSET
        else:
            return _STDOFFSET

    def dst(self, dt):
        if self._isdst(dt):
            return _DSTDIFF
        else:
            return _ZERO

    def tzname(self, dt):
        return _time.tzname[self._isdst(dt)]

    # everything depends on this private method which assumes 'dt' argument
    # is in local time
    def _isdst(self, dt):
        tt = (dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(), 0, -1)  # last -1 means dst unknown (mktime will fill in)
        stamp = _time.mktime(tt)  # mktime returns secs
        tt = _time.localtime(stamp)  # localtime returns time_struct with tm_isdst attribute
        return tt.tm_isdst > 0

LOCAL = LocalTimezone()

stamp = 'Thu, 01 Oct 2015 00:02:01 +0200'
dt = datetime(*_time.strptime(' '.join(stamp.split()[:-1]),
                              '%a, %d %b %Y %H:%M:%S')[:6], tzinfo=UTC)
local_dt = dt.astimezone(LOCAL)
print(local_dt.strftime('%Y-%M-%d %H:%M:%S'))

【讨论】:

  • ¡这肯定有效,但我从没想过它需要做很多工作。我认为这可以在几行中完成。
  • @Pep: LocalTimezone 使用 time.timezone, time.daylight may fail in some edge cases for the current time 如果本地 utc 偏移量在过去可能不同,它肯定可能会在过去/未来日期失败。
  • 是的,需要相当多的代码,因为普通的 Python 只定义了一个抽象的 tzinfo 类。尽管如此,我提供的只是尝试仅使用内置模块以通用方式解决您的问题的具体实现。 pytz 模块之类的替代方案包含更多代码。之所以需要如此多的代码,是因为看似简单但极其惯用的做法(具有讽刺意味的是,随着时间的推移而变化)的复杂性令人惊讶。
  • 您是否了解 utc 偏移量在不同时间可能不同(与 DST 转换无关),因此 constanttime.timezone 不可能提供正确答案在这种情况下?
最近更新 更多