Search code examples
javasimpledateformat

Java date string conversion to different format but with the same timezone


SimpleDateFormat from = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
SimpleDateFormat to = new SimpleDateFormat("MM/dd/yyyy Z");
Date date = from.parse("2017-08-10T00:00:00.000+0000");
String newDateStr = to.format(date);

The newDateStr is 08/09/2017 -0500. I expect that newDataStr can have the same timezone as the original date string(0000) -- 08/10/2017 -0000. What should I do to achieve this?


Solution

  • Preserving the offset from the original string is much easier with java.time, the modern Java date and time API:

        DateTimeFormatter from = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSZ");
        DateTimeFormatter to = DateTimeFormatter.ofPattern("MM/dd/yyyy Z");
        String newDateStr = OffsetDateTime.parse("2017-08-10T00:00:00.000+0000", from)
                .format(to);
        System.out.println(newDateStr);
    

    This prints

    08/10/2017 +0000
    

    This is not the only reason for recommending changing to the modern API. The Date class that you are using is long outdated, and SimpleDateFormat in particular is renowned for being troublesome to work with. I always recommend staying away from those classes in 2018. The modern API is generally much nicer. And since you are already using Java 8, there is absolutely no reason why you shouldn’t want it (for anyone reading along and using Java 6 or 7, the new API has been backported to those Java versions too).

    What went wrong?

    An old-fashioned Date object is just a point in time, it doesn’t hold a time zone or offset in it. So after you had parsed your string into a Date, the offset information was no longer there. So neither the Date nor to, the new formatter, had any way of knowing which offset or time zone had been in the original string. Instead, the new formatter used its own time zone. Since you had not explicitly set a time zone on the formatter, its time zone was that of your JVM, which apparently was a time zone that was on offset -5 from UTC on these days of September 2017.

    There are tricky ways to solve the problem with the outdated classes, but as I have probably said already, I wouldn’t want to bother.

    "Call requires API Level 26" for Android

    @Ponomarenko Oleh in a comment writes:

    Pay attention: "Call requires API Level 26" for Android.

    However, java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

    • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in. This is also the intended meaning of the message quoted in the comment.
    • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
    • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

    Links