SimpleDateFormat
で「Y」が2012を返し、「Y」が2011を返すのはなぜかと思います。
System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012
System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011
誰でもその理由を説明できますか?
週年 および年。 javadocから
1週間はWEEK_OF_YEARサイクルと同期しています。最初の週と最後の週(これを含む)の間のすべての週は、同じ週の年の値を持ちます。したがって、週の最初の日と最後の日では、暦年の値が異なる場合があります。
たとえば、1998年1月1日は木曜日です。 getFirstDayOfWeek()がMONDAYでgetMinimalDaysInFirstWeek()が4(ISO 8601標準互換設定)の場合、1998年の第1週は1997年12月29日に始まり、1998年1月4日に終了します。ただし、getFirstDayOfWeek()がSUNDAYの場合、1998年の第1週は1998年1月4日に始まり、1998年1月10日に終了します。 1998年の最初の3日間は1997年の53週の一部であり、その週の年は1997年です。
GregorianCalendarはおそらく廃止されるか、将来のJDKバージョンから削除されるため、いくつかのコードを含むJava 8アップデートです。
新しいコードはWeekFields
クラスで処理され、特に小文字のy
/大文字のY
で weekBasedYear()
フィールドアクセサー。
このWeekFieldsに基づいて週ベースの年の年にアクセスするためのフィールドを返します。これは、週が月曜日などの固定曜日から始まり、各週が正確に1年に属する年の概念を表します。このフィールドは通常、dayOfWeek()およびweekOfWeekBasedYear()で使用されます。
週one(1)は、少なくとも年にgetMinimalDaysInFirstWeek()日があるgetFirstDayOfWeek()で始まる週です。 したがって、週の開始は年の開始前になります。最初の週が年の始まりの後に始まる場合、前の期間は前年の最後の週になります。
このフィールドは、任意のカレンダーシステムで使用できます。
解析の解決フェーズでは、週ベースの年、週の曜日、曜日から日付を作成できます。
厳格モードでは、3つのフィールドすべてが、有効な値の範囲に対して検証されます。年の週フィールドは、結果の週ベースの年が要求された週ベースの年であることを確認するために検証されます。
スマートモードでは、3つのフィールドすべてが、有効な値の範囲に対して検証されます。 week-of-week-based-yearフィールドは、1〜53で検証されます。つまり、結果の日付は、指定された週に基づいた次の週になります。
寛容モードでは、有効な値の範囲に対して年と曜日が検証されます。結果の日付は、次の3段階のアプローチと同等に計算されます。最初に、要求された週ベースの年の最初の週の最初の日に日付を作成します。次に、週単位の週を取り、1を減算し、週の量を日付に加算します。最後に、ローカライズされた週内の正しい曜日に調整します。
このWeekFields
インスタンスの設定はロケールに依存し、それに応じて異なる設定を持つ場合があります。フランスなどの米国とヨーロッパの国では、週の開始日が異なる場合があります。
たとえば、Java 8のDateFormatterBuilder
は、ロケールでパーサーをインスタンス化し、このロケールをY
シンボルに使用します。
public final class DateTimeFormatterBuilder {
...
private void parsePattern(String pattern) {
...
} else if (cur == 'Y') {
// Fields defined by Locale
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
} else {
...
static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
...
/**
* Gets the printerParser to use based on the field and the locale.
*
* @param locale the locale to use, not null
* @return the formatter, not null
* @throws IllegalArgumentException if the formatter cannot be found
*/
private DateTimePrinterParser printerParser(Locale locale) {
WeekFields weekDef = WeekFields.of(locale);
TemporalField field = null;
switch (chr) {
case 'Y':
field = weekDef.weekBasedYear();
if (count == 2) {
return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0);
} else {
return new NumberPrinterParser(field, count, 19,
(count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
}
case 'e':
case 'c':
field = weekDef.dayOfWeek();
break;
case 'w':
field = weekDef.weekOfWeekBasedYear();
break;
case 'W':
field = weekDef.weekOfMonth();
break;
default:
throw new IllegalStateException("unreachable");
}
return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
}
...
}
...
}
ここにいくつかの例があります
System.out.format("Conundrum : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'")));
System.out.format("Solution : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmms'S'")));
System.out.format("JVM Locale first day of week : %s%n",
WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
System.out.format("US first day of week : %s%n",
WeekFields.of(Locale.US).getFirstDayOfWeek());
System.out.format("France first day of week : %s%n",
WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
System.out.format("JVM Locale min days in 1st week : %s%n",
WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek());
System.out.format("US min days in 1st week : %s%n",
WeekFields.of(Locale.US).getMinimalDaysInFirstWeek());
System.out.format("JVM Locale min days in 1st week : %s%n",
WeekFields.of(Locale.FRANCE).getMinimalDaysInFirstWeek());
System.out.format("JVM Locale week based year (big Y): %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("France week based year (big Y) : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear()));
System.out.format("US week based year (big Y) : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.US).weekBasedYear()));
ロケールと大文字のY
に関しては、コマンドラインオプション-Duser.language=
(fr
、en
、es
など)、または呼び出し時にロケールを強制する:
System.out.format("English localized : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.ENGLISH)));
System.out.format("French localized : %s%n",
ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC"))
.format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.FRENCH)));
カレンダーが平年をサポートしている場合、Y
をフォーマットして平年を取得します。 (getCalendar().isWeekDateSupported()
)
JSTLタグライブラリの難しい方法を学びましたformat:date
でshort
が要求された形式としてYYYYを使用しています。実際、印刷された日付を1年先に進めることができます。