I want to check if a LocalTime
is midnight. For this use case midnight is defined as anything in between 23:59
and 00:01
. That is a range of 2 minutes.
private final LocalTime ONE_MINUTE_BEFORE_MIDNIGHT = LocalTime.of(23, 59, 0);
private final LocalTime ONE_MINUTE_AFTER_MIDNIGHT = LocalTime.of(0, 1, 0);
I have a method
public boolean isAtMidnight(LocalTime time) {
return time.isAfter(ONE_MINUTE_BEFORE_MIDNIGHT)
&& time.isBefore(ONE_MINUTE_AFTER_MIDNIGHT);
}
This method is always returning false
. Even for LocalTime.MIDNIGHT
. it should, however, return true
.
How can I check if the time is +-1
minute from midnight?
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));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With