Christian Sisti
Christian Sisti

Reputation: 199

What I am doing wrong when parsing an ISO8601 date time?

I am expecting the test below to pass. Could someone tell me what I am doing wrong here? Most likely I am using a wrong pattern but I can't see what is wrong.

@Test
public void parseDateTest() {
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
    DateTime dt = formatter.parseDateTime("1983-03-06T05:00:03.000Z");
    assertEquals("1983-03-06T05:00:03.000Z", dt.toString());
}

FYI dt.toString() does print: 1983-03-06T05:00:00.000Z

Thanks!

P.S. Please note that on this snippet I rely on the default timezone. This is not production code and how to handle correctly the timezone based on needs is covered by many other questions.

The default time zone is derived from the system property user.timezone. If that is null or is not a valid identifier, then the value of the JDK TimeZone default is converted. If that fails, UTC is used.

Upvotes: 0

Views: 351

Answers (3)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79095

java.time

Quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

Solution using java.time API: java.time API is based on ISO 8601 and therefore you do not need a DateTimeFormatter to parse a date-time string which is already in ISO 8601 format (e.g. your date-time string, 1983-03-06T05:00:03.000Z).

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;

class Main {
    public static void main(String[] args) {
        String strModifiedDate = "1983-03-06T05:00:03.000Z";
        Instant instant = Instant.parse(strModifiedDate);
        System.out.println(instant);

        // It can also be directly parsed into a ZonedDateTime
        ZonedDateTime zdt = ZonedDateTime.parse(strModifiedDate);
        System.out.println(zdt);

        // or even into an OffsetDateTime
        OffsetDateTime odt = OffsetDateTime.parse(strModifiedDate);
        System.out.println(odt);
    }
}

Output:

1983-03-06T05:00:03Z
1983-03-06T05:00:03Z
1983-03-06T05:00:03Z

Learn more about the modern Date-Time API from Trail: Date Time.

Upvotes: 2

wallenborn
wallenborn

Reputation: 4273

Don't use dt.toString(), use formatter.format(dt) instead. That's what the formatter is for:

@Test
public void parseDateTest() {
  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
  LocalDateTime dt = formatter.parse("1983-03-06T05:00:03.000Z", LocalDateTime::from);
  assertEquals("1983-03-06T05:00:03.000Z", formatter.format(dt));
}

Upvotes: 0

Sam
Sam

Reputation: 20486

This checks to see if "1983-03-06T05:00:03.000Z" is equal to dt.toString(). You say that dt.toString() is equal to "1983-03-06T05:00:00.000Z".

"1983-03-06T05:00:03.000Z" !== "1983-03-06T05:00:00.000Z"

Now the problem is why dt.toString() does not have the correct amount of seconds. Let's look at your DateTimeFormat pattern:

"yyyy-MM-dd'T'HH:mm:ss.sss'Z'"

According to the docs, s is for "second of minute" and S is for "fraction of second" (note the case). This means in your input string, both 03 and 000 are being parsed as seconds (when the later should be fractions) and your DateTime's seconds are being overridden with 00. Try updating this format string:

@Test
public void parseDateTest() {
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    DateTime dt = formatter.parseDateTime("1983-03-06T05:00:03.000Z");
    assertEquals("1983-03-06T05:00:03.000Z", dt.toString());
}

Upvotes: 4

Related Questions