2017-08-18 145 views
2

我需要解析不同的时间格式到BASIC_ISO_DATE。眼下,有4种类型的日期格式:如何使用DateTimeFormatter统一日期格式

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

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

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

如何使用DateTimeFormatter实现这一目标?

+1

在所有情况下你只需要日期(LocalDate)吗?或者当你需要一天的时间(最后一个例子)? –

+0

我不明白'20161001'的月份可能是一月份吗?一个错字? –

+1

@ OleV.V。我认为这不是一个错字。如果有一个月(在这种情况下,'10'),则只有一天默认为'1'。如果没有月份,则默认为1月份。 –

回答

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(); 

这工作方式完全相同。您可以选择哪一个更清晰或更容易维护。如果有不同的模式,使用[]可能最终会更混乱,国际海事组织。

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

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")); 
} 
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)); 
} 
1

如果你只想要一个DateTimeFormatterFlown’s answer是经过深思熟虑的,并且其本身相当不错,以增加更多可能的格式或改变在其他方面的要求。

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

对于2016T,可以选择使用parseDefaulting()作为空运过来的答案,或者只是解析为Year,然后使用例如.atDay(1)201610T同样如此:一种选择是解析为YearMonth并使用其atDay()

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