Lenient Java 8日期解析

我想用LocalDateTime解析’2015-10-01’。 我要做的是

 LocalDate localDate = LocalDate.parse('2015-10-01'); LocalDateTime localDateTime = localDateTime.of(localDate, LocalTime.MIN); 

但是我想像一遍一样解析它

 // throws DateTimeParseException LocalDateTime date = LocalDateTime.parse('2015-10-01', DateTimeFormatter.ISO_LOCAL_DATE); 

字符串的一小部分差异也会引发exception。

 // throws DateTimeParseException LocalDate localDate = LocalDate.parse("2015-9-5", DateTimeFormatter.ISO_LOCAL_DATE); 

我可以使用Java 8 Date API轻松解析日期字符串吗?

如果要将日期字符串解析为"2015-10-01""2015-9-5"LocalDateTime对象,可以使用DateTimeFormatterBuilder构建自己的DateTimeFormatterBuilder

 DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("yyyy") .appendLiteral('-') .appendValue(MONTH_OF_YEAR) .appendLiteral('-') .appendValue(DAY_OF_MONTH) .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum()) .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum()) .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum()) .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum()) .toFormatter(); System.out.println(LocalDateTime.parse("2015-9-5", formatter)); System.out.println(LocalDateTime.parse("2015-10-01", formatter)); 

每个字段的可变长度由对appendValue(field)的调用处理。 引用Javadoc:

像这样的可变宽度值的解析器通常表现得很贪婪,需要一个数字,但接受尽可能多的数字。

这意味着它将能够解析用1或2位数格式化的月份和日期。

要构造LocalDateTime ,我们还需要为此构建器提供LocalTime 。 这是通过对parseDefaulting(field, value)的每个字段使用parseDefaulting(field, value)来完成的。 如果要解析的String中不存在该字段,则此方法将获取该字段的字段和默认值。 因为在我们的例子中,时间信息不会出现在字符串中,所以将选择默认值,即该字段的有效值范围的最小值(通过将getMinimum调用该字段的ValueRange获得) ;也许我们也可以硬编码0)。


如果要解析的String可能包含时间信息,我们可以使用DateTimeFormatter可选部分,如下所示:

 DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("yyyy") .appendLiteral('-') .appendValue(MONTH_OF_YEAR) .appendLiteral('-') .appendValue(DAY_OF_MONTH) .appendPattern("[ HH:mm]") // optional sections are surrounded by [] .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum()) .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum()) .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum()) .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum()) .toFormatter(); System.out.println(LocalDateTime.parse("2015-9-5", formatter)); System.out.println(LocalDateTime.parse("2015-10-01", formatter)); System.out.println(LocalDateTime.parse("2015-1-1 10:10", formatter)); 

解析日期和时间

要从字符串创建LocalDateTime对象,可以使用静态LocalDateTime.parse()方法。 它需要一个字符串和一个DateTimeFormatter作为参数。 DateTimeFormatter用于指定日期/时间模式。

 String str = "1986-04-08 12:00"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); LocalDateTime dateTime = LocalDateTime.parse(str, formatter); 

格式化日期和时间

要从LocalDateTime对象创建格式化字符串,可以使用format()方法。

 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30); String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30" 

请注意,在DateTimeFormatter中有一些常用的日期/时间格式预定义为常量。 例如:使用DateTimeFormatter.ISO_DATE_TIME从上面格式化LocalDateTime实例将导致字符串“1986-04-08T12:30:00”。

所有与日期/时间相关的对象(例如LocalDate或ZonedDateTime)都可以使用parse ()和format ()方法

你可以试试

  private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").withResolverStyle(ResolverStyle.LENIENT); 

针对您的特定用例的简单解决方案是定义您自己的格式。 在这个例子中,即使我在我的模式中为月份指定了单个M ,并且在当天指定了单个d ,它仍然会解析两个示例相同。

 @Test public void parsing_singleDigitDates_andDoubleDigitDates_areEqual() { DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-Md"); LocalDate dt1 = LocalDate.parse("2015-09-05", fmt); LocalDate dt2 = LocalDate.parse("2015-9-5", fmt); Assert.assertEquals(dt1, dt2); } 

在看到DateTimeFormatterBuilder要求你编写代码汤以解决同样的问题后,我决定写这个答案。