note.nkmk.me

Pythonでうるう年を判定・カウント・列挙

Date: 2019-07-29 / tags: Python, 日時処理

Pythonの標準ライブラリcalendarモジュールに、うるう年(閏年)を判定したり、指定期間内のうるう年の回数を返す関数が用意されている。

ここでは以下の内容について説明する。

  • うるう年のルール
  • うるう年かどうか判定: calendar.isleap()
  • 指定期間内のうるう年の回数をカウント: calendar.leapdays()
  • 指定期間内のうるう年を列挙しリスト化
  • datetime, dateオブジェクトをうるう年か判定

calendarモジュールを使ってテキストやHTMLのカレンダーを取得・出力する方法については以下の記事を参照。

スポンサーリンク

うるう年のルール

うるう年のルールは以下の通り。

  1. 西暦年が4で割り切れる年は(原則として)閏年。
  2. ただし、西暦年が100で割り切れる年は(原則として)平年。
  3. ただし、西暦年が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)
source: calendar.py

指定期間内のうるう年の回数をカウント: 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()をリスト内包表記の条件として使う。

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はリストに含まれないので注意。

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
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事