How to unify date format using DateTimeFormatter

前端 未结 4 967
盖世英雄少女心
盖世英雄少女心 2020-12-20 02:20

I need to parse different time format into BASIC_ISO_DATE. Right now, there are 4 types of date format:

  • 2016-10-01 (ISO_LOCAL_DATE)<
相关标签:
4条回答
  • 2020-12-20 02:47

    Try something like this:

    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"));
    }
    
    0 讨论(0)
  • If you want just one DateTimeFormatter, Flown’s answer is well thought out and lends itself pretty well to adding more possible formats or changing the requirements in other ways.

    I think a simple alternative is that you use three or four DateTimeFormatter objects and try them in turn until one works.

    For 2016T, you may either use parseDefaulting() as in Flown’s answer or just parse into a Year and then use for example .atDay(1). Similarly for 201610T: one option is to parse into a YearMonth and use its atDay().

    My solution may be less elegant, but possibly clearer to read.

    0 讨论(0)
  • 2020-12-20 03:00

    Just to complement @Flown's answer (which works perfectly BTW), you can also use optional patterns (delimited by []):

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

    This works exactly the same way. You can choose which one is clearer or easier to maintain. If there are lots of different patterns, using [] might end up being more confusing, IMO.

    Note that I used ISO_OFFSET_DATE_TIME instead of ISO_ZONED_DATE_TIME. The only difference is that ISO_ZONED_DATE_TIME also accepts a timezone name in the end (like [Europe/London]), while ISO_OFFSET_DATE_TIME doesn't. Check the javadoc for more info.

    0 讨论(0)
  • 2020-12-20 03:00

    You could build your own 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));
    }
    
    0 讨论(0)
提交回复
热议问题