使用偏移量处理字符串日期

问题描述

我在从外部系统接收的持久存储中有日期时间。我需要使用它并将其设置为 Java 库例程的日期类型。这混淆了在当前 jvm 时区下设置的相同内容。我知道偏移量不一定对应时区,但是,这会搞砸很多事情。

例如:

2020-08-14T08:59:34.961+05:30

示例代码

String dateFromDatabase = "2020-08-14T08:59:34.961+05:30";
SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date tempDate=outputDateFormat.parse(dateFromDatabase);
System.out.println( tempDate );

示例输出

Thu Aug 13 23:29:34 EDT 2020

预期输出

it should not return the EDT based datetime

如何使用正确的偏移量保持我的日期?

关于如何实现这一目标有任何建议吗?

谢谢

解决方法

java.util.Date 对象不是像 modern date-time types 那样的真实日期时间对象;相反,它表示自称为“纪元”的标准基准时间以来的毫秒数,即 January 1,1970,00:00:00 GMT(或 UTC)。这意味着无论世界上的位置如何,Date 对象都表示相同的数字(从纪元开始的毫秒数)。当您打印 java.util.Date 的对象时,它的 toString 方法返回 JVM 时区中的日期时间,从这个毫秒值计算出来。为了在不同的时区打印日期时间,我们将时区设置为 SimpleDateFormat 并从中获取格式化的字符串。

如果您不喜欢 Thu Aug 13 23:29:34 EDT 2020 这样的输出,它是 Date#toString 在您所在的时区返回的字符串(并且在不同的时区会有所不同),有两种选择:

  1. 表示使用 Date#getTime 获得的以毫秒为单位的 Date(如上所述,它在世界上的任何位置都是相同的)。
  2. 保留原始字符串 2020-08-14T08:59:34.961+05:30 原样,因为它已经表示 ISO8601 format 中的日期时间。

请注意,java.util 日期时间 API 及其格式 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern date-time API*

现代日期时间 API 的演示:

import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Date;

public class Main {

    public static void main(String args[]) {
        String dateFromDatabase = "2020-08-14T08:59:34.961+05:30";
        ZonedDateTime zdt = ZonedDateTime.parse(dateFromDatabase);
        System.out.println(zdt);

        // If at all you need java.util.Date,you can get it from Instant
        Instant instant = zdt.toInstant();
        Date date = Date.from(instant);
    }
}

输出:

2020-08-14T08:59:34.961+05:30

Trail: Date Time 了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project