LocalTime between 23.59 and 00:01

The solution is to use || instead of &&:

public boolean isAtMidnight(LocalTime time) {
    return time.isAfter(ONE_MINUTE_BEFORE_MIDNIGHT) || time.isBefore(ONE_MINUTE_AFTER_MIDNIGHT);
}

This is so counter-intuitive, isn't it? The trick is that 00:00:01 are not after 23:59, so that's always going to fail. This is so because LocalTime.isAfter or LocalTime.isBefore assumes that those are times of the same day.


Instead of checking if time is after 23:59 and before 00:01, you should check if it is after 23:59 or before 00:01.

public boolean isAtMidnight(LocalTime time){
    return time.isAfter(ONE_MINUTE_BEFORE_MIDNIGHT) || time.isBefore(ONE_MINUTE_AFTER_MIDNIGHT);
}

If we look at the implementation for LocalTime#isAfter, we see the following:

public boolean isAfter(LocalTime other) {
    return compareTo(other) > 0;
}

Looking at LocalTime#compareTo:

@Override
public int compareTo(LocalTime other) {
    int cmp = Integer.compare(hour, other.hour);
    if (cmp == 0) {
        cmp = Integer.compare(minute, other.minute);
        if (cmp == 0) {
            cmp = Integer.compare(second, other.second);
            if (cmp == 0) {
                cmp = Integer.compare(nano, other.nano);
            }
        }
    }
    return cmp;
}

We can see that two instances of LocalTime are first compared by their respective hours, then minutes, then seconds, and finally nanoseconds. For LocalTime#compareTo to return a value greater than 0 to satisfy LocalTime#isAfter, the hour of the first LocalTime instance must be greater than the second instance's. This is not true for 00:00 and 23:59, hence why your method returns false. The same analysis can be done for LocalTime#isBefore, and you'll arrive at the same result.

Keep in mind that you can just check against LocalTime.MIDNIGHT if you want to be exact, but I assume you're considering any time within a 1-minute range to be "midnight" (including seconds).


If you really need to do this that way, it cannot fulfil both statements. Consider using or, this code returns true for me:

public static void main(String[] args)
{
    LocalTime ONE_MINUTE_BEFORE_MIDNIGHT = LocalTime.of(23, 59, 0);
    LocalTime ONE_MINUTE_AFTER_MIDNIGHT = LocalTime.of(0, 1, 0);
    LocalTime md = LocalTime.MIDNIGHT;
    System.out.println(md.isBefore(ONE_MINUTE_AFTER_MIDNIGHT) || md.isAfter(ONE_MINUTE_BEFORE_MIDNIGHT));
}