简体   繁体   English

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

[英]How to parse DateTime in format yyyyMMddHHmmss to OffsetDateTime using DateFormatter

I have an API for JSON parsing which requires a DateTimeFormatter instance in order to parse date time strings to OffsetDateTime.我有一个用于 JSON 解析的 API,它需要一个 DateTimeFormatter 实例才能将日期时间字符串解析为 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).但是我总是得到一个异常Unable to get ZoneOffset from TemporalAccessor: {},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);

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.我必须如何创建 DateTimeFormatter 才能提供 ZoneOffset,以便 API 能够正确解析 DateTime。 The ZoneOffset may be UTC. ZoneOffset 可以是 UTC。

Update更新

I understood from you that you are using the API as follows:我从您那里了解到您使用的 API 如下:

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:在这种情况下,您可以使用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);
    }
}

Output:输出:

2021-08-17T13:26:49Z

ONLINE DEMO在线演示

ie 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.将其解析为LocalDateTime ,然后对其应用偏移量。

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.输出中的Z是零时区偏移的时区指示符 It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).它代表祖鲁语并指定Etc/UTC时区(时区偏移为+00:00小时)。 You can specify a different timezone offset (eg ZoneOffset.of("+05:30") ) as per your requirement.您可以根据您的要求指定不同的时区偏移量(例如ZoneOffset.of("+05:30") )。

In case you have ZoneId available如果您有可用的ZoneId

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 .如果您有可用的ZoneId ,则应将给定的日期时间字符串解析为LocalDateTime ,然后将ZoneId应用于它以获取ZonedDateTime ,您始终可以从中获取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. ZonedDateTime最好的一点是它旨在自动调整时区偏移,而OffsetDateTime用于表示固定的时区偏移。

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 (eg ZoneId.of("Asia/Kolkata") ) as per your requirement.您可以根据您的要求指定不同的ZoneId (例如ZoneId.of("Asia/Kolkata") )。

Learn more about the modern Date-Time API * from Trail: Date Time .Trail: Date Time 中了解有关现代日期时间 API * 的更多信息。


* 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 . * 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 通过 desugaring 可用的 Java 8+ API Note that Android 8.0 Oreo already provides support for java.time .请注意,Android 8.0 Oreo 已提供java.time支持

Better use a ZonedDateTime - the difference being the Day Saving Time, and countries on with the same zone offset.更好地使用ZonedDateTime - 不同之处在于日保存时间和具有相同区域偏移量的国家/地区。 Maybe using the default ZoneId .也许使用默认的ZoneId

Well, the string you passed in does not contain zone information, while an OffsetDateTime requires zone information.好吧,您传入的字符串不包含区域信息,而OffsetDateTime需要区域信息。

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:您可以使用DateTimeFormatterBuilder类,如果解析信息中缺少某个字段,则可以指示该类使用一些默认值:

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设置一个隐含区域:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM