in reply to Average start time handling midnight

You can calculate the average and the variance for the 24h intervals centered around every hour (0, 1, 2,... 23) and pick the center which minimizes the variance:
use POSIX qw(fmod); my @data = (1, 1, 1, 0, 1, 2, 3, 4, 21, 22, 20, 22, 23, 20, 22); sub circular_average { my ($pivot, $round, @data) = @_; my $sum = 0; my $sum2 = 0; my $displacement = 1.5 * $round - $pivot; for my $data (@data) { my $displaced = fmod($data + $displacement, $round); # printf "%2i->%3i,%2i ", $data, $displaced, $displaced - $dis +placement; $sum += $displaced; $sum2 += $displaced * $displaced; } # print "\n"; my $inv_n = 1.0 / @data; my $avg = fmod($inv_n * $sum + 0.5 * $round + $pivot, $round); wantarray ? ($avg, $inv_n * $sum2 - $inv_n * $inv_n * $sum * $sum) + : $avg; } my ($best_avg, $best_s2); for my $time (0..23) { my ($avg, $s2) = circular_average $time, 24, @data; if (not defined $best_s2 or $best_s2 > $s2) { $best_avg = $avg; $best_s2 = $s2; } } printf "avg: %.1f, s2: %.1f\n", $best_avg, $best_s2;
Then, you can even iterate a few times centering the interval around the best average ($best_avg) found:
for (0..5) { ($best_avg, $best_s2) = circular_average $best_avg, 24, @data; printf "avg: %.1f, s2: %.1f\n", $best_avg, $best_s2; }