parsing DateTime with ThreetenBp causes DateTimeParseException or incomplete string error

634 views Asked by At

I am trying to check if the date has passed more than one day or not.

And I got these errosr while it parses the string.

java.lang.IllegalArgumentException: Pattern ends with an incomplete string literal: uuuu-MM-dd'T'HH:mm:ss'Z
org.threeten.bp.format.DateTimeParseException: Text '2020-04-04T07:05:57+00:00' could not be parsed, unparsed text found at index 19

My data example is here:

val lastDate = "2020-04-04T07:05:57+00:00"
val serverFormat = "uuuu-MM-dd'T'HH:mm:ss'Z"
val serverFormatter =
        DateTimeFormatter
            .ofPattern(serverFormat)
val serverDateTime =
        LocalDateTime
            .parse(
                lastDate,
                serverFormatter
            )
            .atZone(ZoneId.of("GMT"))
val clientDateTime =
        serverDateTime
            .withZoneSameInstant(ZoneId.systemDefault())

val timeDiff =
        ChronoUnit.DAYS.between(
            serverDateTime,
            clientDateTime

I've tried with these:

uuuu-MM-dd\'T\'HH:mm:ss\'Z
yyyy-MM-dd\'T\'HH:mm:ss\'Z
uuuu-MM-dd\'T\'HH:mm:ss
uuuu-MM-dd'T'HH:mm:ss'Z
yyyy-MM-dd'T'HH:mm:ss'Z
uuuu-MM-dd'T'hh:mm:ss'Z
yyyy-MM-dd'T'hh:mm:ss'Z
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd HH:mm:ssZ
yyyy-MM-dd'T'HH:mm:ss
yyyy-MM-dd'T'HH:mm:ssZ
yyyy-MM-dd'T'HH:mm:ss

And none of them worked... What is the correct way?

1

There are 1 answers

0
Anonymous On BEST ANSWER

You don’t need any explicit formatter. In Java (because it’s what I can write):

    String lastDate = "2020-04-04T07:05:57+00:00";
    OffsetDateTime serverDateTime = OffsetDateTime.parse(lastDate);
    ZonedDateTime clientDateTime
            = serverDateTime.atZoneSameInstant(ZoneId.systemDefault());

    System.out.println("serverDateTime: " + serverDateTime);
    System.out.println("clientDateTime: " + clientDateTime);

Output in my time zone:

serverDateTime: 2020-04-04T07:05:57Z
clientDateTime: 2020-04-04T09:05:57+02:00[Europe/Copenhagen]

The format of the string from your server is ISO 8601. The classes of java.time parse the most common ISO 8601 variants as their default, that is, without any formatter being specified.

Since the string from your server has a UTC offset, +00:00, and no time zone, like Asia/Seoul, OffsetDateTime is the best and most correct time to use for it. On the other hand, the client time has got time zone, so ZonedDateTime is fine here.

Since server and client time denote the same time, the difference will always be zero:

    Duration difference = Duration.between(serverDateTime, clientDateTime);
    System.out.println(difference);
PT0S

Read as a period of time of 0 seconds (this too is ISO 8601 format).

If you want to know the difference between the current time and the server time, use now():

    Duration difference = Duration.between(serverDateTime, OffsetDateTime.now());
    System.out.println(difference);

What went wrong in your code?

First, the UTC offset in your string is +00:00. Neither one format pattern letter Z nor a literal Z will match this. So don’t try that. Second, never give Z as a literal enclosed in single quotes in your format pattern string. When a Z appears as an offset, which is common, you need to parse it as an offset, not as a literal. Third, literal text in a format pattern string needs to have a single quote before and a single quote after it. You are doing it correctly for the T in the middle. If you didn’t mean Z to be a literal, don’t put a single quote before it. If you did mean it to be a literal — as I said, just don’t.

Links