2

I am having troubles comparing dates as strings. I am required to iterate through a collection and compare the date value of each object against 2 dates passed as parameters. The dates are all stored as strings and am required to keep them that way.

It is known that the dates will all be formatted YYYY-MM-DD. Below is a quick example of what I mean. Thanks all!

public ArrayList<Object> compareDates(String dateOne, String dateTwo) {
    for(Object object : objectCollection) {
        String objectDate = object.getDate();
        if(objectDate.equals(dateOne) || objectDate.equals(dateTwo)) { // Unsure of how to determine if the objects date is inbetween the two given dates
            //add object to collection
        }
    }
return  collection;
}
Jude Niroshan
  • 4,280
  • 8
  • 40
  • 62
SnugglyCrow
  • 35
  • 1
  • 4
  • 1
    why would you want to compare dates as Strings? there are tons of tools to make comparisons of dates easy and precise, why not use those? – Stultuske Sep 05 '18 at 10:47
  • 1
    convert to a date object before compare is the only sane method – fantaghirocco Sep 05 '18 at 10:49
  • If you really want to stick to `String`s, then split them by `"-"` and compare the separated values. You may have to cast them to `int` then... – deHaar Sep 05 '18 at 10:49
  • 1
    Maybe you can use the `SimpleDateFormat` to make concrete `Date` objects out of your string and compare these. – AnarchoEnte Sep 05 '18 at 10:49
  • The example above doesn't look complete, i.e. it doesn't contain the defintion of the `objectCollection` variable. Like @Stultuske said, why compare them as streings? You can parse them in to `Calendar`s or `Date`s which are comparable. – mhvelplund Sep 05 '18 at 10:49
  • `Object` does not contain a `getDate` method. Thus, this code is not supposed to compile. – RealSkeptic Sep 05 '18 at 11:07
  • Yes. I understand the code is incomplete and wont compile. That is not exactly what my code looks like but is just a random example to get my point across. – SnugglyCrow Sep 06 '18 at 05:09

4 Answers4

3

Since your dates are in the YYYY-MM-DD format, a lexicographic comparison can be used to determine the ordering between two dates. Thus, you can just use the String.compareTo() method to compare the strings:

int c1 = objectDate.compareTo(dateOne);
int c2 = objectDate.compareTo(dateTwo);
if ((c1 >= 0 && c2 <= 0) || (c1 <= 0 && c2 >= 0)) {
    // objectDate between dateOne and dateTwo (inclusive)
}

If it is guaranteed that dateOne < dateTwo, then you can just use (c1 >= 0 && c2 <= 0). To exclude the date bounds, use strict inequalities (> and <).

Holmes
  • 406
  • 4
  • 7
  • Agreed with your answer. However, I *guess* what the author of the question has trouble doing is not so much comparing the strings, but rather, how to express/implement a "between" relationship in terms of String.compareTo(), which returns an int. Maybe you could expand your answer to address this part too. (@ernest_k's answer was just posted, adding such an explanation) – GPI Sep 05 '18 at 11:02
  • Thank you for this! Between yours and @ernest_k's answer it makes a lot of sense now! – SnugglyCrow Sep 05 '18 at 12:09
0

Here is the procedure you need to follow:

  1. Convert both String dateOne, String dateTwo into java.time.LocalDate
  2. Iterate over your ArrayList and convert the indexed string into java.time.LocalDate

    Note: You need to accept ArrayList<String> in order to parse the string to LocalDate, not ArrayList<Object>

  3. Do the comparison

Refer to the documentation to implement the comparison logic.

You may refer to this link for additional help.

Jude Niroshan
  • 4,280
  • 8
  • 40
  • 62
0

As your dates are in the yyyy-MM-dd format, then String's compareTo should return consistent results:

if(objectDate.compareTo(dateOne) >= 0 && objectDate.compareTo(dateTwo) <= 0)

This roughly checks (conceptually): objectDate >= dateOne && objectdate <= dateTwo

That's just if one must use string's methods. A better approache, though, would be to convert the strings to date objects and perform a date-based comparisons.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • I don't think conversion to date is better. String comparison is fast, conversion is slow, and if the OP is supposed to keep the dates as they are, it means converting every time. – RealSkeptic Sep 05 '18 at 11:02
  • Maybe you could stress that your implementation works only when `dateOne` is before `dateTwo`. – GPI Sep 05 '18 at 11:04
  • @RealSkeptic Not really. This is easy because it's just local date values. What if time zones, offsets, daylight savings complexities are introduced? Date/time types would clearly be more appropriate. – ernest_k Sep 05 '18 at 11:04
  • Comparing strings is just going through them once. Converting them requires going through them once, and then also doing validity checks for the day and month. – RealSkeptic Sep 05 '18 at 11:06
  • @RealSkeptic Not arguing your point. You're talking performance, I'm talking accuracy. But you've got a valid point, not disputing that. – ernest_k Sep 05 '18 at 11:08
  • Thank you! This is what I was looking for. I know it seems kind of odd to keep them as Strings but my prof wont allow me to convert them to a date object even though it seemed vastly simpler to me. – SnugglyCrow Sep 05 '18 at 12:07
0

If dateOne is before dateTwo you can use following comparison if you like have date inbetween.

    public ArrayList<Object> compareDates(List<Object> objectCollection, String start, String end) {
        ArrayList<Object> dateBetween = new ArrayList<>();
        for(Object object : objectCollection) {
            LocalDate objectDate = parseDate(object.getDate());
            if( !objectDate.isBefore(parseDate(start)) && !objectDate.isAfter(parseDate(end))) {
                dateBetween.add(object);
            }
        }
        return dateBetween;
    }

    private LocalDate parseDate(String date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-DD");
        return LocalDate.parse(date, formatter);
    }
Bartek
  • 2,109
  • 6
  • 29
  • 40
  • Parsing `start` and `end` at each loop iteration may be quiete expensive... – GPI Sep 05 '18 at 11:06
  • Yes, but comparing date as strings seems for me a bit tricky. – Bartek Sep 05 '18 at 11:09
  • You could parse them, as dates, once at the start of the method. Just a thought. – GPI Sep 05 '18 at 13:32
  • Does this increase performance, after all you have the same number of dates to parse? – Bartek Sep 05 '18 at 13:36
  • If you have N items in the collection, with the current code, you call `parseDate` 3 times (1 for `object.getDate`, one for `start`, once for `end`) on each iterations, so `3*N` times total. But only `N+2` times are necessary (once and only once for `start` and `end`, and once for each of the N objects). That is a lot of unnecessary `DateTimeFormatter` instanciation and calls to `parse` if you happen to have a huge list. – GPI Sep 05 '18 at 15:03