python_cookbook

Python Cookbook [Finding the Date Range for the Current Month : その月は何日まで?] 投稿一覧へ戻る

Tags: datetime , timedelta , range , monthrange , generator , calendar , python , cookbook

Published 2020年4月18日18:17 by T.Tsuyoshi

Problem:
ある月の全ての日を簡単にループ処理したい。


Solution:
対象となる月の日数分のリストを用意するような必要はありません。
開始日(その月の1日)と終了日(翌月の1日)を取得し、datetime.timedelta オブジェクトを利用してその間を1日ずつループしていきます。

from datetime import datetime, date, timedelta
import calendar

def get_month_range(start_date = None):
if start_date is None:
start_date = date.today()

start_date = start_date.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)



ここでは、対象となる月の初日を求めるために date 又は datetime オブジェクトの replace 関数を利用しています。


replace 関数は、対象が date オブジェクトであれば変換結果も date を、datetime オブジェクトであれば datetime をちゃんと返してくれます。使い勝手がいいです。


続いて、calendar.monthrange() 関数を利用して対象月の日数を取得しています。この関数は、対象月の初日の曜日と日数をタプルで返します。


最後に、取得した日数で timedelta オブジェクトを作成し加算することで最終日を取得しています。
この「最終日」は実は対象月の翌月の1日です。


ここでこのような仕様にしているのは、Python におけるスライスや範囲の扱いが「最終点は含まない」となっているため、それに合わせるためです。


作成した関数を利用すれば、対象月の初日から最終日まで簡単にループできます。

a_day = timedelta(days = 1)
first_day, last_day = get_month_range(date(2020, 2, 18))
while first_day < last_day:
print(first_day)
first_day += a_day

# 2020-02-01
# 2020-02-02
# ...
# 2020-02-28
# 2020-02-29
#
# 2020年は閏年なので 29 日までですね。



first_day, last_day = get_month_range(date(2019, 2, 3))
while first_day < last_day:
print(first_day)
first_day += a_day

# 2019-02-01
# 2019-02-02
# ...
# 2019-02-27
# 2019-02-28




もしかすると、組み込みの range() 関数と同様な動きを日付に対して行うような関数を用意できれば理想的かもしれません。


実は generator を利用することで非常に簡単に実装できます。

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



使い方の一例です。

for d in date_range(datetime(2020, 4, 18), datetime(2020, 5, 7), timedelta(hours = 6)):
print(d)

# 2020-04-18 00:00:00
# 2020-04-18 06:00:00
# 2020-04-18 12:00:00
# ...
# 2020-05-06 06:00:00
# 2020-05-06 12:00:00
# 2020-05-06 18:00:00

この投稿をメールでシェアする

0 comments

コメントはまだありません。

コメントを追加する(不適切と思われるコメントは削除する場合があります)