記事一覧はこちら

Java8のSimpleDateFormatで大文字のYYYYと指定すると、月日までおかしくなる話

ややこしい日付の書式について - dechnostick's blog javaのSimpleDateFormatで「YYYY」指定した時の挙動 - モーグルとカバとパウダーの日記 多分これに関係ある・・・がわからん。

SimpleDateFormatで指定する文字のYについては結構トラップがあって、小文字のyを通常は使うべきで大文字のYは直感的でない動作をする というのは知っていた。 例えば2013/12/31は火曜日で、翌日の2014/01/01は水曜日。 火曜日の段階で何年か?と言えば当然その時は2013年だけど、大文字のYを指定すると水曜日が2014年だから火曜日も2014年です!って返してしまう。 直感的でないけど理屈は分かる。が、月日まで変わるのは理屈不明。以下再現コード

package p20150921_timeformat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class P20150921_timeformat {
    public static void main(String[] args) throws ParseException {
        checkPattern("yyyy-MMM-dd EEE HH:mm:ss Z", Locale.US);
        checkPattern("YYYY-MMM-dd EEE HH:mm:ss Z", Locale.US);
        SimpleDateFormat sf = new SimpleDateFormat(format, Locale.US);
    }
    private static void checkPattern(String pattern, Locale locale) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
        Date now = new Date();
        String str = format.format(now);
        Date date = format.parse(str);
        System.out.println(now.toLocaleString() + " "+(now.toLocaleString().equals(date.toLocaleString())?"==":"!=") +" "+ date.toLocaleString()+" | "+str);
    }
}
----------------------------
2015/09/21 22:20:51 == 2015/09/21 22:20:51 | 2015-Sep-21 Mon 22:20:51 +0900
2015/09/21 22:20:51 != 2014/12/29 22:20:51 | 2015-Sep-21 Mon 22:20:51 +0900

checkPatternメソッドの中でDateオブジェクトを作って、フォーマッタで文字列にしたり、文字列からDateオブジェクトに戻したりする。小文字のyを指定している時は問題なく同じ日時が復元されるのに、大文字のYを指定すると年月日全部壊れてしまう。時分秒は維持されてるから完全にぶっ壊れている訳ではないだろうが、なおさらわからん。 [quote source='SimpleDateFormat (Java Platform SE 8 )' ]暦週の基準年'Y'が指定され、カレンダが暦週の基準年をサポートしていない場合は、代わりにカレンダの年('y')が使用されます。getCalendar().isWeekDateSupported()を呼び出すと、暦週の基準年のサポートをテストできます。[/quote] 特に月日についての記述は無いな・・・ ↓二回目のcheckPatternで!=になってる。とりあえず糞環境乙ではないと思う。