Java 使用新的日期时间 API 格式化日期
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23069370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Format a date using the new date time API
提问by user2336315
I was playing with the new date time API but when running this:
我正在使用新的日期时间 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);
}
}
It throws:
它抛出:
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)
When looking at the source code of the LocalDate class, I see:
查看 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);
}
As it described in the doc:
正如它在文档中描述的那样:
This method will create a formatter based on a simple pattern of letters and symbols as described in the class documentation.
此方法将根据类文档中所述的简单字母和符号模式创建格式化程序。
And all these letters are defined.
所有这些字母都已定义。
So why DateTimeFormatter.ofPattern
doesn't allow us to use some pattern letters?
那么为什么DateTimeFormatter.ofPattern
不允许我们使用一些模式字母呢?
采纳答案by James_D
LocalDate
represents just a date, not a DateTime. So "HH:mm:ss" make no sense when formatting a LocalDate
. Use a LocalDateTime
instead, assuming you want to represent both a date and time.
LocalDate
仅代表一个日期,而不是 DateTime。所以“HH:mm:ss”在格式化LocalDate
. 使用 aLocalDateTime
代替,假设您要同时表示日期和时间。
回答by Meno Hochschild
I would like to add following details to the correct answer of @James_D:
我想在@James_D 的正确答案中添加以下详细信息:
Background:Most date-and-time-libraries (java.util.Calendar
in Java, see also .Net-DateTime or Date
in JavaScript or DateTime
in Perl) are based on the concept of a universal all-purpose unique temporal type (in German there is the poetic expression "eierlegende Wollmilchsau"). In this design there cannot be an unsupported field. But the price is high: Many time problems cannot be adequately handled with such an unflexible approach because it is hard to impossible to find a common denominator for all kinds of temporal objects.
背景:大多数日期和时间库(java.util.Calendar
在 Java 中,另见 .Net-DateTime 或Date
在 JavaScript 或DateTime
Perl 中)基于通用通用唯一时间类型的概念(在德语中有诗意的表达“ eierlegende Wollmilchsau”)。在此设计中,不能有不受支持的字段。但代价是高昂的:许多时间问题无法通过这种不灵活的方法得到充分处理,因为很难甚至不可能为所有类型的时间对象找到一个共同点。
JSR-310 has choosen another way, namely to allow different temporal types which consist of type-specific sets of supported built-in fields. The natural consequence is that not every possible field is supported by every type (and users can even define their own specialized fields). It is also possible to programmatically askevery object of type TemporalAccessor
for its specific set of supported fields. For LocalDate
we find:
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
There is no HOUR_OF_DAY-field which explains the problem of UnsupportedTemporalTypeException
. And if we look at the JSR-310-mapping of pattern symbols to fieldswe see that the symbol H is mapped to unsupported HOUR_OF_DAY:
没有 HOUR_OF_DAY 字段可以解释UnsupportedTemporalTypeException
. 如果我们查看 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);
}
This field mapping does not mean that the field is supported by the concrete type. Parsing happens in several steps. The field mapping is only the first step. The second step is then parsing to a raw object of type TemporalAccessor
. And finally parsing delegates to the target type (here: LocalDate
) and let it decide if it accepts all the field values in parsed intermediate object.
此字段映射并不意味着该字段受具体类型支持。解析分几个步骤进行。字段映射只是第一步。第二步是解析为类型的原始对象TemporalAccessor
。最后将委托解析为目标类型(此处:)LocalDate
并让它决定是否接受解析的中间对象中的所有字段值。
回答by isapir
The right class for me was ZonedDateTime
which includes both Time and Time Zone.
对我来说正确的课程ZonedDateTime
包括时间和时区。
LocalDate
doesn't have the Time information so you get a UnsupportedTemporalTypeException: Unsupported field: HourOfDay
.
LocalDate
没有时间信息,所以你得到一个UnsupportedTemporalTypeException: Unsupported field: HourOfDay
.
You can use LocalDateTime
but then you don't have the Time Zone information so if you try to access that (even by using one of the predefined formatters) you will get a UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
.
您可以使用LocalDateTime
但随后您没有时区信息,因此如果您尝试访问该信息(即使使用预定义的格式化程序之一),您将获得UnsupportedTemporalTypeException: Unsupported field: OffsetSeconds
.