I think the problem is too complicated to allow for a clean solution, at least according to my definition of "clean".
You'll need a container for your (non-overlapping) daily intervals, supporting efficiently the following operations:
- find in which specific interval a given time belongs,
- move an interval backwards, in the container, and
- move to the last interval (in chronological order).
It seems to me that boost::icl::interval_set<Time>
is an adequate solution. Your time does not need to keep track of the date, you can have that separately.
Your algorithm will be something like:
let d and t be the date and time portions of your t
let i be the interval where t belongs
loop
if t-s belongs in i then
return t-s on day d
else
let j be the previous interval from i
if j does not exist (because i was the first) then
let j be the last interval
move d one weekday backwards
s := s - (t-start(i))
t := end(j)
i := j
This is more or less what you say that your code does. I don't think it can be much cleaner.