2,3日前にこういうのを書いたんだけど
irofさんと喋ってたら「yyyyじゃなくてuuuu使わなきゃとかもありますよねー」って言われて「え?そうなんだっけ・・・あれー?全然知らない!・・・ような、頭の隅にあるような・・・」ってなって、調べといた。
どういうこと?
https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html
yyyyは暦に対する年(year-of-era)、uuuuは暦とは無関係な年(year)。なんだって。
year-of-eraって何?
day-of-monthが、月始まりからの日にちだから、暦始まりの年ってことなんだろうな。ふむー。イマイチぴんとこない。から、やってみよう。
普通に書くとこうか。
@Test public void 普通にyyyyとuuuuを使ったら同じ結果になる() { LocalDate target = LocalDate.of(2017, 10, 22); assertThat(target.format(DateTimeFormatter.ofPattern("yyyy/MM/dd", Locale.US))) .isEqualTo("2017/10/22"); assertThat(target.format(DateTimeFormatter.ofPattern("uuuu/MM/dd", Locale.US))) .isEqualTo("2017/10/22"); }
暦はGか。つけてみよう。
@Test public void Gをつけてみたらどうなる() { LocalDate target = LocalDate.of(2017, 10, 22); assertThat(target.format(DateTimeFormatter.ofPattern("G yyyy/MM/dd", Locale.US))) .isEqualTo("AD 2017/10/22"); assertThat(target.format(DateTimeFormatter.ofPattern("G uuuu/MM/dd", Locale.US))) .isEqualTo("AD 2017/10/22"); }
ADよね。・・・そうか、BCやってみるか。
@Test public void 紀元前を渡したらどうなる() { LocalDate target = LocalDate.of(-2017, 10, 22); assertThat(target.format(DateTimeFormatter.ofPattern("G yyyy/MM/dd", Locale.US))) .isEqualTo("BC 2018/10/22"); assertThat(target.format(DateTimeFormatter.ofPattern("G uuuu/MM/dd", Locale.US))) .isEqualTo("BC -2017/10/22"); }
なるほどなぁ。uuuuの方はGに関係ないってことか。すっきりした。だから、こう使うのが正しそうね。
@Test public void こういう風に使うってことか() { LocalDate target = LocalDate.of(2017, 10, 22); assertThat(target.format(DateTimeFormatter.ofPattern("G yyyy/MM/dd", Locale.US))) .as("yyyy使うなら暦と一緒に") .isEqualTo("AD 2017/10/22"); assertThat(target.format(DateTimeFormatter.ofPattern("uuuu/MM/dd", Locale.US))) .as("uuuu使うなら暦は使わない") .isEqualTo("2017/10/22"); }
んで、和暦はこうなるってことか
@Test public void 和暦はこうなるってことか() { JapaneseDate japaneseDate = JapaneseDate.of(2017, 10, 22); assertThat(japaneseDate.format(DateTimeFormatter.ofPattern("G yyyy/MM/dd", Locale.JAPAN))) .isEqualTo("平成 0029/10/22"); assertThat(japaneseDate.format(DateTimeFormatter.ofPattern("uuuu/MM/dd", Locale.JAPAN))) .isEqualTo("2017/10/22"); }
パースはこんな感じだね
@Test public void STRICTモードで暦指定なしyyyyは例外発生() { assertThatExceptionOfType(DateTimeParseException.class) .isThrownBy(() -> LocalDate.parse("2017/10/22", DateTimeFormatter.ofPattern("yyyy/MM/dd") .withResolverStyle(ResolverStyle.STRICT))); } @Test public void yyyyを使うなら暦を指定する() { assertThat(LocalDate.parse("AD 2017/10/22", DateTimeFormatter.ofPattern("G yyyy/MM/dd").withResolverStyle(ResolverStyle.STRICT))) .isEqualTo(LocalDate.of(2017, 10, 22)); } @Test public void でも西暦を扱うときには暦を指定したりしないだろうからuuuuを使うべきってことね() { assertThat(LocalDate.parse("2017/10/22", DateTimeFormatter.ofPattern("uuuu/MM/dd").withResolverStyle(ResolverStyle.STRICT))) .isEqualTo(LocalDate.of(2017, 10, 22)); }