Python 将 tzinfo 传递给天真的日期时间,无需 pytz

问题描述 投票:0回答:3

我在 Python 中的日期/时区上苦苦挣扎了太久,并认为有人可以在这里帮助我。

基本上我想在 UTC 中进行转换并考虑到 DST 的变化。

我从 Python 教程之一创建了以下 tzinfo 类(我知道不是 100% 准确,但不需要):

from datetime import tzinfo, timedelta, datetime

ZERO = timedelta(0)
HOUR = timedelta(hours=1)

def first_sunday_on_or_after(dt):
    days_to_go = 6 - dt.weekday()
    if days_to_go:
        dt += timedelta(days_to_go)
    return dt

DSTSTART_2007 = datetime(1, 3, 8, 2)
DSTEND_2007 = datetime(1, 11, 1, 1)
DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
DSTEND_1987_2006 = datetime(1, 10, 25, 1)
DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
DSTEND_1967_1986 = DSTEND_1987_2006

class USTimeZone(tzinfo):

    def __init__(self, hours, reprname, stdname, dstname):
        self.stdoffset = timedelta(hours=hours)
        self.reprname = reprname
        self.stdname = stdname
        self.dstname = dstname

    def __repr__(self):
        return self.reprname

    def tzname(self, dt):
        if self.dst(dt):
            return self.dstname
        else:
            return self.stdname

    def utcoffset(self, dt):
        return self.stdoffset + self.dst(dt)

    def dst(self, dt):
        if dt is None or dt.tzinfo is None:
            # An exception may be sensible here, in one or both cases.
            # It depends on how you want to treat them.  The default
            # fromutc() implementation (called by the default astimezone()
            # implementation) passes a datetime with dt.tzinfo is self.
            return ZERO
        assert dt.tzinfo is self

        # Find start and end times for US DST. For years before 1967, return
        # ZERO for no DST.
        if 2006 < dt.year:
            dststart, dstend = DSTSTART_2007, DSTEND_2007
        elif 1986 < dt.year < 2007:
            dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
        elif 1966 < dt.year < 1987:
            dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
        else:
            return ZERO

        start = first_sunday_on_or_after(dststart.replace(year=dt.year))
        end = first_sunday_on_or_after(dstend.replace(year=dt.year))

        # Can't compare naive to aware objects, so strip the timezone from
        # dt first.
        if start <= dt.replace(tzinfo=None) < end:
            return HOUR
        else:
            return ZERO

另一方面,我在 EST 中有一个任意

date
对象,我想通过考虑 DST 来了解它们相差的小时数。

我尝试过这样的事情:

>>> Eastern = ustimezone.USTimeZone(-5, "Eastern",  "EST", "EDT")
>>> x = datetime.date.today() # I actually get an arbitrary date but this is for the example
>>> x_dt = datetime.datetime.combine(x, datetime.time())
>>> x_dt_tz = x_dt.astimezone(Eastern)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime

我看过几篇帖子,告诉我要使用

localize
模块中的
pytz
,但不幸的是我无法使用其他模块,所以不可能使用
pyzt

有谁知道如何在不使用 pytz 的情况下将这个天真的日期时间放入时区对象中

python timezone
3个回答
16
投票
就其价值而言,@skyl 提供的答案或多或少相当于

pytz

 所做的。

这是相关的

pytz

 来源。  它只是使用 
replace
 kwarg:
datetime
对象上调用
tzinfo

def localize(self, dt, is_dst=False): '''Convert naive time to local time''' if dt.tzinfo is not None: raise ValueError('Not naive datetime (tzinfo is already set)') return dt.replace(tzinfo=self)
    

13
投票
使用

x_dt.replace(tzinfo=Eastern)

从此 Google 网上论坛帖子找到)。

x_dt.replace(tzinfo=Eastern).utcoffset()

 返回 
datetime.timedelta(-1, 72000)
,对应于 -4 小时! (来自问题的评论)


0
投票
从 Python 3.9 开始,您现在可以使用内置库

ZoneInfo:

>>> dt.replace(tzinfo=ZoneInfo("America/Los_Angeles")) >>> print(dt) 2020-10-31 12:00:00-07:00
    
© www.soinside.com 2019 - 2024. All rights reserved.