每月的第一天很容易构建,下个月的第一天也是如此。一旦你有了这些,剩下的就更容易了。正如 OP 所指出的,该calendar.monthrange
函数为我们提供了最易读的方法来获取一个月的最后一天。
>>> from datetime import date, year
>>> import calendar
>>> def first_day(dt):
... # Simply copy year and month into new date instance
... return date(dt.year, dt.month, 1)
...
>>> def last_day(dt):
... days_in_month = calendar.monthrange(dt.year, dt.month)[1]
... return date(dt.year, dt.month, days_in_month)
...
>>> nth_day = 32
>>> day_of_year = date(2012, 1, 1) + timedelta(days=nth_day - 1)
>>> day_of_year
datetime.date(2012, 2, 1)
>>> first_day(day_of_year), last_day(day_of_year)
(datetime.date(2012, 2, 1), datetime.date(2012, 2, 29))
>>> day_of_year - first_day(day_of_year), last_day(day_of_year) - day_of_year
(datetime.timedelta(0), datetime.timedelta(28))
要将这些技术组合成一个功能:
def delta_to_start_and_end(year, day_of_year):
dt = date(year, 1, 1) + timedelta(days=(day_of_year - 1))
def first_day(dt):
return date(dt.year, dt.month, 1)
def last_day(dt):
days_in_month = calendar.monthrange(dt.year, dt.month)[1]
return date(dt.year, dt.month, days_in_month)
return (dt - first_day(dt)).days, (last_day(dt) - dt).days
输出:
>>> delta_to_start_and_end(2012, 32)
(0, 28)
>>> delta_to_start_and_end(2011, 32)
(0, 27)
>>> delta_to_start_and_end(2012, 34)
(2, 26)
>>> delta_to_start_and_end(2012, 364)
(28, 2)
我不确定您是否要添加1
到这两个值中的每一个;目前,当月的第一天(第一个示例)将您0
作为第一个值,将 (days-in-the-month - 1) 作为第二个值,因为这是与这些点的天数差。如果您需要这些,在函数的最后一行添加+ 1
两次是微不足道的。delta_to_start_and_end
作为历史记录,此答案的先前版本使用不同的方法来计算没有日历模块的一个月的最后一天:
def last_day(dt):
rest, month = divmod(dt.month, 12)
return date(dt.year + rest, month + 1, 1) - timedelta(days=1)
这个函数使用divmod
内置函数来处理“当前月份是十二月”的边缘情况;在这种情况下,下个月不是13
,但是1
我们也需要将年份增加一。将数字滚动回“开始”是数字的模数,但该divmod
函数也为我们提供了除数,1
如果当前月份是12
. 这为我们提供了一个方便的指标,何时增加年份。