BLOG

閏年とプログラム

ひらの

こんにちは、ひらのです。
2024年の2月は「閏年」ですね。

閏年だからといって何か特別なことがあるわけではないのですが…

閏年と言えば、プログラミング入門でお馴染みのアレです。

「特定の年が閏年かそうでないかを判定するプログラムを作成しなさい」

というよく聞くアレ。

今回は私もウン十年ぶりに初心に戻って…閏年判定プログラムについて考えてみようと思います。

閏年とは

そもそも閏年とは…

閏年(leap year、intercalary year)とは…
閏(1年の月数や日数が普段の年よりも多いこと)のある年である
これに対し、閏年ではない年を平年(common year)と呼ぶ。

Wikipediaより引用

24時間365日でカウントしてるとちょっとズレていくので閏を設けて時差を合わせましょう。ってことですね。

グレゴリオ暦

この長い時間かけてズレてい行く問題を解決するために昔の頭の良い人達が色々と考えて…
グレゴリオ暦を作成し、その中で閏年の条件を設けました。

グレゴリオ暦では次の規則に従って閏年を設けます。

  • 西暦年が4で割り切れる年は(原則として)閏年
  • ただし、西暦年が100で割り切れる年は(原則として)平年
  • ただし、西暦年が400で割り切れる年は必ず閏年

この条件に沿って考えれば100年後、1000年後の閏年がいつなのか ということも確認できる というわけです。

なぜ閏年とプログラミングなのか

昔々、プログラミングのプの字も理解していなかった私は当時の先生に
「特定の年が閏年かそうでないかを判定するプログラムを作成しなさい」と言われ…

(閏年判定プログラムなんていらなくね…?)とか思ってました。

閏年の判定条件は絶妙な複雑さで、プログラミングの「条件分岐」の練習に良い題材なんだろうなとか思います。

なので、Hello worldの次くらいに誰もが通る道かもしれません。

閏年の条件分岐を考える

さて、ここからプログラミング的に閏年判定について考えていきます。

先ほどの閏年の条件を使ってフローチャートを書いてみます

  1. まずは先述の条件の中から「西暦年が400で割り切れる年は必ず閏年」という条件で、必ず閏年となる年かどうかの判定を行います。
  2. この判定で「NO」になった場合は、次の条件「西暦年が100で割り切れる年は(原則として)平年」という条件で判定を行います。
  3. この判定でさらに「NO」になった場合は、最後の条件「西暦年が4で割り切れる年は(原則として)閏年」という条件を使って判定を行います。

このように条件1つずつに対して「YESかNOか」の判定を行い、与えられた西暦年が閏年かどうかを振り分けて判定を行います。

プログラミングではこのような「〇〇だったらAの結果、××だったらBの結果へ」という条件分岐の処理はよく使いますが、この概念の流れを知るのに閏年の判定は分かりやすい題材です。

if文で書いてみる

フローチャートを書いて、条件での分岐方法が明確になったので
if文を使ってJavascriptで実際にプログラムを書いてみます。

const year = 2024;

if(year % 400 === 0) {
  //西暦年が400で割り切れる
  console.log('閏年')
} else {
  //西暦年が400で割り切れない
  if(year % 100 === 0) {
    //100で割り切れる
    console.log('平年')
  } else {
    //100で割り切れない
    if(year % 4 === 0) {
      //4で割り切れる
      console.log('閏年')
    } else {
      //4で割り切れない
      console.log('平年')
    }
  }
}

すなおに条件を追って書いていくとこのようになります。
この方法で条件分岐はできていますが、プログラムコードが少し読みにくいです…

if文の中にif文を書く(入れ子)の書き方はコードの可読性が下がってしまうため
良くないと言われることが多いです…

また、条件が複雑になればなるほどif文の入れ子が深くなり可読性もどんどんと下がっていきます。

なのでこのコードをもう少しわかりやすい形に直してみます。

const year = 2024;

if(year % 400 === 0) {
  //西暦年が400で割り切れる
  console.log('閏年')
} else if(year % 100 === 0) {
  //西暦年が400で割り切れず、100で割り切れる
  console.log('平年')
} else if(year % 4 === 0) {
   //西暦年が400で割り切れず、100で割り切れず、4で割り切れる
  console.log('閏年')
} else {
   //西暦年が400で割り切れず、100で割り切れず、4で割り切れない
   console.log('平年')
}

else if を使って条件分岐を行い、最後は「どの条件も満たさない場合は平年」という記述に変更しました。
入れ子の記述がなくなり、少しすっきりしました。

さらにコードを読みやすくしていきます。

const year = 2024;

if(year % 400 === 0 || year % 100 !== 0 && year % 4 === 0) {
  //西暦年が400で割り切れる か 西暦年が100で割り切れず かつ 4で割り切れる
  console.log('閏年')
} else {
   //上記の条件以外の場合
   console.log('平年')
}

if の()中の条件の記述が少し複雑になりましたが、全体のコードは短くなり可読性がかなり良くなりました。

このifの条件の中で「○○かつ(AND)△△」「××か(OR)□□」という書き方が登場します。
この書き方を最初に学ぶものも閏年判定だったような気がします。

if文を使ってこれまでの閏年を数えてみる

実際にJavaScriptでグレゴリオ暦が始まってから今年までの442年間で何回閏年があったかを調べてみました。

See the Pen Untitled by hirano (@_y_hirano) on CodePen.

数百年の中から閏年の条件に一致する年を手作業で調べるのは途方もない作業ですが
プログラムで条件を判断させれば一瞬で調べることができました。

このような処理はカレンダー機能のあるアプリ制作等では利用する機会もありそうですね。

最後に…

ウン十年ぶりに閏年の判定について考えてみました。

作成するプログラムにもよりますが、実務で閏年判定を行う機会は殆どありませんでしたが
学生の時に先生に教えられながら作った閏年判定のおかげでif文の使い方を理解できたのも体感として覚えています。

今回たまたま閏年でブログのネタにしてみましたが久々に思い出してみると面白かったです。
次回の閏年は2028年。それまでに新しい閏年ネタを考えてみようと思います。