How to handle overlapping time intervals

When is the shop open?

Posted by Boris Stumm on Saturday, 5 August 2017

Some days ago I stumbled over some code that was calculating the opening hours for a shop in a certain time range. Besides the usual opening hours, e.g. 9:00 - 18:00, more things have to be taken into account:

  • on sundays and holidays, the shop is closed
  • certain days have extended or reduced opening hours, e.g. new year's eve or shopping nights
  • and sometimes, there are sunday openings

Getting a non-overlapping list of ranges of opening hours based on this information is not trivial, but I thought "it cannot be that difficult. After some googling I found Guava RangeSet, a class representing "A set comprising zero or more nonempty, disconnected ranges". The perfect tool for the job. Now, its just adding all of the previous information to a RangeSet (full code example):

val mutableRS = TreeRangeSet.create[LocalDateTime]()
(normalRanges ++ overrideRanges).foldLeft(mutableRS) { (rs, range) =>
  range match {
    case r if r.isEmpty => // whole day closed, so we _remove_ the corresponding range
      rs.remove(Range.closedOpen(r.lowerEndpoint(), r.lowerEndpoint() plusDays 1))
    case r => // add the open range
      rs.add(r)
  }
  rs
}