java.time DateTimeFormatter pattern for timezone offset
Solution 1
Use capital letter X instead of x, hence XXX. The difference is that big X can recognize the input letter "Z" as UTC-Offset +00:00 while small pattern letter X cannot.
Suggested pattern:
yyyy-MM-dd-HH.mm.ss.SSSSSSXXX
Please be also aware of following JDK-bug:
java.time.format.DateTimeFormatter cannot parse an offset with single digit hour
UPDATE:
I have now tested the described workaround in the bug-log.
String input = "2014-05-02-10.45.05.993280-5:00";
DateTimeFormatter f = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS")
.parseLenient()
.appendOffset("+HH:MM", "Z")
.toFormatter();
System.out.println(f.parse(input, ZonedDateTime::from));
But it throws an exception:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2014-05-02-10.45.05.993280-5:00' could not be parsed at index 26 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849) at HelloWorld.main(HelloWorld.java:16)
So lenient parsing does not help either. So there are now only three options left for you:
-
Use workaround suggested by bug reporter: [...] workaround is to parse the date/time separately, use a hand coded parser for the offset and combine the LocalDateTime with the hand parsed offset. Not an easy work around.
-
Try your own specialized string preprocessing. If you have a fixed format then you can try to insert the zero-digit at position 26 (if the total input length is one digit too small).
-
Or you use an external library which can do this. My library Time4J (v4.0) can do that if you are willing to add an extra dependency. See this code:
String input = "2014-05-02-10.45.05.993280-5:00";
ZonalDateTime zdt =
ZonalDateTime.parse(
input,
Moment.localFormatter("yyyy-MM-dd-HH.mm.ss.SSSSSSXXX", PatternType.CLDR));
System.out.println(zdt); // 2014-05-02T10:45:05,993280UTC-05:00
ZonedDateTime result = zdt.toTemporalAccessor();
Update: According to JDK-bug-status, the bug has been fixed for Java-9, but a backport for Java-8 does not seem to be available though.
Solution 2
Offset for SimpleDateFormat
sign is Z
check Java7
or Java8
SimpleDateFormat API
.
Then, your parser format for String
2014-05-02-10.45.05.993280-5:00
must be:
yyyy-MM-dd-HH.mm.ss.SSSSSSZ
UPDATE: for DateTimeFormatter
the offset Patterns for Formatting and Parsing are:
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;
Your desired pattern in DateTimeFormatter
is X
.
Solution 3
All the answers are good. The java8+ have these patterns for parsing and formatting timezone: V
, z
, O
, X
, x
, Z
.
Here's they are, for parsing, according to rules from the documentation :
Symbol Meaning Presentation Examples
------ ------- ------------ -------
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
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;
But how about formatting?
Here's a sample for a date (assuming ZonedDateTime
) that show these patters behavior for different formatting patters:
// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}
// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]
// Rules:
// printInPattern(dt, "V"); // exception!
printInPattern(dt, "VV"); // America/Los_Angeles
// printInPattern(dt, "VVV"); // exception!
// printInPattern(dt, "VVVV"); // exception!
printInPattern(dt, "z"); // PST
printInPattern(dt, "zz"); // PST
printInPattern(dt, "zzz"); // PST
printInPattern(dt, "zzzz"); // Pacific Standard Time
printInPattern(dt, "O"); // GMT-8
// printInPattern(dt, "OO"); // exception!
// printInPattern(dt, "OO0"); // exception!
printInPattern(dt, "OOOO"); // GMT-08:00
printInPattern(dt, "X"); // -08
printInPattern(dt, "XX"); // -0800
printInPattern(dt, "XXX"); // -08:00
printInPattern(dt, "XXXX"); // -0800
printInPattern(dt, "XXXXX"); // -08:00
printInPattern(dt, "x"); // -08
printInPattern(dt, "xx"); // -0800
printInPattern(dt, "xxx"); // -08:00
printInPattern(dt, "xxxx"); // -0800
printInPattern(dt, "xxxxx"); // -08:00
printInPattern(dt, "Z"); // -0800
printInPattern(dt, "ZZ"); // -0800
printInPattern(dt, "ZZZ"); // -0800
printInPattern(dt, "ZZZZ"); // GMT-08:00
printInPattern(dt, "ZZZZZ"); // -08:00
In the case of positive offset the +
sign character is used everywhere(where there is -
now) and never omitted.
This well works for new java.time
types. If you're about to use these for java.util.Date
or java.util.Calendar
- not all going to work as those types are broken(and so marked as deprecated, please don't use them)
Related videos on Youtube
wbd
Updated on June 11, 2021Comments
-
wbd almost 3 years
I am trying to parse:
2014-05-02-10.45.05.993280-5:00
where the-5:00
is the offset from UTC. Using a java.timeDateTimeFormatter
in Java 8.For the first bit I have the following:
yyyy-MM-dd-HH.mm.ss.SSSSSS
however, I can't figure out what the pattern should be to parse the offset also.If I had the offset with 4 digits (-05:00) I could use:
yyyy-MM-dd-HH.mm.ss.SSSSSSxxx
, but this doesn't work for 3 digits.Any ideas?
-
wbd almost 9 yearsI am using a
DateTimeFormatter
and adding aZ
does not appear ot work -
dcsohl almost 9 yearsYou linked to Java 7 twice. Java 8 API is here.
-
wbd almost 9 yearsThe pattern does not work...but the link to the bug looks like exactly my issue. I tried the builder suggestion, but that didn't appear to work either.
-
Meno Hochschild almost 9 years@Cheetah You are right. Sorry that you suffer from the bug. Please see also my update if you can use any of the alternative workarounds.
-
djangofan about 6 yearsI tried variations of this and cant get it to print the format "+00:00" on a GMT time. It will only print "+0000" . On the other hand, if the timezone is offset by at least 1, then DateTimeFormatter.ISO_OFFSET_DATE_TIME will print the former desired pattern.
-
SnellyBigoda about 3 yearsThe FORMATTING of the symbol is what was causing me issues. Thank you for this detailed example!