如何在夏令时区添加每周时间点

时间:2014-07-10 09:46:26

标签: python datetime timezone dst timedelta

我想在本地化日期时间对象中添加或减去周(或天或月或年)。问题是,由于夏令时区,天真的方法会导致1小时的移位。

2014-03-27 12:00正好从冬季到夏季转换。如果我添加一个星期的时间值到这个日期本地化在欧洲/柏林时区,结果将是2014-04-03 13:00。我想在2014-04-03 12:00的同一小时。我找到了解决方案:

from datetime import datetime, timedelta
import pytz
my_tz = pytz.timezone("Europe/Berlin")

def add_relativedelta(date, delta):
    """
    Adds the given timedelta to the given date. Shifts in timezone offsets
    will be removed.
    """
    tz = date.tzinfo
    result = tz.normalize(date + delta)
    if result.utcoffset() != date.utcoffset():
        result = tz.normalize(date.utcoffset() - result.utcoffset() + result)
    return result

date = my_tz.localize(datetime(year=2014, month=3, day=27, hour=12, minute=0))
print """{} Original localized date (winter time)
{} One week later (summer time)
{} Date one week later preserving hour of day (summer time)""".format(date,
                     my_tz.normalize(date + timedelta(days=7)),
                     add_relativedelta(date, timedelta(days=7)))


2014-03-27 12:00:00+01:00 Original localized date (winter time)
2014-04-03 13:00:00+02:00 One week later (summer time)
2014-04-03 12:00:00+02:00 Date one week later preserving hour of day (summer time)

我想知道是否有更通用/更好的解决方案。有没有可以解决这个问题的图书馆?这似乎是一个非常普遍的问题。

3 个答案:

答案 0 :(得分:15)

timedelta(days=7)表示7天,如7*24小时 - 而不是“太阳日”。 如果您将7天添加到时区感知日期时间,您将获得7天后的日期时间 - 与时区中代表的日期时间无关。

您真正想要的是将delta应用于您指定的时间,忽略时区详细信息。请注意区别:

In [13]: print my_tz.normalize( my_tz.localize( dt ) + delta )
2014-04-03 13:00:00+02:00

In [14]: print my_tz.normalize( my_tz.localize( dt + delta ) )
2014-04-03 12:00:00+02:00

因此,如果可能,请在本地化之前将增量应用于日期时间。

答案 1 :(得分:1)

我使用这个简单的代码而不需要其他库:

from datetime import datetime, timedelta
from pytz import timezone

tz = timezone('Europe/Berlin')
dt = tz.localize(datetime(2014, 3, 27, 12))

week_naive = datetime.combine(dt.date() + timedelta(days=7), dt.time())
week_local = dt.tzinfo.localize(week_naive)

print(dt, "Original datetime")
print(week_local, "Next week datetime")

输出:

2014-03-27 12:00:00+01:00 Original datetime
2014-04-03 12:00:00+02:00 Next week datetime

答案 2 :(得分:0)

我试图查找给定日期的一周的开始和结束,因此遇到了这个问题。使用U+1F913包,我可以实现DST感知的时间增量。这是我的操作方式:

def post_params
    params.require(:post).permit(:description, :title, :user_id, json: {}, data: {})
end

请注意,由于夏令时在from dataclasses import dataclass from datetime import datetime import arrow @dataclass(frozen=True) class Week: start: datetime end: datetime def get_week_range(dt: datetime, tz: str) -> Week: """Returns Week instance with localized, time-aware start and end datetimes""" dt = arrow.get(dt, tz) start = dt.shift(days=-dt.weekday()) end = start.shift(days=7).shift(seconds=-1) return Week(start=start, end=end) >>> get_week_range(datetime(2020, 10, 27), "America/Chicago") Week(start=<Arrow [2020-10-26T00:00:00-05:00]>, end=<Arrow [2020-11-01T23:59:59-06:00]>) 时区的凌晨2点11点结束,因此本例中返回的结束日期如何正确调整为-06:00