5

My standard method for checking if a date is between two dates in Java looks like this:

public static boolean isWithinRange(Date date, Date startDate, Date endDate) {
    return !(date.before(startDate) || date.after(endDate));
}

I want to add support for null values on startDate or endDate (meaning user hasn't entered a date. If startDate is null I only want to check endDate and if endDate is null I only want to check startDate and if both null then it is true. My current solution looks like this:

public static boolean isWithinRange(Date date, Date startDate, Date endDate) {
    if (startDate == null && endDate == null) {
        return true;
    }

    if (!(startDate != null || !date.after(endDate))) {
        return true;
    }

    if (!(endDate != null || !date.before(startDate))) {
        return true;
    }

    return !(date.before(startDate) || date.after(endDate));
}

alternative more readable example:

public static boolean isWithinRange(Date date, Date startDate, Date endDate) {
    if (startDate == null && endDate == null) {
        return true;
    }

    if (startDate == null && date.before(endDate))) {
        return true;
    }

    if (endDate == null && date.after(startDate))) {
        return true;
    }

    return date.after(startDate) && date.before(endDate));
}

But it feels like really bad code. Is there any other way to deal with this?

Mureinik
  • 297,002
  • 52
  • 306
  • 350
uraza
  • 907
  • 4
  • 12
  • 22
  • 1
    All the !'s are making it rather difficult for me to read. But you might consider whether this would be a better fit for codereview.stackexchange.com. –  Oct 26 '16 at 11:49
  • It's to make it inclusive instead of strictly before and after. – uraza Oct 26 '16 at 11:50
  • assylias’ answer is best, but the second version of your code is pretty reasonable. – VGR Oct 26 '16 at 12:19

3 Answers3

11

How about:

return (startDate == null || !date.before(startDate))
    && (endDate == null || !date.after(endDate));

This uses the fact that these two statements are equivalent:

!(date.before(startDate) || date.after(endDate))
!date.before(startDate) && !date.after(endDate)

And the fact that || is a short-circuit, which prevents NullPointerExceptions.

assylias
  • 321,522
  • 82
  • 660
  • 783
3

Java 8's enhances to the Comaparator interface provide a pretty elegant way of doing this:

private static final Comparator<Date> NULL_SAFE_BEFORE =
        Comparator.nullsFirst(Comparator.naturalOrder());

private static final Comparator<Date> NULL_SAFE_AFTER =
        Comparator.nullsLast(Comparator.naturalOrder());

public static boolean isWithinRange(Date date, Date startDate, Date endDate) {
    return NULL_SAFE_BEFORE.compare(startDate, date) < 0 &&
            NULL_SAFE_AFTER.compare(date, endDate) < 0;
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
  • Can you add some example code showing how to use this in the context of the Question? – Basil Bourque Oct 26 '16 at 16:16
  • @BasilBourque not sure what you mean - I did not change the signature of the `isWithinRange` method. Could you clarify what exactly you're asking? – Mureinik Oct 26 '16 at 18:22
  • Yes, I see that now. I misread you code, thinking you were quoting from the `Comparator` class rather than using it. – Basil Bourque Oct 26 '16 at 19:31
1

This should be equivalent:

public static boolean isWithinRange(Date date, Date startDate, Date endDate) {
    return !(startDate != null && date.before(startDate) || endDate != null && date.after(endDate));
}
ArcticLord
  • 3,999
  • 3
  • 27
  • 47