Update
I understood from you that you are using the API as follows:
apiClient.getJSON().setOffsetDateTimeFormat(DateTimeFormatter);
and you do not have a parameter to pass timezone information. In this case, you can use DateTimeFormatter#withZone as shown below:
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)
.withZone(ZoneOffset.UTC);
OffsetDateTime odt = OffsetDateTime.parse("20210817132649", formatter);
System.out.println(odt);
}
}
Output:
2021-08-17T13:26:49Z
ONLINE DEMO
i.e. now, your call will be:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH)
.withZone(ZoneOffset.UTC);
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.
java - How to parse DateTime in format yyyyMMddHHmmss to OffsetDateTime using DateFormatter - Stack Overflow
Is it possible to format dates in format yyyyMMddHHmmssSSS and yyyyMMddHHmmss with a single DateTimeFormatter?
java - Parsing a date using DateTimeFormatter ofPattern - Stack Overflow
Convert date regardless of incoming pattern - Mirth Community
Update
I understood from you that you are using the API as follows:
apiClient.getJSON().setOffsetDateTimeFormat(DateTimeFormatter);
and you do not have a parameter to pass timezone information. In this case, you can use DateTimeFormatter#withZone as shown below:
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)
.withZone(ZoneOffset.UTC);
OffsetDateTime odt = OffsetDateTime.parse("20210817132649", formatter);
System.out.println(odt);
}
}
Output:
2021-08-17T13:26:49Z
ONLINE DEMO
i.e. now, your call will be:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH)
.withZone(ZoneOffset.UTC);
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.
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);
I receive dates in 2 formats (yyyyMMddHHmmssSSS and yyyyMMddHHmmss) from a system and I have to parse them based on the format. I tried different ways however, they are failing. Following is what I tried.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("[yyyyMMddHHmmss][SSS]")DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("yyyyMMddHHmmss").optionalStart().appendPattern("SSS").optionalEnd().toFormatter();
Both these formatters can parse 20220114123456 but not 20220114123456000.
The easy way would be 2 create 2 different formatters and based on the length of the input, use the appropriate formatter. I am looking for a better solution. Is it possible to do it using a single DateTimeFormatter ?
It can be done with SDF, but since it's not thread-safe, we don't use it in our project anymore.
It should be
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
//or
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz");
instead of
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-ddTHH:mm:ss.SSSZ");
From JAVADoc:
Offset X and x: This formats the offset based on the number of pattern letters. One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'. Two letters outputs the hour and minute, without a colon, such as '+0130'. Three letters outputs the hour and minute, with a colon, such as '+01:30'. Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'. Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'. Six or more letters throws IllegalArgumentException. Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.
Both "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ" and "yyyy-MM-dd'T'HH:mm:ss.SSSVV" would work. Note that 5 Zs work but no less