【问题标题】:Java convert ISO 8601 string to Date ignoring offsetJava 将 ISO 8601 字符串转换为忽略偏移量的日期
【发布时间】:2020-12-28 08:50:34
【问题描述】:

我收到一个格式如下的字符串 "yyyy-MM-dd'T'HH:mm:ssZ" 例如:2020-09-09T09:58:00+0000" 偏移量是 UTC。

我需要将字符串转换为 Date 对象而不应用偏移量“+0000”,但是在运行我的代码时我不断得到不同的时间:

DateTimeFormatter isoFormat = ISODateTimeFormat.dateTimeParser();
Date date = isoFormat.parseDateTime("2020-09-09T09:58:00+0000").toDate();
// Wed Sep 09 05:58:00 EDT 2020

如上所示,日期已更改。

相反,我想保持相同的日期和时间,例如:Wed Sep 09 09:58:00,因此我可以将此 Date 对象转换为带有“yyyy-MM-dd”、“HH:mm:”的字符串: ss”和“yyyy-MM-dd'T'HH:mm:ss”格式。

【问题讨论】:

  • 你的问题没有意义,对不起。如果不应用偏移量或时区,就无法将您的字符串转换为Date。你想应用一个*不同的*偏移量吗??
  • 日期已更改 (1) 在Date 中,您得到的日期和时间没有更改。 (2) 当你打印Date 时,你隐式调用了它的toString 方法。该方法将日期和时间更改为 JVM 的默认时区。 Date 本身仍然没有改变。是的,我同意,这令人困惑。

标签: java date jodatime iso8601


【解决方案1】:

答案的第一个也是最重要的部分是:不要转换为老式的Date。要么坚持使用 Joda-Time,要么迁移到现代 Java 日期和时间 API 的 java.time,正如 Arvind Kumar Avinash 的好答案中所涵盖的那样。

由于您已经在使用 Joda-Time,我将向您展示 Joda-Time 解决方案。说服格式化程序保留解析字符串的时间和偏移量的技巧是withOffsetParsed()

    DateTimeFormatter isoFormat
            = ISODateTimeFormat.dateTimeParser().withOffsetParsed();
    String incomingString = "2020-09-09T09:58:00+0000";
    DateTime dateTime = isoFormat.parseDateTime(incomingString);

但是!如果我猜对了您想以 UTC 格式存储日期和时间(推荐做法),那么比 withOffsetParsed() 更好的是在解析器上指定 UTC:

    DateTimeFormatter isoFormat
            = ISODateTimeFormat.dateTimeParser().withZoneUTC();

现在,如果有一天一个具有非零 UTC 偏移量的字符串进入,您也将获得正确的时间。

无论如何,我们现在可以将您获得的DateTime 格式化为您请求的字符串。

    String dateString = dateTime.toString(ISODateTimeFormat.date());
    System.out.println(dateString);
    
    String timeString = dateTime.toString(ISODateTimeFormat.hourMinuteSecond());
    System.out.println(timeString);
    
    String dateTimeString = dateTime.toString(ISODateTimeFormat.dateHourMinuteSecond());
    System.out.println(dateTimeString);

输出:

2020-09-09
09:58:00
2020-09-09T09:58:00

使用 Date 有什么问题? 首先,Date 类设计不佳且早已过时。其次,Date 只是一个时间点,它没有日期和时间的概念(他们尝试在 Java 1.0 中将其构建到其中,但在 1997 年的 Java 1.1 中放弃并弃用了它)。因此,Date 无法为您保存 UTC 日期和时间。

您的代码中发生的事情是您得到了一个 Date 代表正确的时间点。只有当您打印 Date 时,您才会隐式调用其 toString 方法。 Date.toString() 混淆了 JVM 的时区设置(在您的情况下显然是北美东部时间)并使用它来呈现要返回的字符串。因此,在您的情况下,时间点呈现为Wed Sep 09 05:58:00 EDT 2020

【讨论】:

  • 任何使用我答案的人都不应错过此答案中的宝贵信息。
【解决方案2】:

我建议您使用 modern java.time 日期时间 API 和相应的格式化 API(包,java.time.format)来执行此操作。从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        // The given date-time string
        String strDateTime = "2020-09-09T09:58:00+0000";

        // Define the formatter
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ");

        // Parse the given date-time string into OffsetDateTime
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime, formatter);

        // Output OffsetDateTime in the default format
        System.out.println(odt);

        // Print OffsetDateTime using the defined formatter
        String formatted = formatter.format(odt);
        System.out.println(formatted);
    }
}

输出:

2020-09-09T09:58Z
2020-09-09T09:58:00+0000

注意:java.util.Date 不代表日期/时间对象。它只是代表没有。从1970-01-01T00:00:00Z 的纪元开始的毫秒数。它没有任何时区或时区偏移信息。当您打印它时,Java 会打印通过应用 JVM 的时区获得的字符串。我建议你停止使用 java.util.Date 并切换到现代日期时间 API。

使用joda date-time API,你可以这样做:

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

public class Main {
    public static void main(String[] args) {
        // The given date-time string
        String strDateTime = "2020-09-09T09:58:00+0000";

        // Define the formatter
        DateTimeFormatter isoFormat = ISODateTimeFormat.dateTimeParser();
        DateTime dateTime = isoFormat.parseDateTime("2020-09-09T09:58:00+0000");

        // Display DateTime in the default format
        System.out.println(dateTime);

        // Define formatter for ouput
        DateTimeFormatter outputFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ").withZoneUTC();

        // Display DateTime in the defined output format
        String formatted = outputFormat.print(dateTime);
        System.out.println(formatted);
    }
}

输出:

2020-09-09T10:58:00.000+01:00
2020-09-09T09:58:00+0000

【讨论】:

    猜你喜欢
    • 2019-02-27
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    • 2019-01-25
    • 1970-01-01
    相关资源
    最近更新 更多