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.