先日2人のプログラマーさんが、それぞれうるう年の判定をSQLで記述していました。
片方のプログラマーさんは、マイクロソフトのドキュメントに記載されている方法でうるう年を判別していました。
もう片方のプログラマーさんは、独自の方法でうるう年の判別を行っていました。
今回は2人のプログラマーさんが行っていたうるう年の判定について記載します。
マイクロソフトのドキュメント記載のやり方
マイクロソフトのドキュメントにはうるう年の判定方法として次のように記載されています。
年がうるう年かどうかを判断する方法
年が閏年かどうかを判断するには、次の手順を実行します。
- 年が4で割り切れる場合は、手順2に進みます。 それ以外の場合は、手順5に進みます。
- 年が100で割り切れる場合は、手順3に進みます。 それ以外の場合は、手順4に進みます。
- 年が400で割り切れる場合は、手順4に進みます。 それ以外の場合は、手順5に進みます。
- 年はうるう年 (1 年366日) です。
- 年はうるう年ではありません (365 日)。
上記のルール(仕様)をもとにSQLを組むと以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
-- うるう年かどうかを判定する年 DECLARE @YEAR SMALLINT; SET @YEAR = 2020; /* 1.判定する年が 4 で割り切れる場合は2.に進む。割り切れない場合は5.に進む。 2.その年が100で割り切れる場合は3.に進む。割り切れない場合は4.に進む。 3.その年が400で割り切れる場合は4.に進む。割り切れない場合は5.に進む。 4.その年はうるう年。 (この年は366日) 5.その年はうるう年ではない。 (この年は365日) */ DECLARE @IS_LEAP_YEAR BIT; SET @IS_LEAP_YEAR = -- 1.判定する年が 4 で割り切れるか CASE WHEN @YEAR % 4 = 0 THEN -- 2.その年が 100 で割り切れるか CASE WHEN @YEAR % 100 = 0 THEN -- 3.その年が 400 で割り切れるか CASE WHEN @YEAR % 400 = 0 THEN -- 4.その年はうるう年 1 ELSE -- 5.その年はうるう年ではない 0 END ELSE -- 4.その年はうるう年 1 END ELSE -- 5.その年はうるう年ではない 0 END; SELECT @IS_LEAP_YEAR AS [うるう年かどうか]; |
指定した年がうるう年であれば1が表示され、うるう年でなければ0が表示されます。
日付として正しいかどうかを判定するやり方
日付として正しいかどうかを判定する方法は簡単です。
年に2月29日を足して、日付かどうかを関数で判別します。
以下、SQLServerでの例です。
1 2 3 4 5 6 7 8 9 10 11 12 |
-- うるう年かどうかを判定する年 DECLARE @YEAR SMALLINT; SET @YEAR = 2020; DECLARE @DATE VARCHAR(10); -- 年に2月29日を足す SET @DATE = CONVERT(NVARCHAR(4), @YEAR) + '/2/29'; -- ISDATE関数で日付かどうかを判定する DECLARE @IS_LEAP_YEAR BIT; SET @IS_LEAP_YEAR = ISDATE(@DATE); SELECT @IS_LEAP_YEAR AS [うるう年かどうか]; |
MySQLではISDATE関数がないので、DAYOFYEAR関数を使って日付が正しいかどうかを判定します。
DAYOFYEAR関数は渡された値が日付として正しくない場合にNULLを返します。ですので、戻り値がNULLかどうかを検査してあげれば日付として正しいかどうかが分かります。
1 2 |
-- DAYOFYEAR関数で日付かどうかを判定する SET @is_leap_year = DAYOFYEAR(@date); |
関数を作成して試してみる
それぞれの処理をユーザー定義関数として作成して結果を見てみます。
関数作成SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
-- マイクロソフト仕様の関数 CREATE FUNCTION IS_LEAP_YEAR_1(@YEAR SMALLINT) RETURNS BIT AS BEGIN DECLARE @IS_LEAP_YEAR BIT; SET @IS_LEAP_YEAR = -- 1.判定する年が 4 で割り切れるか CASE WHEN @YEAR % 4 = 0 THEN -- 2.その年が 100 で割り切れるか CASE WHEN @YEAR % 100 = 0 THEN -- 3.その年が 400 で割り切れるか CASE WHEN @YEAR % 400 = 0 THEN -- 4.その年はうるう年 1 ELSE -- 5.その年はうるう年ではない 0 END ELSE -- 4.その年はうるう年 1 END ELSE -- 5.その年はうるう年ではない 0 END; RETURN @IS_LEAP_YEAR; END; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- 2月29日の日付判定仕様の関数 CREATE FUNCTION IS_LEAP_YEAR_2(@YEAR SMALLINT) RETURNS BIT AS BEGIN DECLARE @DATE VARCHAR(10); -- 年に2月29日を足す SET @DATE = CONVERT(NVARCHAR(4), @YEAR) + '/2/29'; -- ISDATE関数で日付かどうかを判定する DECLARE @IS_LEAP_YEAR BIT; SET @IS_LEAP_YEAR = ISDATE(@DATE); RETURN @IS_LEAP_YEAR; END; |
関数を呼び出して結果を確認
関数を呼び出してうるう年かどうかの結果を取得します。
対象の年は「2016年」~「2020年」にします。2016年と2020年はうるう年のはずです。
1 2 3 4 5 6 7 8 9 10 11 |
SELECT dbo.IS_LEAP_YEAR_1(2016) AS [MicroSoft_2016], dbo.IS_LEAP_YEAR_2(2016) AS [IsDate_2016], dbo.IS_LEAP_YEAR_1(2017) AS [MicroSoft_2017], dbo.IS_LEAP_YEAR_2(2017) AS [IsDate_2017], dbo.IS_LEAP_YEAR_1(2018) AS [MicroSoft_2018], dbo.IS_LEAP_YEAR_2(2018) AS [IsDate_2018], dbo.IS_LEAP_YEAR_1(2019) AS [MicroSoft_2019], dbo.IS_LEAP_YEAR_2(2019) AS [IsDate_2019], dbo.IS_LEAP_YEAR_1(2020) AS [MicroSoft_2020], dbo.IS_LEAP_YEAR_2(2020) AS [IsDate_2020]; |
それぞれの関数で同様の結果を取得することができました。