I have an API for JSON parsing which requires a DateTimeFormatter instance in order to parse date time strings to OffsetDateTime. However I always get an exception Unable to obtain ZoneOffset from TemporalAccessor: {},ISO resolved to 2021-08-17T13:26:49 of type java.time.format.Parsed The API uses OffsetDateTime.parse(String, DateFormatter).
// DateTimeFormatter instance to be provided to the API
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
// this is how the API uses the DateTimeFormatter instance
OffsetDateTime dateTime = OffsetDateTime.parse("20210817132649", formatter);
How do I have to create the DateTimeFormatter in order to deliver a ZoneOffset, so that the API is able to parse the DateTime correctly. The ZoneOffset may be UTC.
CodePudding user response:
Update
I understood from you that you are using the API as follows:
apiClient.getJSON().setOffsetDateTimeFormat(DateTimeFormatter);
and you do not have a way to pass timezone information. In this case, you can use DateTimeFormatter#withZone
as shown below:
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH)
.withZone(ZoneId.of("Etc/UTC"));
ZonedDateTime zdt = ZonedDateTime.parse("20210817132649", formatter);
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
}
}
Output:
2021-08-17T13:26:49Z
i.e. your call be now:
apiClient.getJSON().setOffsetDateTimeFormat(formatter);
Original answer
Your date-time string does not have a timezone offset. Parse it into a LocalDateTime
and then apply the offset to it.
Demo:
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH);
OffsetDateTime odt = LocalDateTime.parse("20210817132649", formatter)
.atOffset(ZoneOffset.UTC);
System.out.println(odt);
}
}
Output:
2021-08-17T13:26:49Z
The Z
in the output 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). You can specify a different timezone offset (e.g. ZoneOffset.of(" 05:30")
) as per your requirement.
In case you have ZoneId
available
If you have ZoneId
available, you should parse the given date-time string into a LocalDateTime
and then apply the ZoneId
to it to get a ZonedDateTime
from which you can always obtain an OffsetDateTime
. The best thing about a ZonedDateTime
is that it has been designed to adjust the timezone offset automatically whereas an OffsetDateTime
is used to represent a fixed timezone offset.
Demo:
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH);
ZonedDateTime zdt = LocalDateTime.parse("20210817132649", formatter)
.atZone(ZoneId.of("Etc/UTC"));
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
}
}
Output:
2021-08-17T13:26:49Z
You can specify a different ZoneId
(e.g. ZoneId.of("Asia/Kolkata")
) as per your requirement.
Learn more about the modern Date-Time API* from Trail: Date Time.
* 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. Note that Android 8.0 Oreo already provides support for java.time
.
CodePudding user response:
Better use a ZonedDateTime
- the difference being the Day Saving Time, and countries on with the same zone offset. Maybe using the default ZoneId
.
CodePudding user response:
Well, the string you passed in does not contain zone information, while an OffsetDateTime
requires zone information.
So you'll have to set a value for it.
You could use the DateTimeFormatterBuilder
class, which then can be instructed to use some default value if a field is missing from the parsed information:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.appendPattern("yyyyMMddHHmmss")
.toFormatter(Locale.ROOT);
You could also directly set an implied zone to the DateTimeFormatter
:
DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC);