Python的relativedelta中的非确定性行为

0 投票
3 回答
992 浏览
提问于 2025-04-28 09:40

我想要得到一个日期,距离另一个日期早七天。

所以我在控制台里这样做:

import datetime
from dateutil.relativedelta import relativedelta

dt = datetime.date(2014, 10, 18)
dt_minus_one_week = datetime.date(2014, 10, 18) - relativedelta(days=7)

结果是,正如我预期的那样,得到了 datetime.date(2014, 10, 11)。但是,我在运行一个网络服务(用的是eve,不过我觉得这并不重要)的时候,当我调用这个方法来获取早一周的日期时,却得到了 datetime.date(2014, 10, 10)。代码和上面的一模一样。

如果我重启这个应用,日期就会变成我预期的那样。为什么会这样呢?是因为 relativedelta 不确定吗?有没有什么办法可以“重置”它,让我再次得到正确的值?

暂无标签

3 个回答

1

如果你只需要处理日期,我建议你使用 datetime 这个模块。

import datetime

old_date = datetime.date(2014, 10, 18)

new_date = old_date - datetime.timedelta(days=7)

输出的结果会是 datetime.date(2014, 10, 11)。我用过 timedelta,没有遇到过日期不准确的问题。

1

假设你的网络服务器设置在美国夏威夷时区,现在的当地时间是2014年10月17日晚上11点。那么

In [57]: datetime.datetime(2014, 10, 17, 23, 0, 0, tzinfo=pytz.timezone('US/Pacific')).date()
Out[57]: datetime.date(2014, 10, 17)

但是,美国太平洋时区的当前时间是

In [44]: now = datetime.datetime(2014, 10, 17, 23, 0, 0)

In [45]: hawaii = pytz.timezone('US/Hawaii')

In [46]: pacific = pytz.timezone('US/Pacific')

In [47]: pacific.normalize(hawaii.localize(now).astimezone(pacific)).date()
Out[47]: datetime.date(2014, 10, 18)

这会导致你看到的现象。

简单来说,你几乎不想通过直接提供给tzinfo来创建一个带时区的日期时间对象:

datetime.datetime.now(pytz.timezone('US/Pacific')).date()

如果你在使用pytz库,应该使用pytz时区的localize方法:

tzone.localize(naive_date)

顺便提一下,

datetime.datetime.now(pytz.timezone('US/Pacific')).date()

总是等同于

datetime.datetime.now().date()

或者

datetime.date.today()

datetime.datetime.now(pytz.timezone('US/Pacific'))datetime.datetime.now() 是一样的,唯一的区别是tzinfo被设置为pytz.timezone('US/Pacific'),但是如果你接着调用date方法,那么tzinfo就不重要了,因为你得到的只是年份、月份和日期。

4

根据你在评论中对函数的描述,你踩到了一个常见的Python“雷区”。

def get_d_minus_one_pacific_local_date():
    return datetime.datetime.now(
            pytz.timezone('US/Pacific')).date() - relativedelta(days=1)

def get_relative_date(init=get_d_minus_one_pacific_local_date(), *args, **kwargs):
    return init + datetime.timedelta(*args, **kwargs)

# ...
get_relative_date(days=-7)

当你在get_relative_date函数定义中设置init的默认值时,这个值不会再被重新计算。所以当第二天到来的时候,它会使用函数定义时得到的那个值。

详细信息请查看:https://stackoverflow.com/a/530768/632706

撰写回答