在Java中比较日期字符串

11

我正在使用dateString1.compareTo(dateString2)进行字符串比较,它基于每个字符的Unicode值进行字典比较,并返回一个整数。以下是代码示例。

String dateString1 = "05-12-2012";
String dateString2 = "05-13-2012";
if (dateString1.compareTo(dateString2) <=0){
   System.out.println("dateString1 is an earlier date than dateString2");
}

在Java中比较日期,这种方法是否错误?

在我的测试中,我没有遇到过意外的结果。如果可以不用创建一个日期对象并在长时间运行的循环内进行比较,我是不想这么做的。

忍者编辑 从下面的答案中可以得出结论,如果日期格式为yyyyMMdd,将字符串比较作为日期比较是没有问题的,但如果是其他格式,则会出现错误。

实际上,在我的代码中,我的日期字符串是yyyyMMdd格式。(我在上面给出的示例中输入了错误的格式)。所以,我现在会让代码保持原状,并添加一些注释来证明我的决定。

但我现在看到像这样比较字符串非常有局限性,如果数据库管理员决定在今后更改日期格式,我将遇到错误,尽管我认为这不太可能发生。


2
请看我之前提出的这个问题:https://dev59.com/1HE85IYBdhLWcg3w1HGF - ant
6个回答

18

在Java中使用字符串处理日期并不总是最佳选择。例如,在闰年时,二月有一个额外的日子。由于字符串可能看起来是正确的,因此执行转换更为适当。Java会验证日期是否正确。

您可以使用SimpleDateFormat类将字符串转换为日期。

public static void main(String[] args) throws ParseException {
    String dateString1 = "05-12-2012";
    String dateString2 = "05-13-2012";

    SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");

    Date date1 = format.parse(dateString1);
    Date date2 = format.parse(dateString2);

    if (date1.compareTo(date2) <= 0) {
        System.out.println("dateString1 is an earlier date than dateString2");
    }
}

要找出允许检查的参数,请参考Customizing Formats (The Java™ Tutorials > Internationalization > Formatting)


是的,输出dateString1在日期上早于dateString2。代码有什么问题吗? - Paul Vargas
日期字符串的格式与SimpleDateFormat构造函数不同。 - Thorbjørn Ravn Andersen
我之前没有注意到。谢谢指点。 - Paul Vargas
1
我喜欢你的答案,点个赞给你,但是我还是不明白为什么不将其转换为日期对象会导致我的代码在闰年出错。我将按字典顺序比较的只是 "02-29-2014" 和 "02-28-2014"。使用字符串比较方式仍然可以返回正确的值。 - pacman
仅当字符串正确时,比较才有效。使用“日期”可以确保这一点。 - Paul Vargas

8

我建议你按照这里描述的方式,将日期转换为正确的Date对象进行比较。如果性能实际上影响了应用程序(这很可能不会发生),再开始担心它的性能影响。


2
除了在2017年及以后,应该改用LocalDateDate在2012年是一个不错的选择,但现在已经过时了)。 - Ole V.V.

4

现在这样做是不好的,因为您无法处理年份变更。

如果您想这样做,您可能需要将日期格式化为YYYY-MM-DD,以避免新年破坏它。


2
任何建议将日期比较为字符串的方法都值得被打几个友好的拳头! :) - Alfabravo
4
YYYYMMDD可以被视为字符串进行比较。 - Thorbjørn Ravn Andersen

3

不应该使用字母排序规则来处理日期排序,这主要是因为按照字母和数字系统进行排序会导致排序方式不同的问题。

对于字母排序:

01-02-2011 comes before
01-1-2011 (because 0 in the date field is before 1 in the other date field)

对于数字系统:
01, 02, 2011 comes after
01, 1, 2011  because all fields are being compared like numbers

日期对象扩展了数字比较,以知道哪些字段在比较中优先考虑,这样你就不会出现一个早些月份将一个日期“放在”另一个实际发生在更晚月份但更早年份的日期之前的情况。

如果您严格控制日期格式,可以使日期遵循字母顺序规则对齐; 但是,这样做会有一个风险,即如果意外注入格式错误的日期,则整个程序可能以奇怪的方式失败。

通常的做法是(不建议使用,而是使用非字符串日期比较)

YYYYMMDD
(year)(month)(day) all zero-padded.

最后一种技术的主要目的是为了让你能够识别它,因为你最终会在实际开发中看到它,它是一种尝试在没有正确的日期库(即聪明的黑客技巧)的情况下处理日期的方法。

谢谢。你能给我最后一部分的参考资料吗?虽然这个案例对我来说非常有效,但我只是想确保逻辑是完全可靠的。 - ShikharDua

2

如讨论所述,通常最好使用日期时间对象而不是字符串。

java.time

其他答案使用过时的日期时间类,这些类被证明设计不佳、令人困惑且麻烦。它们缺乏一个能够真正表示仅包含日期值而不包含时间和时区的类。

相反,应该使用内置于Java 8及更高版本中的java.time框架。请参阅Oracle教程。Java.time的许多功能已经被移植到Java 6和7中的ThreeTen-Backport,并在ThreeTenABP中进一步适用于Android。

String input = "05-12-2012";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "MM-dd-yyyy" );
LocalDate ld = LocalDate.parse( input , formatter );

LocalDate 实现了 compareTo 方法。同时,你可以调用 equals、isBefore 和 isAfter 方法。

Boolean isEarlier = ld.isBefore( someOtherLocalDate );

1

如果您每个日期仅进行一次读取,那么YYYYMMDD(而不是您所使用的MMDDYYYY)可能是最优解。但是,如果您打算多次处理每个日期(例如,您正在对它们进行排序),那么肯定更好将它们更改为可比较速度更快的对象(例如日期)而不是字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接