Java DateTimeFormatter和ISO 8601字符串

Java DateTimeFormatter和ISO 8601字符串,java,time,Java,Time,我正在使用一个RESTful api,它以ISO-8601格式返回带有偏移量的日期,下面显示了一个示例 2019-12-30T00:00:00.000+00:00 我正在使用下面的方法将日期字符串转换为传递的格式,它使用DateTimeFormatter.ISO_date_TIME,我根据oracle的文档选择了它,该文档声明“这返回一个不可变的格式化程序,能够格式化和解析ISO-8601扩展的本地或偏移日期时间格式” 下面是这个方法的一个简单测试 public static void m

我正在使用一个RESTful api,它以ISO-8601格式返回带有偏移量的日期,下面显示了一个示例

 2019-12-30T00:00:00.000+00:00
我正在使用下面的方法将日期字符串转换为传递的格式,它使用DateTimeFormatter.ISO_date_TIME,我根据oracle的文档选择了它,该文档声明“这返回一个不可变的格式化程序,能够格式化和解析ISO-8601扩展的本地或偏移日期时间格式”

下面是这个方法的一个简单测试

 public static void main(String[] args) {

    System.out.println(BaseConverter.formatISODateTime("2019-12-27T00:00:00.000+00:00", "MM/dd/yyyy"));
    System.out.println(BaseConverter.formatISODateTime("2019-12-27T00:00:00.000+18:00", "MM/dd/yyyy"));
    System.out.println(BaseConverter.formatISODateTime("2019-12-27T00:00:00.000-18:00", "MM/dd/yyyy"));
}
这是输出

 12/27/2019
 12/27/2019
 12/27/2019

我很难理解为什么偏移量(-/+18)不会产生不同的日期?

您正在解析为一个本地日期

尽管在时间轴上代表了不同的时刻(由于偏移),但在当地,中国的12月27日与委内瑞拉的12月27日是相同的。也就是说,当实例化
LocalDate
s时,信息将不可逆转地丢失

如果要打印不同的日期,您可能希望UTC发生转换

首先,您需要解析为一个同时保留时间和区域信息的结构(这样做),然后您可以手动转换为UTC

public static String formatISODateTime(String isoString, String format) {

    ZonedDateTime date = null;
    String returnDate = null;
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;

    try {
        date = ZonedDateTime.parse(isoString, dateTimeFormatter).withZoneSameInstant(ZoneOffset.UTC);
        returnDate = date.format(DateTimeFormatter.ofPattern(format));
    } catch(DateTimeParseException e) {
        // do something
    } catch(DateTimeException e) {
        // do something
    }

    return returnDate;
}
这张照片

12/27/2019
12/26/2019
12/27/2019

您正在解析为本地日期

尽管在时间轴上代表了不同的时刻(由于偏移),但在当地,中国的12月27日与委内瑞拉的12月27日是相同的。也就是说,当实例化
LocalDate
s时,信息将不可逆转地丢失

如果要打印不同的日期,您可能希望UTC发生转换

首先,您需要解析为一个同时保留时间和区域信息的结构(这样做),然后您可以手动转换为UTC

public static String formatISODateTime(String isoString, String format) {

    ZonedDateTime date = null;
    String returnDate = null;
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;

    try {
        date = ZonedDateTime.parse(isoString, dateTimeFormatter).withZoneSameInstant(ZoneOffset.UTC);
        returnDate = date.format(DateTimeFormatter.ofPattern(format));
    } catch(DateTimeParseException e) {
        // do something
    } catch(DateTimeException e) {
        // do something
    }

    return returnDate;
}
这张照片

12/27/2019
12/26/2019
12/27/2019

LocaleDate/LocalDateTime是区域不可知的。您提供了一个OffsetDateTime作为输入(更现实的是一个可以节省白天时间的ZonedDateTime)。将丢弃LocalDateTime的偏移量

为了显示效果,我使用了格式
“MM/dd/yyyy HH:MM:ss”
和时间部分

对于OffsetDateTime或ZonedDateTime,区域也将在输出中丢弃, 但它是可用的,选择世界时间协调,祖鲁时间,需要在时间中移动区域信息:

public static String formatISODateTime(String isoString, String format) {
    String returnDate = null;
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;

    try{
        // 1
        OffsetDateTime odate = OffsetDateTime.parse(isoString, dateTimeFormatter);
        returnDate = odate.atZoneSameInstant(ZoneId.of("UTC")).format(
                DateTimeFormatter.ofPattern(format));

        // 2
        ZonedDateTime zdate = ZonedDateTime.parse(isoString, dateTimeFormatter);
        returnDate = zdate.withZoneSameInstant(ZoneId.of("UTC")).format(
                DateTimeFormatter.ofPattern(format));
    } catch(DateTimeException e) {
        e.printStackTrace();
    }
    return returnDate;
}

12/27/2019 00:00:00
12/26/2019 06:00:00
12/27/2019 18:00:00

LocaleDate/LocalDateTime是区域不可知的。您提供了一个OffsetDateTime作为输入(更现实的是一个可以节省白天时间的ZonedDateTime)。将丢弃LocalDateTime的偏移量

为了显示效果,我使用了格式
“MM/dd/yyyy HH:MM:ss”
和时间部分

对于OffsetDateTime或ZonedDateTime,区域也将在输出中丢弃, 但它是可用的,选择世界时间协调,祖鲁时间,需要在时间中移动区域信息:

public static String formatISODateTime(String isoString, String format) {
    String returnDate = null;
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;

    try{
        // 1
        OffsetDateTime odate = OffsetDateTime.parse(isoString, dateTimeFormatter);
        returnDate = odate.atZoneSameInstant(ZoneId.of("UTC")).format(
                DateTimeFormatter.ofPattern(format));

        // 2
        ZonedDateTime zdate = ZonedDateTime.parse(isoString, dateTimeFormatter);
        returnDate = zdate.withZoneSameInstant(ZoneId.of("UTC")).format(
                DateTimeFormatter.ofPattern(format));
    } catch(DateTimeException e) {
        e.printStackTrace();
    }
    return returnDate;
}

12/27/2019 00:00:00
12/26/2019 06:00:00
12/27/2019 18:00:00

使用ZoneDateTime而不是LocalDate

公共静态字符串格式IsoDateTime(字符串isoString,字符串格式){


使用ZoneDateTime而不是LocalDate

公共静态字符串格式IsoDateTime(字符串isoString,字符串格式){


它有效地将它们解析为
LocalDate.of(2019,12,27)
LocalTime.of(0,0)
和偏移量
+/-18
;然后丢弃所有的
LocalDate
。它有效地将它们解析为
LocalDate.of(2019,12,27)
LocalTime.of(0,0)
和offset
+/-18
;然后丢弃除
LocalDate
之外的所有数据。回答得很好,实际上我几分钟前才发现ZonedDateTime(我对java.time包不熟悉)。这看起来确实像我想要的!
OffsetDateTime
ZonedDateTime
更适合,因为字符串包含-exactky、偏移量,如
+18:00
,而不是时区,如非洲/罗安达。此外,1-arg
OffsetDateTime.parse(CharSequence)
解析ISO 8601格式,因此我们不需要显式的格式化程序进行解析。@OleV.V.
ZonedDateTime.parse
一个arg签名也可以,我只是尽可能地保持它与他的原始代码相似。我不认为有任何理由更喜欢
OffsetDateTime
。值得注意的是,它的javadoc说“我们打算用
ZonedDateTime
Instant
在更简单的应用程序中对数据建模”。回答得很好,实际上我几分钟前才发现ZonedDateTime(我对java.time包不熟悉)。这看起来确实像我想要的!
OffsetDateTime
ZonedDateTime
更适合,因为字符串包含-exactky、偏移量,如
+18:00
,而不是时区,如非洲/罗安达。此外,1-arg
OffsetDateTime.parse(CharSequence)
解析ISO 8601格式,因此我们不需要显式的格式化程序进行解析。@OleV.V.
ZonedDateTime.parse
一个arg签名也能工作,我只是尽可能地保持它与他的原始代码相似。我看不出有任何理由更喜欢
OffsetDateTime
。值得注意的是,它的javadoc说“其目的是使用
ZonedDateTime
Instant
对更简单的应用程序中的数据进行建模”。