Home > Software engineering >  How to parse DateTime in format yyyyMMddHHmmss to OffsetDateTime using DateFormatter
How to parse DateTime in format yyyyMMddHHmmss to OffsetDateTime using DateFormatter

Time:10-18

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

ONLINE DEMO

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

ONLINE DEMO

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

ONLINE DEMO

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