【发布时间】:2018-09-23 12:27:03
【问题描述】:
我正在尝试将一些代码从 joda 时间移植到 java 时间。
JodaTime 可以像这样为年份指定一个备用值
parser.withDefaultYear((new DateTime(DateTimeZone.UTC)).getYear()).parseDateTime(text);
无论解析器看起来如何(如果它包括一年),都会对其进行解析。
java.time 在那里变得更加严格。尽管有 DateTimeFormatterBuilder.parseDefaulting() 方法允许您指定回退,但这仅在您要解析的日期中未指定该特定字段或标记为可选时才有效。
如果您对传入的日期格式没有任何控制权,因为它是用户提供的,这使得调用parseDefaulting 变得非常困难。
是否有任何解决方法,我可以指定诸如通用后备日期之类的东西,如果没有指定它们的值将被格式化程序使用,或者我如何配置根本不使用的后备值,当它们被指定时格式化程序?
以下是最小、完整和可验证的示例。
public static DateTimeFormatter ofPattern(String pattern) {
return new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.YEAR, 1970)
.toFormatter(Locale.ROOT);
}
public void testPatterns() {
// works
assertThat(LocalDate.from(ofPattern("MM/dd").parse("12/06")).toString(), is("1970-12-06"));
assertThat(LocalDate.from(ofPattern("uuuu/MM/dd").parse("2018/12/06")).toString(), is("2018-12-06"));
// fails with exception, as it uses year of era
assertThat(LocalDate.from(ofPattern("yyyy/MM/dd").parse("2018/12/06")).toString(), is("2018-12-06"));
}
期望的结果:测试应该解析字符串并通过(“变绿”)。
观察到的结果:测试的最后一行抛出异常,并带有以下消息和堆栈跟踪。
无法解析文本“2018/12/06”:发现冲突:1970 年 与 2018 年不同
Exception in thread "main" java.time.format.DateTimeParseException: Text '2018/12/06' could not be parsed: Conflict found: Year 1970 differs from Year 2018
at java.base/java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1959)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1820)
at com.ajax.mypackage.MyTest.testPatterns(MyTest.java:33)
Caused by: java.time.DateTimeException: Conflict found: Year 1970 differs from Year 2018
at java.base/java.time.chrono.AbstractChronology.addFieldValue(AbstractChronology.java:676)
at java.base/java.time.chrono.IsoChronology.resolveYearOfEra(IsoChronology.java:620)
at java.base/java.time.chrono.IsoChronology.resolveYearOfEra(IsoChronology.java:126)
at java.base/java.time.chrono.AbstractChronology.resolveDate(AbstractChronology.java:463)
at java.base/java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:585)
at java.base/java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:126)
at java.base/java.time.format.Parsed.resolveDateFields(Parsed.java:360)
at java.base/java.time.format.Parsed.resolveFields(Parsed.java:266)
at java.base/java.time.format.Parsed.resolve(Parsed.java:253)
at java.base/java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1994)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1816)
... 1 more
【问题讨论】:
-
我也对你的问题感到困惑。你想提供默认值吗?如您所示,使用
DateTimeFormatterBuilder。您想要覆盖日期时间值的某些部分吗?通过在DateTimeFormatter实例化的日期时间对象上调用with…方法进行调整。编辑您的问题以阐明默认值与覆盖。也许给出一些输入和期望输出的例子。 -
抱歉不清楚。想象一下,我想解析日期格式
dd/MM,然后我需要将parseDefaulting(ChronoField.YEAR, 1984)添加到我的格式化程序中,知道这种格式没有年份。如果下一个解析(注意我不知道格式化程序,suer 提供)是YYYY/dd/MM,那么添加parseDefaulting(ChronoField.YEAR, 1984)将返回一个异常,因为年份已经设置。所以我需要以某种方式区分这些日期格式,以便能够设置正确的默认值。希望这是有道理的。 -
我已经从您的最后一个示例中复制了
java.time.format.DateTimeParseException: Text '2018/12/06' could not be parsed: Conflict found: Year 1970 differs from Year 2018。格式化程序有字段年份、时代和年份。我相信parseDefaulting将填写一个字段,如果该特定字段尚未被解析,无论它可能是从其他字段推导出来的。我不知道解决方案。 -
我在猜测是否可以使用
DateTimeFormatter.parseUnresolved()或DateTimeFormatter.withResolverFields()找到解决方案。不明显。 -
这里的斜杠只是一个例子,用户也可以使用像
yyyy.MM.dd这样的点或破折号yyyy-MM-dd..我认为这将是一个正则表达式的超级复杂,因为你需要搜索字母(并计算它们),而不是中间的字符,基本上重建了java时间解析逻辑
标签: java datetime time java-time datetime-parsing