粕谷(@daiksy)です。あるシステムの試験をしていて、少し奇妙な状況に遭遇しました。特定の日付の値が、Scalaで実装されたバリデーションは通るのに、MySQLのテーブルにinsertする際にエラーになってしまうのです。それは、西暦1000年2月29日、という日付が入力された際に起こる現象でした。問題となった値は、Scala上ではjava.util.Date、MySQL上ではDATEでそれぞれ扱われていました。試しにScalaのREPLを使って以下のコードを実行してみます。parse("10000229")すると結果はこのようになりました。1000どうやら西暦1000年2月29日として、Date型で扱われるようです。MySQLの対象となるカラムに問題となる値を入れようとしたところ、こちらはエラーになりました。以上のことから、java.util.DateとMySQLのDATEとの間には、暦の解釈において差異があるようです。このとき、わたしが認識していた閏年の計算アルゴリズムは下記のような具合でした。西暦が4で割り切れる年は閏年ただし、西暦が100で割り切れる年は平年ただし、西暦が400で割り切れる年は閏年プログラムの教科書などに記載されている閏年の計算も、上記のアルゴリズムが記載されているはずです。このアルゴリズムに当てはめて考えてみると、西暦1000年は、4で割り切れる100で割り切れるしかし、400で割り切れないとなるので、二番目の条件にHITしますから閏年ではなく平年、ということになります。これだけを見ると、java.util.Dateの実装に問題があるような気がします。同様に2100年や1900年で試してみると、こちらは平年として判断されているようです。javaはわざわざ西暦1000年を閏年として扱うのでしょうか。java.util.Dateの実装を見てみたところ、内部的にカレンダーの扱いが1582年を境に変わっていることがわかりました。Date.java#Date.getCalendarSystemGregorianCalendarクラスのjavadocを読むと、詳しい説明が書かれています。ユリウス暦を実装しています。グレゴリオ暦とユリウス暦の唯一の違いはうるう年の規則です。割り切れない世紀の初年をうるう年にしません。わたしが当初認識していた閏年の計算は、グレゴリオ暦に基づくアルゴリズムであって、javaでは西暦1582年以前はこのグレゴリオ暦ではなくユリウス暦で閏年を判定しているようです。ちなみに余談ですが、wikipediaで西暦1000年を見てみると、「西暦(ユリウス暦)による、閏年」とありました。calendar”を使用していると定義されています。これは「先発グレゴリオ暦」といって、1582年以前にもグレゴリオ暦を適用する、という考え方のようです。PostgreSQLも同様の方式を採用しているようです。単位の歴史wikipedia:先発グレゴリオ暦わたしはこれまで、日付の扱いはすべてのコンピュータシステムで同じであるはず、と思い込んでいました。現代の我々が扱っている暦が、実際に適用されていなかった時代の日付の扱いについては、システムによっていろいろな考え方でそれぞれの仕様が決められているようです。結論はこうなりました。java.util.Dateでは閏年として扱われる。(1582年以前の暦はユリウス暦になる)MySQLのDATEでは平年として扱われる。いうメソッドがあり、これに値をセットすることで暦の切替日を変更できるようです。