【Python】うるう年を判定

2021年12月1日

Pythonでうるう年を判定やカウント、列挙させる方法について紹介します。



うるう年を判定するcalendar.isleap()

Pythonでその年がうるう年かを判定するにはcalendar.isleap()を使います。

()の中にint型を引数として与えることで判定します。

# うるう年かを判定

import calendar

print(calendar.isleap(2020))
print(calendar.isleap(2021))
True
False

うるう年の条件とcalendar.isleap()の中身

うるう年の条件は以下のように明確に決まっています。

1.西暦年が4で割り切れる年は(原則として)閏年。

2.ただし、西暦年が100で割り切れる年は(原則として)平年。

3.ただし、西暦年が400で割り切れる年は必ず閏年。

Wikipedia-閏年より抜粋

これら3つの条件を調べるためにcalendar.isleap()は以下のようなプログラムになっています。

def isleap(year: int) -> bool:
  """西暦year年は閏年か"""
  return year % 4 == 0 and year % 100 != 0 or year % 400 == 0

year % 4 == 0はyearが4で割り切れる、つまり4で割って余りが0かどうか調べています。

year % 100 != 0はyearが100で割り切れない、つまり100で割った余りが0でないかを調べています。

year % 400 == 0はyearが400で割り切れる、つまり400で割って余りが0かどうか調べています。

and演算子は日本語でのxかつyに相当し、or演算子はどちらか一方でもという意味です。

上のコードの場合だと「4で割り切れて100で割り切れない」または「4で割り切れて400で割り切れる」とうるう年と判定されます。

# うるう年かを判定

import calendar

print(calendar.isleap(1900))
print(calendar.isleap(2000))
False
True

2000年は4で割り切れて400で割り切れるので閏年と判定されます。

一方1900年は4で割り切れるものの100で割り切れて400で割り切れないので平年と判定されます。

入力された年がうるう年か判定

キーボードから入力された年がうるう年かどうか判定するプログラムに書き換えると下のコードのようになります。

# 入力された年がうるう年かを判定

import calendar

print('入力された年が閏年か判定します。')
y = int(input('西暦何年 : '))

if calendar.isleap(y) == 0:
  print('閏年ではありません。')
else:
  print('閏年です。')
入力された年が閏年か判定します。
西暦何年 : 2000
閏年です。
入力された年が閏年か判定します。
西暦何年 : 1900
閏年ではありません。

calendar.isleap()の返却値はTrueかFalseです。

当然うるう年ならTrue、そうでないならFalseと判定しています。

論理値は内部的にFalseが0、Trueが1として表されています。

それらを応用してcalendar.isleap()の返却値がFalseつまり0の時に「閏年ではありません。」と表示します。

calendar.isleap()の返却値がFalseでない(True)つまり0ではなく1の時に「閏年です。」と表示させています。

Falseが0、Trueが1を応用してその年の日数を求めるプログラムを作成すると以下のコードのようになります。

# うるう年かを判定(日数で判定結果を表示)

import calendar

print('入力された年の日数を求めます。')
y = int(input('西暦何年 : '))
print(f'{y}年は{365 + calendar.isleap(y)}日です。')
入力された年の日数を求めます。
西暦何年 : 2000
2000年は366日です。
入力された年の日数を求めます。
西暦何年 : 1900
1900年は365日です。

calendar.isleap()の返却値がTrueつまり1を365に足して366日と表示され2000年が閏年であるとわかります。

calendar.isleap()の返却値がFalseつまり0を365に足して365日と表示され1900年が閏年でないとわかります。

指定期間内のうるう年の回数をカウントする
calendar.leapdays()

指定した期間内のうるう年の回数をカウントするにはcalendar.leapdays()を使います。

calendar.leapdays(y1, y2)とすることでy1年以上y2年未満内のうるう年の回数を数えます。

スライス表記と同様なので指定期間がy1 ≦ x < y2であることに注意します。

# 指定期間内のうるう年の回数をカウント

import calendar

print(calendar.leapdays(2019, 2021))

print(calendar.leapdays(2019, 2024))
1
1

(2019, 2021)では2020の1つがカウントされ1になります。

(2019, 2024)では2024は範囲に含まれず2020の1つがカウントされ1になります。

指定期間内のうるう年を列挙してリスト化

指定した期間内のうるう年を列挙するにはcalendar.isleap()をリスト内包表記の条件として使います。

calendar.leapdays()と同様に指定期間がy1 ≦ x < y2であることに注意します。

# 指定期間内のうるう年を列挙

import calendar

print([y for y in range(2019, 2021) if calendar.isleap(y)])

print([y for y in range(2000, 2020) if calendar.isleap(y)])
[2020]
[2000, 2004, 2008, 2012, 2016]


現在がうるう年であるか判定

現在時刻はdatetimeモジュールのdatetime.datetime.now()で取得できます。

現在が閏年であるか判定するにはyear属性で年の値を取得してcalendar.isleap()で調べればわかります。

# 現在がうるう年であるか判定

import calendar
import datetime

dt = datetime.datetime.now()
print(dt)

print(calendar.isleap(dt.year))
2021-11-22 00:56:48.916769
False

datetimeモジュールには日時と時刻を表すdatetime.datetime型と、年と日時と時刻を表すdatetime.date型があります。

どちらも上のコードのようにyear属性で年の値を取得すれば閏年かを判定できます。

# datetimeモジュールでのうるう年であるかの判定

import calendar
import datetime

dt1 = datetime.datetime(2020, 1, 1, 11, 11, 11)
print(dt1)

print(calendar.isleap(dt1.year))

dt2 = datetime.date(2021, 1, 1)
print(dt2)

print(calendar.isleap(dt2.year))
2020-01-01 11:11:11
True
2021-01-01
False