java.time and ThreeTenABP
The bullet-proof way is switching to java.time, the modern Java date and time API.
DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("MM/dd/yyyy", Locale.ENGLISH);
LocalDate date = LocalDate.parse("06/05/2020", dateFormatter);
System.out.println(date);
Output is:
2020-06-05
What went wrong in your code?
It’s certainly a time zone problem. However, it isn’t reproduced by naïvely running your code. There is something more going on, and we can only guess at exactly what. I’ll present a couple of ways that this might have happened.
The first possibility, the default time zone of your JVM might have changed underway. To demonstrate:
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
Date date = sdf.parse("06/05/2020");
TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));
System.out.println(date);
Thu Jun 04 18:00:00 MDT 2020
In all fairness it’s not a full day wrong, it’s 6 hours. It’s bad enough, and certainly the day of week and day of month are wrong. Please note that the JVM’s time zone setting may have been changed from a completely different part of your program or from a different program running in the same JVM. What happened was: The SimpleDateFormat
got the default time zone of the JVM, that is, UTC. So parsed the date into the first moment of June 5 in UTC. At this point in time, it’s still June 4 in North America. Next, when we print the Date
, Date.toString()
grabs the (changed) time zone of the JVM and uses it for rendering the string. Therefore we got the MDT time (North American Mountain Daylight Time), not the UTC time that had been used for parsing.
We don’t need something as drastic as setting the time zone for the entire JVM to demonstrate, though. It’s enough to set the time zone of the formatter.
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Date date = sdf.parse("06/05/2020");
System.out.println(date);
When running in America/Edmonton time zone:
Thu Jun 04 18:00:00 MDT 2020
What happens is basically the same as above.
Question: Doesn’t java.time require Android API level 26?
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.
- 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