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);
