LoginSignup
2
2

More than 3 years have passed since last update.

[Java] 2020年12月28日が2021年12月28日ってフォーマットされるんだけど?

Last updated at Posted at 2020-12-29

きっかけ

自分が携わるWEBシステムのある画面で2020年12月28日に作業していると、他メンバーから「"2021年12月28日"と1年先で表示されている画面があるんだけど?」と言われたこと

先に結論を言うと 日付のフォーマット形式で
"yyyy/MM/dd" ではなく、"YYYY/MM/dd"で記述していたことが原因だった。

検証コード

検証コード
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
  public static void main(String[] args) throws Exception {
    final SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");
    final SimpleDateFormat YYYYMMdd = new SimpleDateFormat("YYYY-MM-dd");

    Date date = yyyyMMdd.parse("2020-12-28");

    System.out.println(yyyyMMdd.format(date));
    //=> "2020-12-28"
    System.out.println(YYYYMMdd.format(date));
    //=> "2021-12-28"
  }
}

解説

SimpleDateFormat - JavaDoc
y: 年
Y: 暦週の基準年
yとYの違いはJavaDocを読むと上記のような記述があります。

"暦週の基準年"は簡単にいうと、1月1日と同じ週の日は1月1日の年とするという意味になります。
曜日始まりを日曜日とすると、たとえば下記のような年の扱いです。
image.png

また、暦週の基準年で関連する要素として以下のものがあります。

  • 曜日始まり (日曜日始まり? 月曜日始まり?)
  • 年の最初の週に必要な最小日数
  • ロケール

曜日始まり
Calendar.html#getFirstDayOfWeek
年の最初の週に必要な最小日数
Calendar.html#getMinimalDaysInFirstWeek

firstDayOfWeekとminimalDaysInFirstWeekを明示的に指定しないと、デフォルトロケールに応じたデフォルト値が使用されます。
日本_日本語がデフォルトロケール ("ja_JP")だとすると下記のようになります。

デフォルトロケールとロケールごとの値の違い
import java.util.Calendar;
import java.util.Locale;

public class Main {
  public static void main(String[] args) {
    Locale defaultLocale = Locale.getDefault();
    System.out.println(defaultLocale);
    //=> ja_JP

    // "ja_JP" 日本
    {
      Locale locale = new Locale("ja","JP");
      Calendar calendar = Calendar.getInstance(locale);
      // 1: SUNDAY, 2: MONDAY, 3: TUESDAY, 4: WEDNESDAY, 5: THURSDAY, 6: FRIDAY
      System.out.println(calendar.getFirstDayOfWeek());
      // => 1 (SUNDAY)
      System.out.println(calendar.getMinimalDaysInFirstWeek());
      // => 1 (1日)
    }

    // "en_US" アメリカ
    {
      Locale locale = new Locale("en","US");
      Calendar calendar = Calendar.getInstance(locale);
      System.out.println(calendar.getFirstDayOfWeek());
      // => 1 (SUNDAY)
      System.out.println(calendar.getMinimalDaysInFirstWeek());
      // => 1 (1日)
    }

    // "fr_FR" フランス
    {
      Locale locale = new Locale("fr","FR");
      Calendar calendar = Calendar.getInstance(locale);
      System.out.println(calendar.getFirstDayOfWeek());
      // => 2 (MONDAY)
      System.out.println(calendar.getMinimalDaysInFirstWeek());
      // => 4 (4日 ISO8601基準)
    }
  }
}

下記のように明示的な指定をしない限りは、日曜日始まりで1月1日を含む週を1月1年と同じ年に属するというように扱われるということみたいです。

明示的な指定例
Calendar calendar = Calendar.getInstance();
calendar.setFirstDayOfWeek(Calendar.MONDAY); // 月曜日始まりとする
calendar.setMinimalDaysInFirstWeek(4);       // ISO8601基準とする

あとがき

こういった記事を書くきっかけと与えてくれた同じ開発メンバーに感謝!

参考

一番最初に参考としたサイト
SimpleDateFormatのYYYYとyyyyの違いに要注意 - デブのDEV日記

フランスだけ値がなぜ異なるのか?を調べた時の参考サイト
1週間の始まりは月曜日:フランス語の暦(11)
フランスの曜日(語源など) - 生きたフランス語見聞録

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2