11

So I am using dateString1.compareTo(dateString2) which does a lexicographic comparison with strings, based on the Unicode value of each character, and returns an int. Here is a code sample.

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");
}

Is this a wrong approach to compare dates in Java?

In my tests, I have not run into a situation where I have gotten unexpected result. I really do not want to create a Date object out of the string, if I don't have to, because I am doing this inside a long running loop.

Ninja Edit Gleaning from the answers below there is nothing wrong with comparing dates as a string if it is in yyyyMMdd format but if it is in any other format it will obviously result in error.

I actually have my date string as yyyyMMdd format in my actual code. (I typed the format wrong in the example I gave above.) So for now, I will just leave the code as it is, and add few lines of comments to justify my decision.

But I now see that comparing strings like this is very limiting and I will run into bugs if dba decides to change the date format down the road, which I don't see happening.

pacman
  • 1,061
  • 1
  • 17
  • 36
  • 2
    take a look at this question asked by me some time ago http://stackoverflow.com/questions/2592501/compare-dates-in-java – ant May 15 '12 at 22:21

6 Answers6

18

Use strings to handle dates in Java is not always the best option. For example, when it is a leap year, February has an extra day. Because strings can be seemingly correct, it is more appropriate to perform a conversion. Java validates that the date is correct.

You can convert strings to dates using the SimpleDateFormat class.

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");
    }
}

To find out which parameters are allowed to check Customizing Formats (The Java™ Tutorials > Internationalization > Formatting)

Paul Vargas
  • 41,222
  • 15
  • 102
  • 148
8

I suggest you do the Right Thing (as described here) and convert to proper Date objects to compare. Worry about the performance impact if and when it actually impacts your application (which it probably won't).

Community
  • 1
  • 1
andersoj
  • 22,406
  • 7
  • 62
  • 73
  • 2
    Except in 2017 (and onward), convert to `LocalDate` instead (`Date` was a fine choice in 2012, it is long outdated now). – Ole V.V. Jun 08 '17 at 11:49
4

It is pretty bad as now you cannot handle a year change.

If you want to do it like that you might wanna format the date as YYYY-MM-DD so the new year doesn't ruin it.

xuesheng
  • 3,396
  • 2
  • 29
  • 38
ratchet freak
  • 47,288
  • 5
  • 68
  • 106
3

It is bad to use the rules for alphabetization to handle date ordering, mostly because you run into issues where things are ordered differently according to the alphabet and the number system

For the alphabet

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

For the number system

01, 02, 2011 comes after
01, 1, 2011  because all fields are being compared like numbers

Date objects extend numeric comparison to know which fields take precedence in the comparison, so you don't get a earlier month putting a date "before" another that actually occurs at a latter month but an earlier year.

If you have strict control over the date format, you can align the dates such that they also follow alphabetical rules; however, doing so runs a risk of having your entire program fail in odd ways if you accidentally inject a misformatted date.

The typical way to do this is (not recommended, please use non-String Date comparisons)

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

The last technique is included mainly as you will eventually see it in the wild, and should recognize it for what it is: an attempt to handle dates without a proper date library (aka a clever hack).

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • Thanks. Could you give reference for the last part ? This case works for me very well but I just want to make sure the logic is full proof – ShikharDua Dec 23 '14 at 00:40
2

As discussed, generally better to work with date-time objects rather than strings.

java.time

The other Answers use old outmoded date-time classes that have proven to be poorly designed, confusing, and troublesome. They lack a class to truly represent a date-only value without time-of-day and without time zone.

Instead use the java.time framework built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.

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

The LocalDate implements compareTo. Also, you can call methods equals, isBefore, isAfter.

Boolean isEarlier = ld.isBefore( someOtherLocalDate );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
1

if you are doing only one read of each date then YYYYMMDD (not MMDDYYYY as you did it) might be the most optimal solution. however when you intend to process each date more than once (e.g. you are sorting them) then for sure it's better to change them to an object that can be compared quicker than string (e.g. date)

piotrek
  • 13,982
  • 13
  • 79
  • 165