Python的relativedelta中的非确定性行为
我想要得到一个日期,距离另一个日期早七天。
所以我在控制台里这样做:
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 个回答
如果你只需要处理日期,我建议你使用 datetime
这个模块。
import datetime
old_date = datetime.date(2014, 10, 18)
new_date = old_date - datetime.timedelta(days=7)
输出的结果会是 datetime.date(2014, 10, 11)
。我用过 timedelta
,没有遇到过日期不准确的问题。
假设你的网络服务器设置在美国夏威夷时区,现在的当地时间是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就不重要了,因为你得到的只是年份、月份和日期。
根据你在评论中对函数的描述,你踩到了一个常见的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
的默认值时,这个值不会再被重新计算。所以当第二天到来的时候,它会使用函数定义时得到的那个值。