I have two time windows: daytime lasts from 07.00 to 19.00 every day, and nighttime lasts from 19.00 to 7.00 every day. Then I have 'maintenance intervals' with a given start and end time, [s,e]. s and e are real numbers indicating the number of hours since midnight of the very first day. For any maintenance interval, I would like to determine whether it is for the largest part during the day or for the largest part during the night.
Therefore I started to try to determine the total time that a maintenance interval is during daytime and the total time that a maintenance interval is during nighttime, but I cannot find out how to do this nicely.
Some inputs and outputs:
Observe also the similarity between 2 and 3. The 3rd interval lasts much longer (exactly a day longer than the 2nd), but the result would be the same. Potentially a nice solution can benefit from this characteristic, discarding all 'whole days in between' that do not matter to the eventual solution.
Preferably, I obtain an elegant solution that can be easily displayed in mathematical notation (rather than an entire algorithm).
Hope anyone can help!
This may be more nice than efficient. Unless an interval lasts years, you don’t need to worry about efficiency, and maybe even not in that case.
Let’s first declare some constants with nice names. My code is Java, but it should not be hard to translate into your programming language of choice.
private static int HOURS_PER_DAY = 24;
private static double DAY_BEGINS = 7;
private static double NIGHT_BEGINS = 19;
Now my algorithm goes like this:
// Maintenance interval to calculate;
// numbers are numbers of hours since start of the day where the shift begins
double start = 10;
double end = 49;
if (start < 0 || start >= 24 || end < start) {
throw new IllegalStateException();
}
double nightHours = 0;
double dayHours = 0;
double time = start;
double nextNightBegins = NIGHT_BEGINS;
double nextDayBegins = DAY_BEGINS;
if (time >= DAY_BEGINS) {
nextDayBegins += HOURS_PER_DAY;
if (time < NIGHT_BEGINS) { // time is in day time
// establish loop invariant
dayHours += NIGHT_BEGINS - time;
time = NIGHT_BEGINS;
}
nextNightBegins += HOURS_PER_DAY;
}
// Loop invariant:
// time <= nextDayBegins < nextNightBegins || time == end.
// Hours up to time have been summed into dayHours and nightHours.
while (time < end) {
assert time <= nextDayBegins : "" + time + " >= " + nextDayBegins;
assert nextDayBegins < nextNightBegins;
double nightHoursUntil = Math.min(nextDayBegins, end);
nightHours += nightHoursUntil - time;
time = nightHoursUntil;
nextDayBegins += HOURS_PER_DAY;
if (time < end) {
double dayHoursUntil = Math.min(nextNightBegins, end);
dayHours += dayHoursUntil - time;
time = dayHoursUntil;
nextNightBegins += HOURS_PER_DAY;
}
}
assert time == end;
System.out.format(Locale.ENGLISH,
"%.2f hours during nighttime, %.2f hours during daytime%n",
nightHours, dayHours);
if (nightHours > dayHours) {
System.out.println("Nighttime maintenance interval)");
} else if (nightHours < dayHours) {
System.out.println("Daytime maintenance interval");
} else { // they are equal
System.out.println("Undecided maintenance interval)");
}
Output as the code stands is:
18.00 hours during nighttime, 21.00 hours during daytime Daytime maintenance interval
I prefer not to take advantage of the fact that with your boundaries day and night have equal length (12 hours each). Some day a change is made so the night begins at 18:30 instead, and you don’t want to risk that your program tacitly starts to emit incorrect classifications then. In my algorithm above you can change the constant (from 19 to 18.5 in the example), and the code will still work.
I did consider using Java’s LocalTime
for the times, but LocalTime
only goes up to 23:59:59.999999999, so would not have worked immediately.
What you asked for: My idea is to calculate how many more or fewer nighttime hours than daytime hours compared to what I define as a standard situation where the interval starts and ends at 00:00. For this calculation we can safely take the remainder modulo 24 of the end time because it gives us the right hour of day (except for summer time transitions and such anomalies). So set e
to e % 24
and define a function nMinusD
that gives us how many more nighttime than daytime hours there are compared to e == 0
, signed:
nMinusD(e) = e for e <= 7
14 - e for 7 <= e <= 19
e - 24 for e >= 19
Sketching the curve on a piece of paper may help understanding.
For the start time we just need to reverse the sign of the result. So the final signed difference between nighttime and daytime hours is
diff = nMinusD(e) - nMinusD(s)
Now you can look at the sign of diff
.
diff > 0 => more nighttime hours than daytime hours
diff = 0 => equally many nighttime and daytime hours
diff < 0 => more daytime than nighttime hours