私は新しい日時APIで遊んでいましたが、これを実行するとき:
public class Test {
public static void main(String[] args){
String dateFormatted = LocalDate.now()
.format(DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(dateFormatted);
}
}
投げる:
Exception in thread "main" Java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
at Java.time.LocalDate.get0(LocalDate.Java:680)
at Java.time.LocalDate.getLong(LocalDate.Java:659)
at Java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.Java:298)
at Java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.Java:2543)
at Java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.Java:2182)
at Java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.Java:1745)
at Java.time.format.DateTimeFormatter.format(DateTimeFormatter.Java:1719)
at Java.time.LocalDate.format(LocalDate.Java:1685)
at Test.main(Test.Java:23)
LocalDateクラスのソースコードを見ると、次のように見えます。
private int get0(TemporalField field) {
switch ((ChronoField) field) {
case DAY_OF_WEEK: return getDayOfWeek().getValue();
case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
case DAY_OF_MONTH: return day;
case DAY_OF_YEAR: return getDayOfYear();
case Epoch_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
case MONTH_OF_YEAR: return month;
case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
case YEAR: return year;
case ERA: return (year >= 1 ? 1 : 0);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
ドキュメントで説明されているように:
このメソッドは、クラスのドキュメントで説明されているように、文字と記号の単純なパターンに基づいてフォーマッターを作成します。
そして、これらの文字はすべて 定義済み です。
では、なぜDateTimeFormatter.ofPattern
でパターン文字を使用できないのですか?
LocalDate
は、DateTimeではなく、単なる日付を表します。したがって、LocalDate
をフォーマットする場合、「HH:mm:ss」は意味がありません。代わりにLocalDateTime
を使用します(日付と時刻の両方を表現したい場合)。
@James_Dの正解に次の詳細を追加したいと思います。
背景:ほとんどの日時ライブラリ(JavaのJava.util.Calendar
、. Net-DateTimeまたはDate
も参照) JavaScript(PerlのDateTime
)は、万能で汎用的な時間型(ドイツ語では「eierlegende Wollmilchsau」という詩的表現)の概念に基づいています。この設計では、サポートされていないフィールドは存在できません。しかし、価格は高いです。多くの時間の問題は、このような柔軟性のないアプローチでは適切に処理できません。これは、すべての種類の時間オブジェクトの共通分母を見つけることが不可能なためです。
JSR-310は別の方法を選択しました。つまり、サポートされている組み込みフィールドのタイプ固有のセットで構成されるさまざまな時間タイプを許可します。自然な結果は、すべての可能なフィールドがすべてのタイプでサポートされるわけではないということです(そして、ユーザーは独自の専門フィールドを定義することさえできます)。また、サポートされているフィールドの特定のセットに対して、タイプTemporalAccessor
のすべてのオブジェクトを プログラムで要求 することもできます。 LocalDate
の場合:
•DAY_OF_WEEK
•ALIGNED_DAY_OF_WEEK_IN_MONTH
•ALIGNED_DAY_OF_WEEK_IN_YEAR
•DAY_OF_MONTH
•DAY_OF_YEAR
•Epoch_DAY
•ALIGNED_WEEK_OF_MONTH
•ALIGNED_WEEK_OF_YEAR
•MONTH_OF_YEAR
•PROLEPTIC_MONTH
•YEAR_OF_ERA
•YEAR
•ERA
UnsupportedTemporalTypeException
の問題を説明するHOUR_OF_DAYフィールドはありません。 JSR-310 - パターンシンボルのフィールドへのマッピング を見ると、シンボルHがサポートされていないHOUR_OF_DAYにマッピングされていることがわかります。
/** Map of letters to fields. */
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
static {
FIELD_MAP.put('G', ChronoField.ERA);
FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);
FIELD_MAP.put('u', ChronoField.YEAR);
FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);
FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);
FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);
FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);
FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);
FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);
FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);
FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);
FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);
FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);
FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);
FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);
FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);
FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);
FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);
FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);
FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);
FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);
FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);
}
このフィールドマッピングは、フィールドが具象型によってサポートされることを意味するものではありません。解析はいくつかのステップで行われます。フィールドマッピングは最初のステップにすぎません。次に、2番目のステップはTemporalAccessor
型の生オブジェクトに解析します。最後に、デリゲートをターゲットタイプ(ここではLocalDate
)に解析し、解析された中間オブジェクトのすべてのフィールド値を受け入れるかどうかを決定させます。
私にとって適切なクラスは ZonedDateTime
で、これには時間とタイムゾーンの両方が含まれます。
LocalDate
には時間情報がないため、UnsupportedTemporalTypeException: Unsupported field: HourOfDay
を取得します。
LocalDateTime
を使用できますが、タイムゾーン情報がないため、それにアクセスしようとすると(定義済みのフォーマッターのいずれかを使用しても)UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
を取得します。