Half-Open
Generally the best practice in date-time handling is to define a span of time using the Half-Open approach where the beginning is inclusive while the ending is exclusive.
So a day starts with the first moment of one day and runs up to, but does not include, the first moment of the following day. This avoids the problem of trying to determine the infinitely-divisible fractional second of the last moment of the first day.
A month span starts with the first of the month and runs up to, but does include, the first day of the following month. So the month of February runs Feb 1st to March 1st, with no need to determine Leap Year, and no need to determine the length of any month.
Lunch period starts with noon and runs up to, but does not include, 1 PM: 12:00 – 13:00. The next class period runs from 1 PM to 2 PM: 13:00 – 14:00. This lunch period and class period nearly abut one another but do not overlap (because the lunch 13:00 is exclusive).
Also, using the Half-Open approach consistently throughout your codebase makes your code easier to read, with less cognitive burden. And the Half-Open approach makes intervals of stop-start moments abut one another nicely for easier comparisons.
Comparison
Comparing intervals is easy.
For overlap, ask if the start of interval X is before the stop of interval Y AND if the the stop of interval X is after the start of interval Y.
( X.start > Y.stop ) && ( X.stop > Y.start )
Objects
On Object-Oriented environments you should be writing a class to represent each stop-start interval. Build on the comparison code with methods such as “contains”, “overlaps”, etc.
java.time
In Java, we are fortunate to have the best date-time framework in the industry, java.time.
The built-in functionality is further extended by the classes of the ThreeTen-Extra project (the definition of java.time having been JSR 310).
In ThreeTen-Extra you’ll find the Interval
class for a pair of Instant
objects. An Instant
is a moment, a point on the timeline in UTC, with a resolution of nanoseconds. For a pair of date-only values (LocalDate
), use the LocalDateRange
class.
Both classes have already implemented all the comparison methods you’ll likely need.
- abuts
- contains
- encloses
- equals
- intersection
- isAfter
- isBefore
- isConnected
- isEmpty
- overlaps
- span
- union
These classes are open-source so you may peruse the algorithms.
Note that intersection
gives you an interval of the overlap between a pair of intervals.
The union
method gives you an interval with the earliest start and the latest stop. You can maintain an ever-growing unioned-interval of all the comparisons made so far. That tells you if the next comparison lies entirely before or entirely after all the previously-compared intervals, and thus saves you from needless comparisons.