在my other question on how to parse date-only strings as LocalDateTime之后,尝试使用模式yyyyMMdd [HHmmss]解析字符串20120301122133时出现错误。奇怪的是,使用模式yyyyMMdd [HHmmss]解析20120301 122133非常有效。
所以这段代码工作正常
LocalDateTime.parse(
"19940513 230000",
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMdd[ HHmmss]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter()
)
这一次失败
LocalDateTime.parse(
"19940513230000",
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMdd[HHmmss]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter()
)
我应该如何解析格式为yyyyMMdd [HHmmss]的字符串,即格式为yyyyMMddHHmmss,并使用java 8时间API提供可选的时间部分?
解析模式是可配置选项,因此仅在运行时才知道。所以我不能,例如用硬编码的DateTimeFormatterBuilder调用替换String模式。
答案 0 :(得分:1)
问题在于模式表达" yyyy"并不表示固定的四位数年份,而是指示至少4位数(或更多,因此解析器是贪婪的)。但你可以这样做:
LocalDateTime ldt =
LocalDateTime.parse(
"19940513230000",
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4)
.appendPattern("MMdd[HHmmss]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.toFormatter());
System.out.println(ldt); // 1994-05-13T23:00
答案 1 :(得分:1)
System.out.println(LocalDateTime.parse(
"19940513230000",
new DateTimeFormatterBuilder()
.appendPattern("[uuuuMMddHHmmss][uuuuMMdd]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter()
));
打印:
1994-05-13T23:00
如果我尝试使用日期"19940513"
解析一个字符串,我得到
1994-05-13T00:00
它也适用于yyyy
而不是uuuu
。假设您的所有年份都处于这个时代(第1年或更晚),那么您使用哪一年并没有任何区别。通常uuuu
也会接受负面年份,0表示1 BCE,-1表示2 BCE,等等。
答案 2 :(得分:1)
这是因为年份没有固定值,通常限制在19位数。
如果您创建以下格式化程序(不需要分钟和秒)并使用toString()
方法:
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMdd[ HHmmss]")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.toFormatter()
.toString();
您可以看到以下内容:
“值( YearOfEra,4,19,EXCEEDS_PAD )值(MonthOfYear,2)值(DayOfMonth,2)[''Value(HourOfDay,2)Value(MinuteOfHour,2)Value( SecondOfMinute,2)] java.time.format.DateTimeFormatterBuilder$DefaultValueParser@32eff876"
在这里,您可以看到YearOfEra
的最小宽度为4,最大值为19。
您可以使用Meno或Ole的答案之一。
但是,如果您需要接收格式和日期作为参数,并且希望能够以更简单的方式指定日期格式(例如yyyyMMdd[HHmmSS]
而不是[...][...]
),则可以预处理其中一个to值(日期格式)。
您可以创建'dinamically'格式化程序,因此每yyyy
只会被解释为4位数年份。
自定义格式构建器可能类似于(可以改进):
public static DateTimeFormatter createFixed4DigitYearFormatter(String format) {
DateTimeFormatterBuilder formatBuilder = new DateTimeFormatterBuilder();
Arrays.stream(format.split("yyyy", -1))
.flatMap(cur -> Stream.of("yyyy", cur)).skip(1)
.filter(str -> !str.isEmpty())
.forEach(pattern -> {
if ("yyyy".equals(pattern)) formatBuilder
.appendValue(ChronoField.YEAR_OF_ERA, 4);
else formatBuilder.appendPattern(pattern);
});
return formatBuilder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).toFormatter();
}
此格式化程序按字符串"yyyy"
拆分格式,然后将每个非"yyyy"
添加为模式(使用appendPattern(..)
),并将"yyyy"
添加为值类型YEAR_OF_ERA
,固定4位数(appendValue(..)
)。
最后,您可以使用多种格式的格式化程序:
System.out.println(LocalDateTime.parse("19940513230000",
createFixed4DigitYearFormatter("yyyyMMdd[HHmmss]"))); // 1994-05-13T23:00
System.out.println(LocalDateTime.parse("19940513",
createFixed4DigitYearFormatter("yyyyMMdd[HHmmss]"))); // 1994-05-13T00:00
System.out.println(LocalDateTime.parse("1994-05-13 23:00:00",
createFixed4DigitYearFormatter("yyyy-MM-dd[ HH:mm:ss]"))); // 1994-05-13T23:00
System.out.println(LocalDateTime.parse("1994-05-13",
createFixed4DigitYearFormatter("yyyy-MM-dd[ HH:mm:ss]"))); // 1994-05-13T00:00