【问题标题】:Compare two date strings in different time zones with SimpleDateFormat in Java使用 Java 中的 SimpleDateFormat 比较不​​同时区的两个日期字符串
【发布时间】:2021-10-07 00:51:46
【问题描述】:

我有两个来自不同时区的日期:

String s1 = "2021-08-07T03:00:01-07:00";
String s2 = "2021-08-07T15:30:00+05:30";

我想比较两个日期。我正在解析如下日期:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss-hh:mm");
Date d = null;
try {
    d = sdf.parse(s1);
} catch (ParseException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
System.out.println(d);

如何使用字符串中提供的时区偏移将时区添加到日期?

【问题讨论】:

  • 我建议使用Instant::parse。一方面,它使用新的java.time API。另一方面,Instant 会自动处理时区。
  • 您的代码当前失败的原因是模式不正确。
  • @Turing85 OffsetDateTime 用于这些特定输入,而不是 Instant
  • @StephenC 那是因为SimpleDateFormat 太麻烦了。我们永远不应该使用它。 (现代的DateTimeFormatter 也会失败,但有一个例外告诉我们出了点问题,这已经是向前迈出了一步。)
  • @BasilBourque 一方面,Instant.parse() 确实适用于使用较新 Java 版本(11+?)的这些输入。另一方面,使用它当然意味着丢弃偏移信息,我们可能在某些时候想要将其用于其他目的,正如您所说,这是从一开始就使用OffsetDateTime 的论据。

标签: java date timezone


【解决方案1】:

tl;博士

OffsetDateTime
.parse( "2021-08-07T03:00:01-07:00" )
.isBefore(
    OffsetDateTime.parse( "2021-08-07T15:30:00+05:30" )
)

看到这个code run live at IdeOne.com

详情

正如评论,您的格式模式与您的数据不匹配。最后,您没有为从 UTC 的偏移量使用正确的代码。这不是带有加号和减号的一天中的时间。

永远不要使用那些可怕的过时日期时间类。它们在几年前被现代 java.time 类所取代。

默认情况下,可以使用 OffsetDateTime 类解析您的 ISO 8601 标准输入。无需定义格式模式。

String s1="2021-08-07T03:00:01-07:00";
String s2="2021-08-07T15:30:00+05:30";
OffsetDateTime odt1 = OffsetDateTime.parse( s1 ) ;
OffsetDateTime odt2 = OffsetDateTime.parse( s2 ) ;
boolean odt1IsEarlier = odt1.isBefore( odt2 ) ;

看到这个code run live at IdeOne.com

您可以选择将两个对象都调整为 UTC,偏移量为零时分秒。只需提取一个Instant

Instant i1 = odt1.toInstant() ;
Instant i2 = odt2.toInstant() ;

【讨论】:

  • 所以在比较它们之前我们应该把它们放在同一个时区,对吧?我如何将它们带入 UTC,然后我们可以比较它们?
  • @user1887464 (a) -07:00+05:30 是从 UTC 偏移的值,不是时区。时区是由政治家决定的特定地区人民使用的偏移量的过去、现在和未来变化的命名历史。 (b) 无需调整。 OffsetDateTime 类知道如何比较其偏移量不同的对象。
【解决方案2】:

正如其他人所指出的,避免使用被java.time 类取代的旧日期时间类(DateSimpleDateFormat)。

如果您仍想使用DateSimpleDateFormat,请继续阅读。

试试-

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public static void main(String[] args) {
    String inputDateString1 = "2021-08-07T03:00:01-07:00";
    String inputDateString2 = "2021-08-07T15:30:00+05:30";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    Date d1 = null, d2 = null;
    try {
        d1 = sdf.parse(inputDateString1);
        d2 = sdf.parse(inputDateString2);
        System.out.println("Date 1 = " + d1);
        System.out.println("Date 2 = " + d2);
        System.out.println("Date 1 - Date 2 in milliseconds = " + (d1.getTime() - d2.getTime()));
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

上面代码sn-p的输出是:-

Date 1 = Sat Aug 07 15:30:01 IST 2021
Date 2 = Sat Aug 07 15:30:00 IST 2021
Date 1 - Date 2 in milliseconds = 1000

【讨论】:

  • 非常感谢。感谢您在旧日期 API 中提供示例。希望我能给你们两个选择的答案
  • 你能告诉我如何将第一个日期转换为第二个日期吗?我的意思是应用时区?将 1 时间的日期转换为另一个时区
【解决方案3】:

answer by Basil Bourque 是正确的,是推荐的解决方案。您可以将此答案作为他答案的补充。

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,改用modern Date-Time API*

使用现代日期时间 API java.time 的解决方案:

现代日期时间 API 基于 ISO 8601,只要日期时间字符串符合 ISO 8601 标准,就不需要明确使用 DateTimeFormatter 对象。您的两个日期时间字符串都符合带有时区偏移的日期时间的 ISO 8601 格式,因此直接使用 OffsetDateTime 解析它们非常有意义。但是,从 Java SE 12 开始,您甚至可以将它们直接解析为 Instant

演示:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        String s1 = "2021-08-07T03:00:01-07:00";
        String s2 = "2021-08-07T15:30:00+05:30";

        Instant instant1 = Instant.parse(s1);
        Instant instant2 = Instant.parse(s2);

        System.out.println(s1 + " represents " + instant1);
        System.out.println(s1 + " represents " + instant2);

        if (instant1.isBefore(instant2)) {
            System.out.println(s1 + " is before " + s2);
        } else if (instant1.isAfter(instant2)) {
            System.out.println(s1 + " is after " + s2);
        } else {
            System.out.println("The strings represent the same instants.");
        }
    }
}

输出:

2021-08-07T03:00:01-07:00 represents 2021-08-07T10:00:01Z
2021-08-07T03:00:01-07:00 represents 2021-08-07T10:00:00Z
2021-08-07T03:00:01-07:00 is after 2021-08-07T15:30:00+05:30

ONLINE DEMO

Instant 表示时间线上的一个瞬时点,通常以UTC 时间表示。输出中的Z 是零时区偏移的timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(时区偏移量为 +00:00 小时)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 2014-11-15
    • 2020-08-16
    • 2019-07-25
    • 2012-10-23
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多