如何使用 DateFormatter 将格式为 yyyyMMddHHmmss 的 DateTime 解析为 OffsetDateTime

How to parse DateTime in format yyyyMMddHHmmss to OffsetDateTime using DateFormatter

我有一个 API 用于 JSON 解析,它需要 DateTimeFormatter 实例才能将日期时间字符串解析为 OffsetDateTime。但是我总是遇到异常 无法从 TemporalAccessor 获取 ZoneOffset:{},ISO 解析为 java.time.format.Parsed 类型的 2021-08-17T13:26:49 API 使用 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);

我必须如何创建 DateTimeFormatter 才能提供 ZoneOffset,以便 API 能够正确解析 DateTime。 ZoneOffset 可能是 UTC。

更新

我从你那里了解到你正在使用 API 如下:

apiClient.getJSON().setOffsetDateTimeFormat(DateTimeFormatter); 

并且您没有传递时区信息的参数。在这种情况下,您可以使用 DateTimeFormatter#withZone 如下所示:

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

输出:

2021-08-17T13:26:49Z

ONLINE DEMO

即现在,您的电话是:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss", Locale.ENGLISH)
                                .withZone(ZoneOffset.UTC);

apiClient.getJSON().setOffsetDateTimeFormat(formatter); 

原回答

您的日期时间字符串没有时区偏差。将其解析为 LocalDateTime,然后对其应用偏移量。

演示:

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

输出:

2021-08-17T13:26:49Z

ONLINE DEMO

输出中的 Z 是零时区偏移量的 timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(时区偏移量为 +00:00 小时)。您可以根据您的要求指定不同的时区偏移量(例如 ZoneOffset.of("+05:30"))。

如果您有 ZoneId 可用

如果您有 ZoneId 可用,您应该将给定的日期时间字符串解析为 LocalDateTime,然后将 ZoneId 应用于它以获得 ZonedDateTime您总能从中获得 OffsetDateTimeZonedDateTime 最好的一点是它被设计为自动调整时区偏移量,而 OffsetDateTime 用于表示固定的时区偏移量。

演示:

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

输出:

2021-08-17T13:26:49Z

ONLINE DEMO

您可以根据需要指定不同的 ZoneId(例如 ZoneId.of("Asia/Kolkata"))。

详细了解 modern Date-Time API* from Trail: Date Time


* 如果您正在为一个 Android 项目工作并且您的 Android API 水平仍然不符合 Java-8,检查Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time

最好使用 ZonedDateTime - 区别在于夏令时和具有相同时区偏移的国家/地区。也许使用默认 ZoneId.

嗯,您传入的字符串不包含区域信息,而 OffsetDateTime 需要区域信息。

因此您必须为其设置一个值。

您可以使用 DateTimeFormatterBuilder class,如果解析信息中缺少某个字段,则可以指示它使用一些默认值:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    .parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
    .appendPattern("yyyyMMddHHmmss")
    .toFormatter(Locale.ROOT);

您也可以直接将隐含区域设置为 DateTimeFormatter:

DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC);