【问题标题】:How to unify date format using DateTimeFormatter如何使用 DateTimeFormatter 统一日期格式
【发布时间】:2018-01-26 15:12:19
【问题描述】:

我需要将不同的时间格式解析为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 来实现这一点?

【问题讨论】:

  • 在所有情况下都只需要日期(LocalDate)吗?或者你也需要一天中的时间(最后一个例子)?
  • 我不明白20161001 中的一月是几月?错字?
  • @OleV.V.我认为这不是笔误。如果有一个月(在本例中为10),则只有日期默认为1。如果没有月份,则默认为一月。

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


【解决方案1】:

只是为了补充@Flown's answer(顺便说一句,效果很好),您还可以使用可选模式(由[]分隔):

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 了解更多信息。

【讨论】:

    【解决方案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));
    }
    

    【讨论】:

      【解决方案3】:

      如果您只需要一个DateTimeFormatterFlown’s answer 是经过深思熟虑的,非常适合添加更多可能的格式或以其他方式更改要求。

      我认为一个简单的替代方法是使用三个或四个 DateTimeFormatter 对象并依次尝试它们,直到一个有效。

      对于2016T,您可以使用 parseDefaulting(),就像在 Flown 的答案中一样,或者只是解析为 Year,然后使用例如 .atDay(1)。对于201610T 也是如此:一种选择是解析为YearMonth 并使用它的atDay()

      我的解决方案可能不那么优雅,但阅读起来可能更清晰。

      【讨论】:

        【解决方案4】:

        试试这样的:

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

        【讨论】:

          猜你喜欢
          • 2018-08-19
          • 2021-01-20
          • 2018-03-18
          • 2021-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-01
          相关资源
          最近更新 更多