2020/01/03

日付処理(1) - 日付・カレンダー処理の基礎知識

はじめに

アプリケーションエンジニアにとって、日付・カレンダーに関する業務ロジックを組み立てる機会はとても多いことと思います。最近の言語処理系はカレンダー管理系の標準ライブラリを持っていることが多いと思うので、正しく使いこなせればそれほど難しいことでは無くなってきています。

この記事では、日付・カレンダーに関する業務ロジックの典型的なものを Java, Python のコードスニペットとして紹介したいと思います。Java, Python における標準ライブラリを活用した実用的な例に加えて、日付・カレンダー処理に関する基礎知識とアルゴリズムも解説します。原理を把握したい方、便利なカレンダーライブラリの無い環境でどうしても実現しないといけない方などの参考にもなるかと思います。

日付・カレンダー処理の基礎知識

ちょっと回り道に感じるかもしれませんが、まずは基礎知識から説明しておきます。後述のロジック解説の前提知識になってきますので、初めに説明させてください。

現代の暦法はグレゴリオ暦

現代社会で主に使われているカレンダーは、グレゴリオ暦と呼ばれています。平均的に地球が太陽の周りを1周するのにかかる日数は、およそ365.2422日です。これに極力近づけるため、閏年を使って1年の平均日数を365.2425日にしたのが、グレゴリオ暦です。グレゴリオ暦は1582年10月15日からカトリック世界で使われはじめ、徐々に世界中に浸透していきました。日本では1873年1月1日から使われています。なお、グレゴリオ暦の前はユリウス暦が使われていました。ユリウス暦の1582年10月4日の翌日がグレゴリオ暦の1582年10月15日となっています。歴史上の日付は、1582年10月4日まではユリウス暦、1582年10月5日〜14日は存在せず、1582年10月15日以降はグレゴリオ暦として取り扱われることが通例となっています。

グレゴリオ暦を特徴付ける性質は、閏年のルールです。

  1. 西暦年が4で割り切れる年は閏年
  2. ただし、西暦年が100で割り切れる年は閏年としない
  3. でも、西暦年が400で割り切れる年はやっぱり閏年
となっています。これにより、400年に97回閏年が設定されることになり、平均すると1年当たり97÷400=0.2425日が追加されます。従って1年の平均日数が365.2425日となるわけです。ユリウス暦の閏年ルールは1番だけなので、1年の平均日数は365.25日でした。365.2422日との誤差を考えると、ユリウス暦では0.0078日なのに対し、グレゴリオ暦では0.0003日ですから、26分の1の誤差ということですね。

曜日はユリウス暦とグレゴリオ暦で連続している

ユリウス暦最後の日である1582年10月4日は木曜日で、グレゴリオ暦最初の日である1582年10月15日は金曜日でした。これは、曜日の連続性を保つため、意図的にそう定められました。そのため、ユリウス暦、グレゴリオ暦を通じて、通算日数を7で割った余りから、曜日を算出できます。通算日数として、ユリウス通日と呼ばれる紀元前4713年1月1日の正午を起点とした通算日数や、そこから2400000.5を引いた修正ユリウス日がよく用いられます。日付をユリウス通日や修正ユリウス日に変換することで、曜日計算や日数計算が容易にできます。

紀元1年の前年は紀元前1年

業務プログラミングで紀元前の日付を取り扱う機会はあまり無いと思いますが、紀元1年と紀元前1年の間に紀元0年のような年は存在しません。そのため、紀元前の年代をシステム的に表現する場合、紀元前1年を西暦0年、紀元前2年を西暦マイナス1年、…、紀元前x年を西暦1-x年のように表現するのが計算上都合が良いものとなります。