简体   繁体   中英

joda-time ISODateTimeFormat.dateTime() misbehaving

ISODateTimeFormat.dateTime() is supposed to be lenient and flexible. Eg millis are optional, date is optional, timezone is optional, timezone can be Z or +/- HH[:MM]

But it's not. What am I missing?

Using version joda-time:2.9.9 (also tried 2.10.8 with same result)

import org.joda.time.format.ISODateTimeFormat;
import java.util.Arrays;

public static void main(String[] args) {
    Arrays.asList("2020-11-22T01:59:59.001+00:00", "2020-11-22T01:59:59.001Z", "2020-11-22T01:59:59+00:00",
        "2020-11-22T01:59:59Z", "01:59:59").forEach(s -> {
        try {
            System.out.println(String.format("%-30s -- %s", s, ISODateTimeFormat.dateTime().parseDateTime(s)));
        } catch (Exception e) {
            System.out.println(String.format("%-30s -- %s", s, e.getMessage()));
        }
    });
}

Output:

2020-11-22T01:59:59.001+00:00  -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59.001Z       -- 2020-11-22T01:59:59.001Z
2020-11-22T01:59:59+00:00      -- Invalid format: "2020-11-22T01:59:59+00:00" is malformed at "+00:00"
2020-11-22T01:59:59Z           -- Invalid format: "2020-11-22T01:59:59Z" is malformed at "Z"
01:59:59.000                   -- Invalid format: "01:59:59.000" is malformed at ":59:59.000"

javadoc :

public static DateTimeFormatter dateTimeParser()

Returns a generic ISO datetime parser which parses either a date or a time or both.

The returned formatter can only be used for parsing, printing is unsupported.

The parser is strict by default, thus time string 24:00 cannot be parsed.

It accepts formats described by the following syntax:

 datetime          = time | date-opt-time
 time              = 'T' time-element [offset]
 date-opt-time     = date-element ['T' [time-element] [offset]]
 date-element      = std-date-element | ord-date-element | week-date-element
 std-date-element  = yyyy ['-' MM ['-' dd]]
 ord-date-element  = yyyy ['-' DDD]
 week-date-element = xxxx '-W' ww ['-' e]
 time-element      = HH [minute-element] | [fraction]
 minute-element    = ':' mm [second-element] | [fraction]
 second-element    = ':' ss [fraction]
 fraction          = ('.' | ',') digit+
 offset            = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
 

java.time

As Abra suggested in a comment, you may want to follow the official Joda-Time recommendation and move on to java.time, the modern Java date and time API.

The following will not give you the full flexibility of the Joda-Time parser, but it does parse your five example strings. And you may be able to adapt it further to any further needs you may have.

    ZoneOffset defaultOffset = ZoneOffset.UTC; // Configurable
    LocalDate defaultDate = LocalDate.now(ZoneId.systemDefault());
    
    DateTimeFormatter flexibleFormatter = new DateTimeFormatterBuilder()
            .optionalStart()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .optionalEnd()
            .parseDefaulting(ChronoField.YEAR, defaultDate.getYear())
            .parseDefaulting(ChronoField.MONTH_OF_YEAR, defaultDate.getMonthValue())
            .parseDefaulting(ChronoField.DAY_OF_MONTH, defaultDate.getDayOfMonth())
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .optionalStart()
            .appendOffsetId()
            .optionalEnd()
            .parseDefaulting(ChronoField.OFFSET_SECONDS, defaultOffset.getTotalSeconds())
            .toFormatter();

    Arrays.asList("2020-11-22T01:59:59.001+00:00", "2020-11-22T01:59:59.001Z", "2020-11-22T01:59:59+00:00",
            "2020-11-22T01:59:59Z", "01:59:59").forEach(s -> {
            try {
                System.out.println(String.format("%-30s -- %s", s, OffsetDateTime.parse(s, flexibleFormatter)));
            } catch (DateTimeParseException dtpe) {
                System.out.println(String.format("%-30s -- %s", s, dtpe.getMessage()));
            }
        });     

Output when I ran just now in Europe/Copenhagen time zone:

 2020-11-22T01:59:59.001+00:00 -- 2020-11-22T01:59:59.001Z 2020-11-22T01:59:59.001Z -- 2020-11-22T01:59:59.001Z 2020-11-22T01:59:59+00:00 -- 2020-11-22T01:59:59Z 2020-11-22T01:59:59Z -- 2020-11-22T01:59:59Z 01:59:59 -- 2020-11-19T01:59:59Z

From the Joda-Time home page:

Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

What went wrong in your code?

jensgram said it already in the comment:

You're linking to the docs for dateTimeParser but invoking dateTime()

Links

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM