Java has excellent date-time formatting with the arrival of
java.time
(JSR310) in Java 8. I point out that release as it
came with a usable, safe API. (Let us never speak of Calendar
again).
However, I never recall how to format timezone. There are so many options, and it is easy to get is "almost right", but not exactly right.
Problem
I'd like to append a "Z" character on the end of a UTC timestamp. OK, let's look at the options, showing only those for timezone/offset:
Symbol | Meaning | Presentation | Examples |
---|---|---|---|
V | time-zone ID | zone-id | America/Los_Angeles; Z; -08:30 |
v | generic time-zone name | zone-name | Pacific Time; PT |
z | time-zone name | zone-name | Pacific Standard Time; PST |
O | localized zone-offset | offset-O | GMT+8; GMT+08:00; UTC-08:00 |
X | zone-offset 'Z' for zero | offset-X | Z; -08; -0830; -08:30; -083015; -08:30:15 |
x | zone-offset | offset-x | +0000; -08; -0830; -08:30; -083015; -08:30:15 |
Z | zone-offset | offset-Z | +0000; -0800; -08:00 |
One thing to be wary of: formatting characters can be doubled, tripled, or quadrupled, and it changes the result. Further, some characters have special rules on repeating (eg, "VV", and "O" vs "OOOO").
The best way to understand what to use is to try them all:
final var when = ZonedDateTime.of( LocalDate.of(2011, 2, 3), LocalTime.of(14, 5, 6, 7_000_000), ZoneId.of("UTC")) .toInstant(); for (final String tzFormat : List.of("VV", "v", "z", "zz", "zzz", "zzzz", "O", "OOOO", "X", "XX", "XXX", "XXXX", "x", "xx", "xxx", "xxxx", "Z", "ZZ", "ZZZ", "ZZZZ")) { System.out.println( tzFormat + " - " + DateTimeFormatter .ofPattern("yyyy-MM-dd'T'HH:mm:ss" + tzFormat) .withZone(ZoneId.of("UTC")) .format(when)); }
Producing:
VV - 2011-02-03T14:05:06UTC v - 2011-02-03T14:05:06UTC z - 2011-02-03T14:05:06UTC zz - 2011-02-03T14:05:06UTC zzz - 2011-02-03T14:05:06UTC zzzz - 2011-02-03T14:05:06Coordinated Universal Time O - 2011-02-03T14:05:06GMT OOOO - 2011-02-03T14:05:06GMT X - 2011-02-03T14:05:06Z XX - 2011-02-03T14:05:06Z XXX - 2011-02-03T14:05:06Z XXXX - 2011-02-03T14:05:06Z x - 2011-02-03T14:05:06+00 xx - 2011-02-03T14:05:06+0000 xxx - 2011-02-03T14:05:06+00:00 xxxx - 2011-02-03T14:05:06+0000 Z - 2011-02-03T14:05:06+0000 ZZ - 2011-02-03T14:05:06+0000 ZZZ - 2011-02-03T14:05:06+0000 ZZZZ - 2011-02-03T14:05:06GMT
What an exciting list! "zzzz" is rather wordy, and it's unclear what "ZZZZ" is doing. Actually, the whole list is even more iteresting for timezones other than UTC.
Solution
Since the goal is to append a "Z", the simplest choice is:
yyyy-MM-dd'T'HH:mm:ssX
.
Addendum
Why didn't I just use DateTimeFormatter.ISO_INSTANT
, which is
documented to produce the "Z"? I want a timestamp that is to only seconds-precision,
and the format for "ISO_INSTANT" includes milliseconds.