如何使用DateTimeFormatter统一日期格式

时间:2017-08-18 03:29:36

标签: java datetime java-8 java-time datetime-parsing

我需要将不同的时间格式解析为BASIC_ISO_DATE。现在,有4种类型的日期格式:

  • 2016-10-01(ISO_LOCAL_DATE)
  • 2016T
  • 201610T
  • 2016-02-07T22:03:39.937Z(ISO 8601)

需要解析为20161001并打印出来,默认日期为01,默认月份为Jan。例子:

  • 2016T - > 20160101
  • 201610T - > 20161001

如何使用DateTimeFormatter来实现此目标?

4 个答案:

答案 0 :(得分:3)

为了补充@Flown's answer(完全适用于BTW),您还可以使用可选模式(由[]分隔):

DateTimeFormatter parser = new DateTimeFormatterBuilder()
    // optional ISO8601 date/time and offset
    .appendOptional(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    // optional yyyy-MM-dd or yyyyT or yyyyMMT
    .appendPattern("[yyyy-MM-dd][yyyy'T'][yyyyMM'T']")
    // default day is 1
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
    // default month is January
    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
    // create formatter
    .toFormatter();

这种方式完全相同。您可以选择哪一个更清晰或更容易维护。如果有批次不同的模式,使用[]可能最终会让人更加困惑,IMO。

请注意,我使用的是ISO_OFFSET_DATE_TIME而不是ISO_ZONED_DATE_TIME。唯一的区别是ISO_ZONED_DATE_TIME最后也接受时区名称(如[Europe/London]),而ISO_OFFSET_DATE_TIME则不然。 Check the javadoc了解更多信息。

答案 1 :(得分:2)

您可以构建自己的DateTimeFormatter

DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
  .appendOptional(DateTimeFormatter.ISO_ZONED_DATE_TIME)
  .appendOptional(DateTimeFormatter.ISO_LOCAL_DATE)
  .appendOptional(new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR, 4)
    .optionalStart()
      .appendValue(ChronoField.MONTH_OF_YEAR)
    .optionalEnd()
    .appendLiteral('T')
    .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1L)
    .parseDefaulting(ChronoField.DAY_OF_MONTH, 1L)
    .toFormatter())
  .toFormatter();
String[] strings = {"2016-10-01", "2016T", "201610T", "2016-02-07T22:03:39.937Z"};
for (String s : strings) {
  System.out.println(LocalDate.parse(s, dateTimeFormatter)
        .format(DateTimeFormatter.BASIC_ISO_DATE));
}

答案 2 :(得分:1)

尝试这样的事情:

public LocalDate parse(String str) {
   // Might want to add some checks here...
   String text = (str.replaceAll("[\-T]", "") + "0101").substring(0, 8);
   return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyyMMdd"));
}

答案 3 :(得分:1)

如果您只想要一个DateTimeFormatterFlown’s answer经过深思熟虑,可以很好地添加更多可能的格式或以其他方式更改要求。

我认为一个简单的替代方案是你使用三个或四个DateTimeFormatter个对象并依次尝试它们直到一个工作。

对于2016T,您可以像在Flown的回答中一样使用parseDefaulting(),也可以只解析Year,然后使用.atDay(1)。同样适用于201610T:一个选项是解析为YearMonth并使用其atDay()

我的解决方案可能不太优雅,但可能更清晰。