1

My input string is:

"2016-06-13T14:20:09.866Z"

My output string is:

"2016-06-13T10:20:09.866-04"

Why are they different and how can I make it output in the same format as the input?

I convert from string to date:

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
dateFormat.parse((String) date));

In a unit test, I convert the parsed date back into a string:

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
dateFormat.format(date);
4castle
  • 32,613
  • 11
  • 69
  • 106
Nelson
  • 2,972
  • 3
  • 23
  • 34
  • What is the last `z` in the date? Does that denote something? – Codebender Jun 14 '16 at 15:17
  • Yes, @Codebender, according to [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) ´Z` means offset 0 from UTC. It’s sometimes pronounced “Zulu” after that military “time zone”. – Ole V.V. May 11 '21 at 08:53
  • I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `OffsetDateTime` and `DateTimeFormatter`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. May 11 '21 at 08:54

2 Answers2

4

The two dates are the same - only the format differs (one is 2pm UTC the other is 10am with an offset of -4 hours = 2pm UTC too).

So I suppose that what you want is to have the second string in UTC time zone too. In that case you can simply set the timezone of the second DateFormat:

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
assylias
  • 321,522
  • 82
  • 660
  • 783
2

Why are they different and how can I make it output in the same format as the input?

Both of them not only represent the same moment but are also in the same format, ISO 8601.

2016-06-13T14:20:09.866Z represents a date-time in UTC. The Z in it is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

2016-06-13T10:20:09.866-04 or 2016-06-13T10:20:09.866-04:00 represents a date-time at a timezone offset of -04:00 hours i.e. this moment can be represented as 2016-06-13T14:20:09.866+00:00 or 2016-06-13T14:20:09.866Z in UTC.

Note that the legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.

Demo using the modern API:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odtWithMinusFourHoursOffset = OffsetDateTime.parse("2016-06-13T10:20:09.866-04");
        System.out.println(odtWithMinusFourHoursOffset);

        OffsetDateTime odtWithSameMomentInUtc = odtWithMinusFourHoursOffset.withOffsetSameInstant(ZoneOffset.UTC);
        System.out.println(odtWithSameMomentInUtc);
    }
}

Output:

2016-06-13T10:20:09.866-04:00
2016-06-13T14:20:09.866Z

Did you notice, we did not use DateTimeFormatter here?

The modern date-time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the date-time string conforms to the ISO 8601 standards.

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


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110