Check if date between date range that also handle null values Java
Asked Answered
B

3

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?

Bullace answered 26/10, 2016 at 11:44 Comment(3)
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.Helbonnas
It's to make it inclusive instead of strictly before and after.Bullace
assylias’ answer is best, but the second version of your code is pretty reasonable.Scilicet
H
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.

Hamford answered 26/10, 2016 at 11:51 Comment(4)
This is the cleanliest answer here. Might even use it myself since I have a similar case.Merous
This seems to work. I added a null check for date too to avoid NPE.Bullace
@Bullace I suspect a null date would be a bug so you could add Objects.requireNonNull(date); on the first line of your method.Hamford
This will fail for null start & end dates and gives opposite results,Josefajosefina
S
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;
}
Stairhead answered 26/10, 2016 at 12:0 Comment(3)
Can you add some example code showing how to use this in the context of the Question?Polak
@BasilBourque not sure what you mean - I did not change the signature of the isWithinRange method. Could you clarify what exactly you're asking?Stairhead
Yes, I see that now. I misread you code, thinking you were quoting from the Comparator class rather than using it.Polak
M
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));
}
Mellott answered 26/10, 2016 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.