Pythonでうるう年を判定・カウント・列挙
Pythonの標準ライブラリcalendarモジュールに、うるう年(閏年)を判定したり、指定期間内のうるう年の回数を返す関数が用意されている。
ここでは以下の内容について説明する。
- うるう年のルール
- うるう年かどうか判定:
calendar.isleap()
- 指定期間内のうるう年の回数をカウント:
calendar.leapdays()
- 指定期間内のうるう年を列挙しリスト化
datetime
,date
オブジェクトをうるう年か判定
calendarモジュールを使ってテキストやHTMLのカレンダーを取得・出力する方法については以下の記事を参照。
うるう年のルール
うるう年のルールは以下の通り。
- 西暦年が4で割り切れる年は(原則として)閏年。
- ただし、西暦年が100で割り切れる年は(原則として)平年。
- ただし、西暦年が400で割り切れる年は必ず閏年。
閏年 - Wikipedia
うるう年かどうか判定: calendar.isleap()
ある年がうるう年かどうか判定するにはcalendar.isleap()
を使う。
import calendar
print(calendar.isleap(2019))
# False
print(calendar.isleap(2020))
# True
上述のルール2, 3も正しく判定される。1900年はルール2により平年(うるう年ではない)、2000年はルール3によりうるう年となる。
print(calendar.isleap(1900))
# False
print(calendar.isleap(2000))
# True
なお、calendar.isleap()
のソースコードは以下の通り。単なる%
による余りの判定の組み合わせで、特に難しいプログラムではない。
def isleap(year):
"""Return True for leap years, False for non-leap years."""
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
指定期間内のうるう年の回数をカウント: calendar.leapdays()
期間を指定してその間のうるう年を数えるにはcalendar.leapdays()
を使う。
calendar.leapdays(y1, y2)
のように、2つの年を指定する。対象期間はy1 ≦ x < y2
で、y2
は含まれない。
print(calendar.leapdays(2019, 2030))
# 3
print(calendar.leapdays(2019, 2020))
# 0
指定期間内のうるう年を列挙しリスト化
期間を指定してその間のうるう年を列挙しリスト化するには、calendar.isleap()
をリスト内包表記の条件として使う。
- 関連記事: Pythonリスト内包表記の使い方
print([y for y in range(2019, 2030) if calendar.isleap(y)])
# [2020, 2024, 2028]
print([y for y in range(2000, 2020) if calendar.isleap(y)])
# [2000, 2004, 2008, 2012, 2016]
range(start, end)
の場合、end
はリストに含まれないので注意。
- 関連記事: Pythonのrange関数の使い方
datetime, dateオブジェクトをうるう年か判定
Pythonの標準ライブラリには日時を処理するdatetimeモジュールがある。
datetimeモジュールには日時(日付と時刻)を表すdatetime.datetime
型と日付(年月日)のみを表すdatetime.date
型がある。
これらのオブジェクトが示す年がうるう年かどうかを判定したい場合、どちらもyear
属性で年の値を取得できるので、それをcalendar.isleap()
に渡せばよい。
import calendar
import datetime
dt = datetime.datetime(2019, 1, 1, 10, 10, 10)
print(dt)
# 2019-01-01 10:10:10
print(calendar.isleap(dt.year))
# False
d = datetime.date(2020, 1, 1)
print(d)
# 2020-01-01
print(calendar.isleap(d.year))
# True
関数化すると以下のようになる。引数に指定するのはdatetime.datetime
でもdatetime.date
でもOK。
def isleap_datetime(dt):
return calendar.isleap(dt.year)
print(dt)
# 2019-01-01 10:10:10
print(isleap_datetime(dt))
# False
print(d)
# 2020-01-01
print(isleap_datetime(d))
# True
calendarモジュールを使いたくない場合は以下の通り。お好みで。
def isleap_datetime2(dt):
return dt.year % 4 == 0 and (dt.year % 100 != 0 or dt.year % 400 == 0)
print(dt)
# 2019-01-01 10:10:10
print(isleap_datetime2(dt))
# False
print(d)
# 2020-01-01
print(isleap_datetime2(d))
# True