3.14 計(jì)算當(dāng)前月份的日期范圍

2018-02-24 15:26 更新

問題

你的代碼需要在當(dāng)前月份中循環(huán)每一天,想找到一個(gè)計(jì)算這個(gè)日期范圍的高效方法。

解決方案

在這樣的日期上循環(huán)并需要事先構(gòu)造一個(gè)包含所有日期的列表。你可以先計(jì)算出開始日期和結(jié)束日期,然后在你步進(jìn)的時(shí)候使用 datetime.timedelta 對象遞增這個(gè)日期變量即可。

下面是一個(gè)接受任意datetime對象并返回一個(gè)由當(dāng)前月份開始日和下個(gè)月開始日組成的元組對象。

from datetime import datetime, date, timedelta
import calendar

def get_month_range(start_date=None):
    if start_date is None:
        start_date = date.today().replace(day=1)
    _, days_in_month = calendar.monthrange(start_date.year, start_date.month)
    end_date = start_date + timedelta(days=days_in_month)
    return (start_date, end_date)

有了這個(gè)就可以很容易的在返回的日期范圍上面做循環(huán)操作了:

>>> a_day = timedelta(days=1)
>>> first_day, last_day = get_month_range()
>>> while first_day < last_day:
...     print(first_day)
...     first_day += a_day
...
2012-08-01
2012-08-02
2012-08-03
2012-08-04
2012-08-05
2012-08-06
2012-08-07
2012-08-08
2012-08-09
#... and so on...

討論

上面的代碼先計(jì)算出一個(gè)對應(yīng)月份第一天的日期。一個(gè)快速的方法就是使用 datedatetime 對象的 replace() 方法簡單的將 days 屬性設(shè)置成1即可。replace() 方法一個(gè)好處就是它會(huì)創(chuàng)建和你開始傳入對象類型相同的對象。所以,如果輸入?yún)?shù)是一個(gè)date實(shí)例,那么結(jié)果也是一個(gè)date實(shí)例。同樣的,如果輸入是一個(gè)datetime實(shí)例,那么你得到的就是一個(gè)datetime實(shí)例。

然后,使用 calendar.monthrange() 函數(shù)來找出該月的總天數(shù)。任何時(shí)候只要你想獲得日歷信息,那么calendar模塊就非常有用了。monthrange() 函數(shù)會(huì)返回包含星期和該月天數(shù)的元組。

一旦該月的天數(shù)已知了,那么結(jié)束日期就可以通過在開始日期上面加上這個(gè)天數(shù)獲得。有個(gè)需要注意的是結(jié)束日期并不包含在這個(gè)日期范圍內(nèi)(事實(shí)上它是下個(gè)月的開始日期)。這個(gè)和Python的 slicerange 操作行為保持一致,同樣也不包含結(jié)尾。

為了在日期范圍上循環(huán),要使用到標(biāo)準(zhǔn)的數(shù)學(xué)和比較操作。比如,可以利用 timedelta 實(shí)例來遞增日期,小于號<用來檢查一個(gè)日期是否在結(jié)束日期之前。

理想情況下,如果能為日期迭代創(chuàng)建一個(gè)同內(nèi)置的 range() 函數(shù)一樣的函數(shù)就好了。幸運(yùn)的是,可以使用一個(gè)生成器來很容易的實(shí)現(xiàn)這個(gè)目標(biāo):

def date_range(start, stop, step):
    while start < stop:
        yield start
        start += step

下面是使用這個(gè)生成器的例子:

>>> for d in date_range(datetime(2012, 9, 1), datetime(2012,10,1),
                        timedelta(hours=6)):
...     print(d)
...
2012-09-01 00:00:00
2012-09-01 06:00:00
2012-09-01 12:00:00
2012-09-01 18:00:00
2012-09-02 00:00:00
2012-09-02 06:00:00
...
>>>

這種實(shí)現(xiàn)之所以這么簡單,還得歸功于Python中的日期和時(shí)間能夠使用標(biāo)準(zhǔn)的數(shù)學(xué)和比較操作符來進(jìn)行運(yùn)算。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號