Search code examples
javadatejodatimeiso8601

Java convert ISO 8601 string to Date ignoring offset


I have a string coming to me in the following format "yyyy-MM-dd'T'HH:mm:ssZ" ex: 2020-09-09T09:58:00+0000" offset is UTC.

I need the string to be converted to a Date object without the offset "+0000" being applied, but I keep getting a different time when running my code:

DateTimeFormatter isoFormat = ISODateTimeFormat.dateTimeParser();
Date date = isoFormat.parseDateTime("2020-09-09T09:58:00+0000").toDate();
// Wed Sep 09 05:58:00 EDT 2020

As you can see above the date has changed.

Instead, I would like to keep the same date and time like: Wed Sep 09 09:58:00, so I can convert this Date object to a String with "yyyy-MM-dd", "HH:mm:ss", and "yyyy-MM-dd'T'HH:mm:ss" format respectively.


Solution

  • The first and most important part of the answer is: don’t convert to an old-fashioned Date. Either stick to Joda-Time or migrate to java.time, the modern Java date and time API, as already covered in the good answer by Arvind Kumar Avinash.

    Since you are already using Joda-Time, I am showing you a Joda-Time solution. The trick for persuading the formatter into keeping the time and offset from the string parsed is withOffsetParsed().

        DateTimeFormatter isoFormat
                = ISODateTimeFormat.dateTimeParser().withOffsetParsed();
        String incomingString = "2020-09-09T09:58:00+0000";
        DateTime dateTime = isoFormat.parseDateTime(incomingString);
    

    However! If I have guessed correctly that you want to store date and time in UTC (a recommended practice), better than withOffsetParsed() is to specify UTC on the parser:

        DateTimeFormatter isoFormat
                = ISODateTimeFormat.dateTimeParser().withZoneUTC();
    

    Now you will also get the correct time if one day a string with a non-zero UTC offset comes in.

    In any case we may now format your obtained DateTime into the strings you requested.

        String dateString = dateTime.toString(ISODateTimeFormat.date());
        System.out.println(dateString);
        
        String timeString = dateTime.toString(ISODateTimeFormat.hourMinuteSecond());
        System.out.println(timeString);
        
        String dateTimeString = dateTime.toString(ISODateTimeFormat.dateHourMinuteSecond());
        System.out.println(dateTimeString);
    

    Output:

    2020-09-09
    09:58:00
    2020-09-09T09:58:00
    

    What was wrong with using Date? First, the Date class is poorly designed and long outdated. Second, a Date was just a point in time, it didn’t have a concept of date and time of day (they tried building that into it in Java 1.0, but gave up and deprecated it in Java 1.1 in 1997). So a Date cannot hold the date and time of day in UTC for you.

    What happened in your code was that you got a Date representing the correct point in time. Only when you printed that Date you were implicitly invoking its toString method. Date.toString() confusingly grabs the JVM’s time zone setting (in your case apparently North American Eastern Time) and uses it for rendering the string to be returned. So in your case the point in time was rendered as Wed Sep 09 05:58:00 EDT 2020.