Averages/Mean time of day: Difference between revisions

From Rosetta Code
Content added Content deleted
(task description: Improve formatting and add related tasks box)
Line 1: Line 1:
{{task|Date and time}}
{{task|Date and time}}

{{task heading}}

A particular activity of bats occurs at these times of the day:
A particular activity of bats occurs at these times of the day:
:<tt>23:00:17</tt>, <tt>23:40:20</tt>, <tt>00:12:45</tt>, <tt>00:17:19</tt>
:<tt>23:00:17</tt>, <tt>23:40:20</tt>, <tt>00:12:45</tt>, <tt>00:17:19</tt>
Line 9: Line 12:
compute and show the average time of the nocturnal activity
compute and show the average time of the nocturnal activity
to an accuracy of one second of time.
to an accuracy of one second of time.

{{task heading|See also}}

{{Related tasks/Statistical measures}}

<hr>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==

Revision as of 14:48, 21 August 2016

Task
Averages/Mean time of day
You are encouraged to solve this task according to the task description, using any language you may know.

A particular activity of bats occurs at these times of the day:

23:00:17, 23:40:20, 00:12:45, 00:17:19

Using the idea that there are twenty-four hours in a day, which is analogous to there being 360 degrees in a circle, map times of day to and from angles; and using the ideas of Averages/Mean angle compute and show the average time of the nocturnal activity to an accuracy of one second of time.

See also

AutoHotkey

Works with: AutoHotkey 1.1

<lang AutoHotkey>MsgBox, % "The mean time is: " MeanTime(["23:00:17", "23:40:20", "00:12:45", "00:17:19"])

MeanTime(t, x=0, y=0) { static c := ATan(1) / 45 for k, v in t { n := StrSplit(v, ":") r := c * (n[1] * 3600 + n[2] * 60 + n[3]) / 240 x += Cos(r) y += Sin(r) } r := atan2(x, y) / c r := (r < 0 ? r + 360 : r) / 15 h := SubStr("00" Round(r // 1, 0), -1) s := SubStr("00" Round(Mod(m := Mod(r, 1) * 60, 1) * 60, 0), -1) m := SubStr("00" Round(m // 1, 0), -1) return, h ":" m ":" s }

atan2(x, y) {

  return dllcall("msvcrt\atan2", "Double",y, "Double",x, "CDECL Double")

}</lang>

Output:
The mean time is: 23:47:43

AWK

<lang AWK>#!/usr/bin/awk -f {

   c = atan2(0,-1)/(12*60*60);
   x=0.0; y=0.0;
   for (i=1; i<=NF; i++) {	
       split($i,a,":");

p = (a[1]*3600+a[2]*60+a[3])*c; x += sin(p); y += cos(p);

   }
   p = atan2(x,y)/c;	
   if (p<0) p += 24*60*60;
   print strftime("%T",p,1);

}</lang>

$ echo 23:00:17, 23:40:20, 00:12:45, 00:17:19 | awk -f mean_time_of_day.awk
23:47:43

BBC BASIC

<lang bbcbasic> nTimes% = 4

     DATA 23:00:17, 23:40:20, 00:12:45, 00:17:19
     
     DIM angles(nTimes%-1)
     FOR N% = 0 TO nTimes%-1
       READ tim$
       angles(N%) = FNtimetoangle(tim$)
     NEXT
     PRINT "Mean time is " FNangletotime(FNmeanangle(angles(), nTimes%))
     END
     
     DEF FNtimetoangle(t$)
     LOCAL A%, I%
     REPEAT
       A% = A% * 60 + VAL(t$)
       I% = INSTR(t$, ":")
       t$ = MID$(t$, I%+1)
     UNTIL I% = 0
     = A% / 240 - 180
     
     DEF FNangletotime(a)
     LOCAL A%, I%, t$
     A% = INT((a + 180) * 240 + 0.5)
     FOR I% = 1 TO 3
       t$ = RIGHT$("0" + STR$(A% MOD 60), 2) + ":" + t$
       A% DIV= 60
     NEXT
     = LEFT$(t$)
     
     DEF FNmeanangle(angles(), N%)
     LOCAL I%, addsin, addcos
     FOR I% = 0 TO N%-1
       addsin += SINRADangles(I%)
       addcos += COSRADangles(I%)
     NEXT
     = DEGFNatan2(addsin, addcos)
     
     DEF FNatan2(y,x) : ON ERROR LOCAL = SGN(y)*PI/2
     IF x>0 THEN = ATN(y/x) ELSE IF y>0 THEN = ATN(y/x)+PI ELSE = ATN(y/x)-PI</lang>
Output:
Mean time is 23:47:43

C

<lang c>/*29th August, 2012 Abhishek Ghosh*/

  1. include<stdlib.h>
  2. include<math.h>
  3. include<stdio.h>

typedef struct {

 int hour, minute, second;

} digitime;

double timeToDegrees (digitime time) {

 return (360 * time.hour / 24.0 + 360 * time.minute / (24 * 60.0) +
         360 * time.second / (24 * 3600.0));

}

digitime timeFromDegrees (double angle) {

 digitime d;
 double totalSeconds = 24 * 60 * 60 * angle / 360;
 d.second = (int) totalSeconds % 60;
 d.minute = ((int) totalSeconds % 3600 - d.second) / 60;
 d.hour = (int) totalSeconds / 3600;
 return d;

}

double meanAngle (double *angles, int size) {

 double y_part = 0, x_part = 0;
 int i;
 for (i = 0; i < size; i++)
   {
     x_part += cos (angles[i] * M_PI / 180);
     y_part += sin (angles[i] * M_PI / 180);
   }
 return atan2 (y_part / size, x_part / size) * 180 / M_PI;

}

int main () {

 digitime *set, meanTime;
 int inputs, i;
 double *angleSet, angleMean;
 printf ("Enter number of inputs : ");
 scanf ("%d", &inputs);
 set = malloc (inputs * sizeof (digitime));
 angleSet = malloc (inputs * sizeof (double));
 printf ("\n\nEnter the data separated by a space between each unit : ");
 for (i = 0; i < inputs; i++)
   {
     scanf ("%d:%d:%d", &set[i].hour, &set[i].minute, &set[i].second);
     angleSet[i] = timeToDegrees (set[i]);
   }
 meanTime = timeFromDegrees (360 + meanAngle (angleSet, inputs));
 printf ("\n\nThe mean time is : %d:%d:%d", meanTime.hour, meanTime.minute,
         meanTime.second);
 return 0;

}</lang>

Output:
Enter number of inputs : 4


Enter the data separated by a space between each unit : 23:00:17 23:40:20 00:12:45 00:17:19


The mean time is : 23:47:43



C#

<lang csharp>using System; using System.Collections.Generic; using System.Linq; using System.Text;

namespace RosettaCode {

   class Program
   {
       static void Main(string[] args)
       {
           Func<TimeSpan, double> TimeToDegrees = (time) => 
               360 * time.Hours / 24.0 +
               360 * time.Minutes / (24 * 60.0) +
               360 * time.Seconds / (24 * 3600.0);
           Func<List<double>, double> MeanAngle = (angles) =>
               {
                   double y_part = 0.0d, x_part = 0.0d;
                   int numItems = angles.Count;
                   for (int i = 0; i < numItems; i++)
                   {
                       x_part += Math.Cos(angles[i] * Math.PI / 180);
                       y_part += Math.Sin(angles[i] * Math.PI / 180);
                   }
                   return Math.Atan2(y_part / numItems, x_part / numItems) * 180 / Math.PI;
               };
           Func<double, TimeSpan> TimeFromDegrees = (angle) =>
                   new TimeSpan(
                       (int)(24 * 60 * 60 * angle / 360) / 3600, 
                       ((int)(24 * 60 * 60 * angle / 360) % 3600 - (int)(24 * 60 * 60 * angle / 360) % 60) / 60, 
                       (int)(24 * 60 * 60 * angle / 360) % 60);
           List<double> digitimes = new List<double>();
           TimeSpan digitime;
           string input;
           Console.WriteLine("Enter times, end with no input: ");
           do
           {
               input = Console.ReadLine();
               if (!(string.IsNullOrWhiteSpace(input)))
               {
                   if (TimeSpan.TryParse(input, out digitime))
                       digitimes.Add(TimeToDegrees(digitime));
                   else
                       Console.WriteLine("Seems this is wrong input: ignoring time");
               }
           } while (!string.IsNullOrWhiteSpace(input));
           if(digitimes.Count() > 0)
               Console.WriteLine("The mean time is : {0}", TimeFromDegrees(360 + MeanAngle(digitimes)));
       }
   }

} </lang>

Output:
Enter times, end with no input:
23:00:17
23:40:20
00:12:45
00:17:19

The mean time is : 23:47:43

D

Translation of: Python

<lang d>import std.stdio, std.range, std.algorithm, std.complex, std.math,

      std.format, std.conv;

double radians(in double d) pure nothrow @safe @nogc {

   return d * PI / 180;

}

double degrees(in double r) pure nothrow @safe @nogc {

   return r * 180 / PI;

}

double meanAngle(in double[] deg) pure nothrow @safe @nogc {

   return (deg.map!(d => fromPolar(1, d.radians)).sum / deg.length).arg.degrees;

}

string meanTime(in string[] times) pure @safe {

   auto t = times.map!(times => times.split(':').to!(int[3]));
   assert(t.all!(hms => 24.iota.canFind(hms[0]) &&
                        60.iota.canFind(hms[1]) &&
                        60.iota.canFind(hms[2])),
          "Invalid time");
   auto seconds = t.map!(hms => hms[2] + hms[1] * 60 + hms[0] * 3600);
   enum day = 24 * 60 * 60;
   const to_angles = seconds.map!(s => s * 360.0 / day).array;
   immutable mean_as_angle = to_angles.meanAngle;
   auto mean_seconds_fp = mean_as_angle * day / 360.0;
   if (mean_seconds_fp < 0)
       mean_seconds_fp += day;
   immutable mean_seconds = mean_seconds_fp.to!uint;
   immutable h = mean_seconds / 3600;
   immutable m = mean_seconds % 3600;
   return "%02d:%02d:%02d".format(h, m / 60, m % 60);

}

void main() @safe {

   ["23:00:17", "23:40:20", "00:12:45", "00:17:19"].meanTime.writeln;

}</lang>

Output:
23:47:43


EchoLisp

<lang scheme>

string hh
mm
ss to radians

(define (time->radian time)

   (define-values (h m s) (map string->number (string-split time ":")))
   (+  (* h (/ PI 12)) (* m (/ PI 12 60)) (* s (/ PI 12 3600))))
radians to string hh
mm;ss

(define (radian->time rad) (when (< rad 0) (+= rad (* 2 PI))) (define t (round (/ (* 12 3600 rad) PI))) (define h (quotient t 3600)) (define m (quotient (- t (* h 3600)) 60)) (define s (- t (* 3600 h) (* 60 m))) (string-join (map number->string (list h m s)) ":"))

(define (mean-time times) (radian->time (angle (for/sum ((t times)) (make-polar 1 (time->radian t))))))

(mean-time '{"23:00:17" "23:40:20" "00:12:45" "00:17:19"})

   →  "23:47:43"

</lang>

Erlang

<lang Erlang> -module( mean_time_of_day ). -export( [from_times/1, task/0] ).

from_times( Times ) -> Seconds = [seconds_from_time(X) || X <- Times], Degrees = [degrees_from_seconds(X) || X <- Seconds], Average = mean_angle:from_degrees( Degrees ), time_from_seconds( seconds_from_degrees(Average) ).

task() -> Times = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"], io:fwrite( "The mean time of ~p is: ~p~n", [Times, from_times(Times)] ).


degrees_from_seconds( Seconds ) when Seconds < (24 * 3600) -> (Seconds * 360) / (24 * 3600).

seconds_from_degrees( Degrees ) when Degrees < 0 -> seconds_from_degrees( Degrees + 360 ); seconds_from_degrees( Degrees ) when Degrees < 360 -> (Degrees * 24 * 3600) / 360.

seconds_from_time( Time ) -> {ok, [Hours, Minutes, Seconds], _Rest} = io_lib:fread( "~d:~d:~d", Time ), Hours * 3600 + Minutes * 60 + Seconds.

time_from_seconds( Seconds_float ) -> Seconds = erlang:round( Seconds_float ), Hours = Seconds div 3600, Minutes = (Seconds - (Hours * 3600)) div 60, Secs = Seconds - (Hours * 3600) - (Minutes * 60), lists:flatten( io_lib:format("~2.10.0B:~2.10.0B:~2.10.0B", [Hours, Minutes, Secs]) ). </lang>

Output:
17> mean_time_of_day:task().
The mean time of  ["23:00:17","23:40:20","00:12:45","00:17:19"] is: "23:47:43"


Euphoria

Works with: OpenEuphoria

<lang Euphoria> include std/console.e include std/math.e include std/mathcons.e include std/sequence.e include std/get.e

function T2D(sequence TimeSeq) return (360 * TimeSeq[1] / 24 + 360 * TimeSeq[2] / (24 * 60) + 360 * TimeSeq[3] / (24 * 3600)) end function

function D2T(atom angle) sequence TimeSeq = {0,0,0} atom seconds = 24 * 60 * 60 * angle / 360

TimeSeq[3] = mod(seconds,60) TimeSeq[2] = (mod(seconds,3600) - TimeSeq[3]) / 60 TimeSeq[1] = seconds / 3600

return TimeSeq end function

function MeanAngle(sequence angles) atom x = 0, y = 0 integer l = length(angles)

for i = 1 to length(angles) do x += cos(angles[i] * PI / 180) y += sin(angles[i] * PI / 180) end for

return atan2(y / l, x / l) * 180 / PI end function

sequence TimeEntry, TimeList = {}, TimeSeq

puts(1,"Enter times. Enter with no input to end\n") while 1 do

TimeEntry = prompt_string("")
if equal(TimeEntry,"") then  -- no more entries
	for i = 1 to length(TimeList) do
		TimeList[i] = split(TimeList[i],":") -- split the times into sequences 
		for j = 1 to 3 do
			TimeList[i][j] = defaulted_value(TimeList[i][j],0) -- convert to numerical values
		end for
	end for
	exit
end if
TimeList = append(TimeList,TimeEntry)

end while

sequence AngleList = repeat({},length(TimeList))

for i = 1 to length(AngleList) do AngleList[i] = T2D(TimeList[i]) end for

sequence MeanTime = D2T(360+MeanAngle(AngleList))

printf(1,"\nMean Time: %d:%d:%d\n",MeanTime)


if getc(0) then end if </lang>

Output:
Enter Times.  Enter with no input to end.
23:00:17
23:40:20
00:12:45
00:17:19

Mean Time: 23:47:43

F#

<lang fsharp>open System open System.Numerics

let deg2rad d = d * Math.PI / 180. let rad2deg r = r * 180. / Math.PI let makeComplex = fun r -> Complex.FromPolarCoordinates(1., r) // 1 msec = 10000 ticks let time2deg = TimeSpan.Parse >> (fun ts -> ts.Ticks) >> (float) >> (*) (10e-9/24.) let deg2time = (*) (24. * 10e7) >> (int64) >> TimeSpan

[<EntryPoint>] let main argv =

   let msg = "Average time for [" + (String.Join("; ",argv)) + "] is"
   argv
   |> Seq.map (time2deg >> deg2rad >> makeComplex)
   |> Seq.fold (fun x y -> Complex.Add(x,y)) Complex.Zero
   |> fun c -> c.Phase |> rad2deg
   |> fun d -> if d < 0. then d + 360. else d
   |> deg2time |> fun t -> t.ToString(@"hh\:mm\:ss")
   |> printfn "%s: %s" msg 
   0</lang>
Output:
>RosettaCode 23:00:17 23:40:20 00:12:45 00:17:19
Average time for [23:00:17; 23:40:20; 00:12:45; 00:17:19] is: 23:47:43

Fortran

Works with: gfortran 5.1.0

<lang fortran> program mean_time_of_day

 implicit none
 integer(kind=4), parameter :: dp = kind(0.0d0)
 type time_t
   integer(kind=4) :: hours, minutes, seconds
 end type
 character(len=8), dimension(4), parameter :: times = &
   (/ '23:00:17', '23:40:20', '00:12:45', '00:17:19' /)
 real(kind=dp), dimension(size(times)) :: angles
 real(kind=dp) :: mean
 angles = time_to_angle(str_to_time(times))
 mean = mean_angle(angles)
 if (mean < 0) mean = 360 + mean
 write(*, fmt='(I2.2, :, I2.2, :, I2.2)') angle_to_time(mean)

contains

 real(kind=dp) function mean_angle(angles)
   real(kind=dp), dimension(:), intent (in) :: angles
   real(kind=dp) :: x, y
   x = sum(sin(radians(angles)))/size(angles)
   y = sum(cos(radians(angles)))/size(angles)
   mean_angle = degrees(atan2(x, y))
 end function
 elemental real(kind=dp) function radians(angle)
   real(kind=dp), intent (in) :: angle
   real(kind=dp), parameter :: pi = 4d0*atan(1d0)
   radians = angle/180*pi
 end function
 elemental real(kind=dp) function degrees(angle)
   real(kind=dp), intent (in) :: angle
   real(kind=dp), parameter :: pi = 4d0*atan(1d0)
   degrees = 180*angle/pi
 end function
 elemental type(time_t) function str_to_time(str)
   character(len=*), intent (in) :: str
   ! Assuming time in format hh:mm:ss
   read(str, fmt='(I2, 1X, I2, 1X, I2)') str_to_time
 end function
 elemental real(kind=dp) function time_to_angle(time) result (res)
   type(time_t), intent (in) :: time
   real(kind=dp) :: seconds
   real(kind=dp), parameter :: seconds_in_day = 24*60*60
   seconds = time%seconds + 60*time%minutes + 60*60*time%hours
   res = 360*seconds/seconds_in_day
 end function
 elemental type(time_t) function angle_to_time(angle)
   real(kind=dp), intent (in) :: angle
   real(kind=dp) :: seconds
   real(kind=dp), parameter :: seconds_in_day = 24*60*60
   seconds = seconds_in_day*angle/360d0
   angle_to_time%hours = int(seconds/60d0/60d0)
   seconds = mod(seconds, 60d0*60d0)
   angle_to_time%minutes = int(seconds/60d0)
   angle_to_time%seconds = mod(seconds, 60d0)
 end function

end program </lang>

Output:
23:47:43

Go

<lang go>package main

import (

   "errors"
   "fmt"
   "log"
   "math"
   "time"

)

var inputs = []string{"23:00:17", "23:40:20", "00:12:45", "00:17:19"}

func main() {

   tList := make([]time.Time, len(inputs))
   const clockFmt = "15:04:05"
   var err error
   for i, s := range inputs {
       tList[i], err = time.Parse(clockFmt, s)
       if err != nil {
           log.Fatal(err)
       }
   }
   mean, err := meanTime(tList)
   if err != nil {
       log.Fatal(err)
   }
   fmt.Println(mean.Format(clockFmt))

}

func meanTime(times []time.Time) (mean time.Time, err error) {

   if len(times) == 0 {
       err = errors.New("meanTime: no times specified")
       return
   }
   var ssum, csum float64
   for _, t := range times {
       h, m, s := t.Clock()
       n := t.Nanosecond()
       fSec := (float64((h*60+m)*60+s) + float64(n)*1e-9)
       sin, cos := math.Sincos(fSec * math.Pi / (12 * 60 * 60))
       ssum += sin
       csum += cos
   }
   if ssum == 0 && csum == 0 {
       err = errors.New("meanTime: mean undefined")
       return
   }
   _, dayFrac := math.Modf(1 + math.Atan2(ssum, csum)/(2*math.Pi))
   return mean.Add(time.Duration(dayFrac * 24 * float64(time.Hour))), nil

}</lang>

Output:
23:47:43

Groovy

Solution: <lang groovy>import static java.lang.Math.*

final format = 'HH:mm:ss', clock = PI / 12, millisPerHr = 3600*1000 final tzOffset = new Date(0).timezoneOffset / 60 def parseTime = { time -> (Date.parse(format, time).time / millisPerHr) - tzOffset } def formatTime = { time -> new Date((time + tzOffset) * millisPerHr as int).format(format) } def mean = { list, closure -> list.sum(closure)/list.size() } def meanTime = { ... timeStrings ->

   def times = timeStrings.collect(parseTime)
   formatTime(atan2( mean(times) { sin(it * clock) }, mean(times) { cos(it * clock) }) / clock)

}</lang>

Test: <lang groovy>println (meanTime("23:00:17", "23:40:20", "00:12:45", "00:17:19"))</lang>

Output:
23:47:43

Haskell

<lang haskell>import Data.Complex (cis, phase) import Data.List.Split (splitOn) import Text.Printf (printf)

timeToRadians :: String -> Float timeToRadians time =

       let hours:minutes:seconds:_ = splitOn ":" time
           s = fromIntegral (read seconds :: Int)
           m = fromIntegral (read minutes :: Int)
           h = fromIntegral (read hours :: Int)
       in  (2*pi)*(h+ (m + s/60.0 )/60.0 )/24.0
  

radiansToTime :: Float -> String radiansToTime r =

       let tau = pi*2
           (_,fDay) = properFraction (r / tau) :: (Int, Float)
           fDayPositive = if fDay < 0 then 1.0+fDay else fDay 
           (hours, fHours) = properFraction $ 24.0 * fDayPositive
           (minutes, fMinutes) = properFraction $ 60.0 * fHours
           seconds = 60.0 * fMinutes
       in printf "%0d" (hours::Int) ++ ":" ++ printf "%0d" (minutes::Int) ++ ":" ++ printf "%0.0f" (seconds::Float)

meanAngle :: [Float] -> Float meanAngle = phase . sum . map cis

main :: IO () main = putStrLn $ radiansToTime $ meanAngle $ map timeToRadians ["23:00:17", "23:40:20", "00:12:45", "00:17:19"] </lang>

Output:
23:47:43

Icon and Unicon

<lang>procedure main(A)

   every put(B := [], ct2a(!A))
   write(ca2t(meanAngle(B)))

end

procedure ct2a(t)

   t ? {s := ((1(move(2),move(1))*60 + 1(move(2),move(1)))*60 + move(2))}
   return (360.0/86400.0) * s

end

procedure ca2t(a)

   while a < 0 do a +:= 360.0
   t := integer((86400.0/360.0)*a + 0.5)
   s := left(1(.t % 60, t /:= 60),2,"0")
   s := left(1(.t % 60, t /:= 60),2,"0")||":"||s
   s := left(t,2,"0")||":"||s
   return s

end

procedure meanAngle(A)

   every (sumSines := 0.0) +:= sin(dtor(!A))
   every (sumCosines := 0.0) +:= cos(dtor(!A))
   return rtod(atan(sumSines/*A,sumCosines/*A))

end</lang>

Sample run:

->amtod 23:00:17 23:40:20 00:12:45 00:17:19
23:47:43
->

J

use avgAngleR from Averages/Mean angle#J <lang J>require 'types/datetime' parseTimes=: ([: _&".;._2 ,&':');._2 secsFromTime=: 24 60 60 #. ] NB. convert from time to seconds rft=: 2r86400p1 * secsFromTime NB. convert from time to radians meanTime=: 'hh:mm:ss' fmtTime [: secsFromTime [: avgAngleR&.rft parseTimes</lang>

Example Use:

<lang J> meanTime '23:00:17 23:40:20 00:12:45 00:17:19 ' 23:47:43</lang>

jq

Works with: jq version 1.4

The "mean time" of two times that differ by 12 hours (e.g. ["00:00:00", "12:00:00"]) is not very well-defined, and is accordingly computed as null here. <lang jq># input: array of "h:m:s" def mean_time_of_day:

 def pi: 4 * (1|atan);
 def to_radians:   pi * . /(12*60*60);
 def from_radians: (. * 12*60*60) / pi;
 def secs2time:  # produce "hh:mm:ss" string
   def pad: tostring | (2 - length) * "0" + .;
   "\(./60/60 % 24 | pad):\(./60 % 60 | pad):\(. % 60 | pad)";
 def round:
   if . < 0 then -1 * ((- .) | round) | if . == -0 then 0 else . end
   else floor as $x
   | if (. - $x) < 0.5 then $x else $x+1 end
   end;
 map( split(":")
      | map(tonumber)
      | (.[0]*3600 + .[1]*60 + .[2])
      | to_radians )
  | (map(sin) | add) as $y
  | (map(cos) | add) as $x
  | if $x == 0 then (if $y > 3e-14 then pi/2 elif $y < -3e-14 then -(pi/2) else null end)
    else ($y / $x) | atan
    end
  | if . == null then null
    else from_radians
    | if (.<0) then . + (24*60*60) else . end
    | round
    | secs2time
    end ;</lang>

Examples <lang jq>["0:0:0", "12:0:0" ], ["0:0:0", "24:0:0" ], ["1:0:0", "1:0:0" ], ["20:0:0", "4:0:0" ], ["20:0:0", "4:0:2" ], ["23:0:0", "23:0:0" ], ["23:00:17", "23:40:20", "00:12:45", "00:17:19"] | mean_time_of_day</lang>

Output:

<lang sh>$ jq -r -n -f Mean_time_of_day.jq null 00:00:00 01:00:00 00:00:00 00:00:01 23:00:00 23:47:43</lang>

Liberty BASIC

<lang lb> global pi pi = acs(-1)

Print "Average of:" for i = 1 to 4

   read t$ 
   print t$
   a=time2angle(t$)
   ss=ss+sin(a)
   sc=sc+cos(a)

next a=atan2(ss,sc) if a<0 then a=a+2*pi print "is ";angle2time$(a)

end data "23:00:17", "23:40:20", "00:12:45", "00:17:19"

function nn$(n)

   nn$=right$("0";n, 2)

end function

function angle2time$(a)

   a=int(a/2/pi*24*60*60)
   ss=a mod 60
   a=int(a/60)
   mm=a mod 60
   hh=int(a/60)
   angle2time$=nn$(hh);":";nn$(mm);":";nn$(ss)

end function

function time2angle(time$)

   hh=val(word$(time$,1,":"))
   mm=val(word$(time$,2,":"))
   ss=val(word$(time$,3,":"))
   time2angle=2*pi*(60*(60*hh+mm)+ss)/24/60/60

end function

function atan2(y, x)

   On Error GoTo [DivZero]      'If y is 0 catch division by zero error
       atan2 = (2 * (atn((sqr((x * x) + (y * y)) - x)/ y)))
       exit function
   [DivZero]
       atan2 = (y=0)*(x<0)*pi

End Function </lang>

Output:
Average of:
23:00:17
23:40:20
00:12:45
00:17:19
is 23:47:43 

Mathematica / Wolfram Language

<lang mathematica>meanTime[list_] :=

 StringJoin@
  Riffle[ToString /@ 
      Floor@{Mod[24 #, 24], Mod[24*60 #, 60], Mod[24*60*60 #, 60]} &[
    Arg[Mean[
       Exp[FromDigits[ToExpression@StringSplit[#, ":"], 60] & /@ 
           list/(24*60*60) 2 Pi I]]]/(2 Pi)], ":"];

meanTime[{"23:00:17", "23:40:20", "00:12:45", "00:17:19"}]</lang>

Output:
23:47:43

MATLAB / Octave

<lang MATLAB>function t = mean_time_of_day(t)

   c = pi/(12*60*60);
   for k=1:length(t)

a = sscanf(t{k},'%d:%d:%d'); phi(k) = (a(1)*3600+a(2)*60+a(3));

   end;
   d = angle(mean(exp(i*phi*c)))/(2*pi); % days 
   if (d<0) d += 1;
   t = datestr(d,"HH:MM:SS");

end; </lang>

mean_time_of_day({'23:00:17', '23:40:20', '00:12:45', '00:17:19'})
ans = 23:47:43

Nim

<lang nim>import math, complex, strutils

proc rect(r, phi): Complex = (r * cos(phi), sin(phi)) proc phase(c): float = arctan2(c.im, c.re)

proc radians(x): float = (x * Pi) / 180.0 proc degrees(x): float = (x * 180.0) / Pi

proc meanAngle(deg): float =

 var c: Complex
 for d in deg:
   c += rect(1.0, radians(d))
 degrees(phase(c / float(deg.len)))

proc meanTime(times): string =

 const day = 24 * 60 * 60
 let
   angles = times.map(proc(time: string): float =
     let t = time.split(":")
     (t[2].parseInt + t[1].parseInt * 60 + t[0].parseInt * 3600) * 360 / day)
   ms = (angles.meanAngle * day / 360 + day) mod day
   (h,m,s) = (ms.int div 3600, (ms.int mod 3600) div 60, ms.int mod 60)
 align($h, 2, '0') &":"& align($m, 2, '0') &":"& align($s, 2, '0')

echo meanTime(["23:00:17", "23:40:20", "00:12:45", "00:17:19"])</lang>

Output:
23:47:43

Oberon-2

Works with: oo2c

<lang oberon2> MODULE AvgTimeOfDay; IMPORT

 M := LRealMath,
 T := NPCT:Tools,
 Out := NPCT:Console;

CONST

 secsDay = 86400;
 secsHour = 3600;
 secsMin = 60;
 toRads = M.pi / 180;

VAR

 h,m,s: LONGINT;
 data: ARRAY 4 OF LONGREAL;

PROCEDURE TimeToDeg(time: STRING): LONGREAL; VAR

 parts: ARRAY 3 OF STRING;
 h,m,s: LONGREAL;

BEGIN

 T.Split(time,':',parts);
 h := T.StrToInt(parts[0]);
 m := T.StrToInt(parts[1]);
 s := T.StrToInt(parts[2]);
 RETURN (h * secsHour + m * secsMin + s) * 360 / secsDay;

END TimeToDeg;

PROCEDURE DegToTime(d: LONGREAL; VAR h,m,s: LONGINT); VAR

 ds: LONGREAL;
 PROCEDURE Mod(x,y: LONGREAL): LONGREAL;
 VAR
   c: LONGREAL;
 BEGIN
   c := ENTIER(x / y);
   RETURN x - c * y
 END Mod;

BEGIN

 ds :=  Mod(d,360.0) * secsDay / 360.0;
 h := ENTIER(ds / secsHour);
 m := ENTIER(Mod(ds,secsHour) / secsMin);
 s := ENTIER(Mod(ds,secsMin));

END DegToTime;

PROCEDURE Mean(g: ARRAY OF LONGREAL): LONGREAL; VAR

 i,l: LONGINT;
 sumSin, sumCos: LONGREAL;

BEGIN

 i := 0;l := LEN(g);sumSin := 0.0;sumCos := 0.0;
 WHILE i < l  DO
   sumSin := sumSin + M.sin(g[i] * toRads);
   sumCos := sumCos + M.cos(g[i] * toRads);  
   INC(i)
 END;
 RETURN M.arctan2(sumSin / l,sumCos / l) * 180 / M.pi;

END Mean;

BEGIN

 data[0] := TimeToDeg("23:00:17");
 data[1] := TimeToDeg("23:40:20");
 data[2] := TimeToDeg("00:12:45");
 data[3] := TimeToDeg("00:17:19");
 DegToTime(Mean(data),h,m,s);
 Out.String(":> ");Out.Int(h,0);Out.Char(':');Out.Int(m,0);Out.Char(':');Out.Int(s,0);Out.Ln

END AvgTimeOfDay. </lang>

Output:
:> 23:47:43

OCaml

<lang ocaml>let pi_twice = 2.0 *. 3.14159_26535_89793_23846_2643 let day = float (24 * 60 * 60)

let rad_of_time t =

 t *. pi_twice /. day

let time_of_rad r =

 r *. day /. pi_twice

let mean_angle angles =

 let sum_sin = List.fold_left (fun sum a -> sum +. sin a) 0.0 angles
 and sum_cos = List.fold_left (fun sum a -> sum +. cos a) 0.0 angles in
 atan2 sum_sin sum_cos

let mean_time times =

 let angles = List.map rad_of_time times in
 let t = time_of_rad (mean_angle angles) in
 if t < 0.0 then t +. day else t

let parse_time t =

 Scanf.sscanf t "%d:%d:%d" (fun h m s -> float (s + m * 60 + h * 3600))

let round x = int_of_float (floor (x +. 0.5))

let string_of_time t =

 let t = round t in
 let h = t / 3600 in
 let rem = t mod 3600 in
 let m = rem / 60 in
 let s = rem mod 60 in
 Printf.sprintf "%d:%d:%d" h m s

let () =

 let times = ["23:00:17"; "23:40:20"; "00:12:45"; "00:17:19"] in
 Printf.printf "The mean time of [%s] is: %s\n"
   (String.concat "; " times)
   (string_of_time (mean_time (List.map parse_time times)))</lang>
Output:
The mean time of [23:00:17; 23:40:20; 00:12:45; 00:17:19] is: 23:47:43

ooRexx

<lang oorexx>/* REXX ---------------------------------------------------------------

  • 25.06.2014 Walter Pachl
  • --------------------------------------------------------------------*/

times='23:00:17 23:40:20 00:12:45 00:17:19' sum=0 day=86400 x=0 y=0 Do i=1 To words(times) /* loop over times */

 time.i=word(times,i)                 /* pick a time                */
 alpha.i=t2a(time.i)                  /* convert to angle (degrees) */
 /* Say time.i format(alpha.i,6,9) */
 x=x+rxcalcsin(alpha.i)               /* accumulate sines           */
 y=y+rxcalccos(alpha.i)               /* accumulate cosines         */
 End

ww=rxcalcarctan(x/y) /* compute average angle */ ss=ww*86400/360 /* convert to seconds */ If ss<0 Then ss=ss+day /* avoid negative value */ m=ss%60 /* split into hh mm ss */ s=ss-m*60 h=m%60 m=m-h*60 Say f2(h)':'f2(m)':'f2(s) /* show the mean time */ Exit

t2a: Procedure Expose day /* convert time to angle */

 Parse Arg hh ':' mm ':' ss
 sec=(hh*60+mm)*60+ss
 If sec>(day/2) Then
   sec=sec-day
 a=360*sec/day
 Return a

f2: return right(format(arg(1),2,0),2,0)

requires rxmath library</lang>
Output:
23:47:43

PARI/GP

<lang parigp>meanAngle(v)=atan(sum(i=1,#v,sin(v[i]))/sum(i=1,#v,cos(v[i])))%(2*Pi) meanTime(v)=my(x=meanAngle(2*Pi*apply(u->u[1]/24+u[2]/1440+u[3]/86400, v))*12/Pi); [x\1, 60*(x-=x\1)\1, round(60*(60*x-60*x\1))] meanTime([[23,0,17], [23,40,20], [0,12,45], [0,17,19]])</lang>

Output:
[23, 47, 43]

Perl 6

Works with: Rakudo version 2015.12

<lang perl6>sub tod2rad($_) { [+](.comb(/\d+/) Z* 3600,60,1) * tau / 86400 }

sub rad2tod ($r) {

   my $x = $r * 86400 / tau;
   (($x xx 3 Z/ 3600,60,1) Z% 24,60,60).fmt('%02d',':');

}

sub phase ($c) { $c.polar[1] }

sub mean-time (@t) { rad2tod phase [+] map { cis tod2rad $_ }, @t }

my @times = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"];

say "{ mean-time(@times) } is the mean time of @times[]";</lang>

Output:
23:47:43 is the mean time of 23:00:17 23:40:20 00:12:45 00:17:19

Phix

<lang Phix>function atan2(atom y, atom x)

   return 2*arctan((sqrt(power(x,2)+power(y,2))-x)/y)

end function

function MeanAngle(sequence angles) atom x=0, y=0, ai_rad integer l=length(angles)

   for i=1 to l do
       ai_rad = angles[i]*PI/180
       x += cos(ai_rad)
       y += sin(ai_rad)
   end for
   if abs(x)<1e-16 then return "not meaningful" end if
   return atan2(y,x)*180/PI

end function

function toSecAngle(integer hours, integer minutes, integer seconds)

   return ((hours*60+minutes)*60+seconds)/(24*60*60)*360

end function

constant Times = {toSecAngle(23,00,17),

                 toSecAngle(23,40,20),
                 toSecAngle(00,12,45),
                 toSecAngle(00,17,19)}

function toHMS(object s)

   if not string(s) then
       if s<0 then s+=360 end if
       s = 24*60*60*s/360
       s = sprintf("%02d:%02d:%02d",{floor(s/3600),floor(remainder(s,3600)/60),remainder(s,60)})
   end if
   return s

end function

printf(1,"Mean Time is %s\n",{toHMS(MeanAngle(Times))}) {} = wait_key()</lang>

Output:
Mean Time is 23:47:43

PHP

<lang PHP> <?php function time2ang($tim) {

       if (!is_string($tim)) return $tim;
       $parts = explode(':',$tim);
       if (count($parts)!=3) return $tim;
       $sec = ($parts[0]*3600)+($parts[1]*60)+$parts[2];
       $ang = 360.0 * ($sec/86400.0);
       return $ang;

} function ang2time($ang) {

       if (!is_numeric($ang)) return $ang;
       $sec = 86400.0 * $ang / 360.0;
       $parts = array(floor($sec/3600),floor(($sec % 3600)/60),$sec % 60);
       $tim = sprintf('%02d:%02d:%02d',$parts[0],$parts[1],$parts[2]);
       return $tim;

} function meanang($ang) {

       if (!is_array($ang)) return $ang;
       $sins = 0.0;
       $coss = 0.0;
       foreach($ang as $a) {
               $sins += sin(deg2rad($a));
               $coss += cos(deg2rad($a));
       }
       $avgsin = $sins / (0.0+count($ang));
       $avgcos = $coss / (0.0+count($ang));
       $avgang = rad2deg(atan2($avgsin,$avgcos));
       while ($avgang < 0.0) $avgang += 360.0;
       return $avgang;

} $bats = array('23:00:17','23:40:20','00:12:45','00:17:19'); $angs = array(); foreach ($bats as $t) $angs[] = time2ang($t); $ma = meanang($angs); $result = ang2time($ma); print "The mean time of day is $result (angle $ma).\n"; ?> </lang>

Output:
The mean time of day is 23:47:43 (angle 356.9306730355).

PicoLisp

<lang PicoLisp>(load "@lib/math.l")

(de meanTime (Lst)

  (let Tim
     (*/
        (atan2
           (sum '((S) (sin (*/ ($tim S) pi 43200))) Lst)
           (sum '((S) (cos (*/ ($tim S) pi 43200))) Lst) )
        43200 pi )
     (tim$ (% (+ Tim 86400) 86400) T) ) )</lang>
Test:

<lang PicoLisp>: (meanTime '("23:00:17" "23:40:20" "00:12:45" "00:17:19")) -> "23:47:43"</lang>

PL/I

<lang pli>*process source attributes xref;

avt: Proc options(main);
/*--------------------------------------------------------------------
* 25.06.2014 Walter Pachl taken from REXX
*-------------------------------------------------------------------*/
Dcl (addr,hbound,sin,cos,atan) Builtin;
Dcl sysprint Print;
Dcl times(4) Char(8) Init('23:00:17','23:40:20','00:12:45','00:17:19');
Dcl time Char(8);
Dcl (alpha,x,y,ss,ww) Dec Float(18) Init(0);
Dcl day Bin Fixed(31) Init(86400);
Dcl pi Dec Float(18) Init(3.14159265358979323846);
Dcl (i,h,m,s) bin Fixed(31) Init(0);
Do i=1 To hbound(times);              /* loop over times            */
 time=times(i);                       /* pick a time                */
 alpha=t2a(time);                     /* convert to angle (radians) */
 x=x+sin(alpha);                      /* accumulate sines           */
 y=y+cos(alpha);                      /* accumulate cosines         */
 End;
ww=atan(x/y);                         /* compute average angle      */
ss=ww*day/(2*pi);                     /* convert to seconds         */
If ss<0 Then ss=ss+day;               /* avoid negative value       */
m=ss/60;                              /* split into hh mm ss        */
s=ss-m*60;
h=m/60;
m=m-h*60;
Put Edit(h,':',m,':',s)(Skip,3(p'99',a));
t2a: Procedure(t) Returns(Bin Float(18)); /* convert time to angle  */
Dcl t Char(8);
Dcl 1 tt Based(addr(t)),
     2 hh Pic'99',
     2 * Char(1),
     2 mm Pic'99',
     2 * Char(1),
     2 ss Pic'99';
Dcl sec Bin Fixed(31);
Dcl a   Bin Float(18);
sec=(hh*60+mm)*60+ss;
If sec>(day/2) Then
  sec=sec-day;
a=2*pi*sec/day;
Return (a);
End;
End;</lang>
Output:
23:47:43

Python

<lang python>from cmath import rect, phase from math import radians, degrees


def mean_angle(deg):

   return degrees(phase(sum(rect(1, radians(d)) for d in deg)/len(deg)))

def mean_time(times):

   t = (time.split(':') for time in times)
   seconds = ((float(s) + int(m) * 60 + int(h) * 3600) 
              for h, m, s in t)
   day = 24 * 60 * 60
   to_angles = [s * 360. / day for s in seconds]
   mean_as_angle = mean_angle(to_angles)
   mean_seconds = mean_as_angle * day / 360.
   if mean_seconds < 0:
       mean_seconds += day
   h, m = divmod(mean_seconds, 3600)
   m, s = divmod(m, 60)
   return '%02i:%02i:%02i' % (h, m, s)


if __name__ == '__main__':

   print( mean_time(["23:00:17", "23:40:20", "00:12:45", "00:17:19"]) )</lang>
Output:
23:47:43

Racket

<lang racket>

  1. lang racket

(define (mean-angle/radians as)

 (define n (length as))
 (atan (* (/ 1 n) (for/sum ([αj as]) (sin αj)))
       (* (/ 1 n) (for/sum ([αj as]) (cos αj)))))

(define (mean-time times)

 (define secs/day (* 60 60 24))
 (define (time->deg time)
   (/ (for/fold ([sum 0]) ([t (map string->number (string-split time ":"))])
        (+ (* 60 sum) t))
      secs/day 1/360 (/ 180 pi)))
 (define secs
   (modulo (inexact->exact (round (* (mean-angle/radians (map time->deg times))
                                     (/ 180 pi) 1/360 secs/day)))
           secs/day))
 (let loop ([s secs] [ts '()])
   (if (zero? s) (string-join ts ":")
       (let-values ([(q r) (quotient/remainder s 60)])
         (loop q (cons (~r r #:min-width 2 #:pad-string "0") ts))))))

(mean-time '("23:00:17" "23:40:20" "00:12:45" "00:17:19")) </lang>

Output:
"23:47:43"


REXX

<lang rexx>/* REXX ---------------------------------------------------------------

  • 25.06.2014 Walter Pachl
  • taken from ooRexx using my very aged sin/cos/artan functions
  • --------------------------------------------------------------------*/

times='23:00:17 23:40:20 00:12:45 00:17:19' sum=0 day=86400 pi=3.14159265358979323846264 x=0 y=0 Do i=1 To words(times) /* loop over times */

 time.i=word(times,i)                 /* pick a time                */
 alpha.i=t2a(time.i)                  /* convert to angle (radians) */
 /* Say time.i format(alpha.i,6,9) */
 x=x+sin(alpha.i)                     /* accumulate sines           */
 y=y+cos(alpha.i)                     /* accumulate cosines         */
 End

ww=arctan(x/y) /* compute average angle */ ss=ww*86400/(2*pi) /* convert to seconds */ If ss<0 Then ss=ss+day /* avoid negative value */ m=ss%60 /* split into hh mm ss */ s=ss-m*60 h=m%60 m=m-h*60 Say f2(h)':'f2(m)':'f2(s) /* show the mean time */ Exit

t2a: Procedure Expose day pi /* convert time to angle */

 Parse Arg hh ':' mm ':' ss
 sec=(hh*60+mm)*60+ss
 If sec>(day/2) Then
   sec=sec-day
 a=2*pi*sec/day
 Return a

f2: return right(format(arg(1),2,0),2,0)


sin: Procedure Expose pi

 Parse Arg x
 prec=digits()
 Numeric Digits (2*prec)
 Do While x>pi
   x=x-pi
   End
 Do While x<-pi
   x=x+pi
   End
 o=x
 u=1
 r=x
 Do i=3 By 2
   ra=r
   o=-o*x*x
   u=u*i*(i-1)
   r=r+(o/u)
   If r=ra Then Leave
   End
 Numeric Digits prec
 Return r+0

cos: Procedure Expose pi

 Parse Arg x
 prec=digits()
 Numeric Digits (2*prec)
 Numeric Fuzz 3
 o=1
 u=1
 r=1
 Do i=1 By 2
   ra=r
   o=-o*x*x
   u=u*i*(i+1)
   r=r+(o/u)
   If r=ra Then Leave
   End
 Numeric Digits prec
 Return r+0

arctan: Procedure

 Parse Arg x
 prec=digits()
 Numeric Digits (2*prec)
 Numeric Fuzz 3
 o=x
 u=1
 r=x
 k=0
 Do i=3 By 2
   ra=r
   o=-o*x*x
   r=r+(o/i)
   If r=ra Then
     Leave
   k=k+1
   If k//1000=0 Then
     Say i left(r,40) format(abs(o/i),15,5)
   End
 Numeric Digits (prec)
 Return r+0</lang>
Output:
23:47:43

Ruby

Using the methods at [angle]

<lang ruby>def time2deg(t)

 raise "invalid time" unless m = t.match(/^(\d\d):(\d\d):(\d\d)$/)
 hh,mm,ss = m[1..3].map {|e| e.to_i}
 raise "invalid time" unless (0..23).include? hh and
                             (0..59).include? mm and
                             (0..59).include? ss
 (hh*3600 + mm*60 + ss) * 360 / 86400.0

end

def deg2time(d)

 sec = (d % 360) * 86400 / 360.0
 "%02d:%02d:%02d" % [sec/3600, (sec%3600)/60, sec%60]

end

def mean_time(times)

 deg2time(mean_angle(times.map {|t| time2deg t}))

end

puts mean_time ["23:00:17", "23:40:20", "00:12:45", "00:17:19"]</lang>

Output:
23:47:43

Run BASIC

<lang runbasic>global pi pi = acs(-1)

Print "Average of:" for i = 1 to 4

   read t$ 
   print t$
   a  = time2angle(t$)
   ss = ss+sin(a)
   sc = sc+cos(a)

next a = atan2(ss,sc) if a < 0 then a = a + 2 * pi print "is ";angle2time$(a) end data "23:00:17", "23:40:20", "00:12:45", "00:17:19"

function nn$(n)

   nn$ = right$("0";n, 2)

end function

function angle2time$(a)

   a  = int(a / 2 / pi * 24 * 60 * 60)
   ss = a mod 60
   a  = int(a / 60)
   mm=a mod 60
   hh=int(a/60)
   angle2time$=nn$(hh);":";nn$(mm);":";nn$(ss)

end function

function time2angle(time$)

   hh=val(word$(time$,1,":"))
   mm=val(word$(time$,2,":"))
   ss=val(word$(time$,3,":"))
   time2angle=2*pi*(60*(60*hh+mm)+ss)/24/60/60

end function

function atan2(y, x)

      if y <> 0 then
       atan2 = (2 * (atn((sqr((x * x) + (y * y)) - x)/ y)))
       else
       atan2 = (y=0)*(x<0)*pi
      end if

End Function</lang>

Scala

<lang Scala>import java.time.LocalTime

import scala.compat.Platform

trait MeanAnglesComputation {

 import scala.math.{Pi, atan2, cos, sin}
 def meanAngle(angles: List[Double], convFactor: Double = 180.0 / Pi) = {
   val sums = angles.foldLeft((.0, .0))((r, c) => {
     val rads = c / convFactor
     (r._1 + sin(rads), r._2 + cos(rads))
   })
   val result = atan2(sums._1, sums._2)
   (result + (if (result.signum == -1) 2 * Pi else 0.0)) * convFactor
 }

}

object MeanBatTime extends App with MeanAnglesComputation {

 val dayInSeconds = 60 * 60 * 24
 def times = batTimes.map(t => afterMidnight(t).toDouble)
 def afterMidnight(twentyFourHourTime: String) = {
   val t = LocalTime.parse(twentyFourHourTime)
   (if (t.isBefore(LocalTime.NOON)) dayInSeconds else 0) + LocalTime.parse(twentyFourHourTime).toSecondOfDay
 }
 def batTimes = List("23:00:17", "23:40:20", "00:12:45", "00:17:19")
 assert(LocalTime.MIN.plusSeconds(meanAngle(times, dayInSeconds).round).toString == "23:47:40")
 println(s"Successfully completed without errors. [total ${Platform.currentTime - executionStart} ms]")

}</lang>

Sidef

Translation of: Ruby

Using the mean_angle() function from: "Averages/Mean angle" <lang ruby>func time2deg(t) {

 (var m = t.match(/^(\d\d):(\d\d):(\d\d)$/)) || die "invalid time"
 var (hh,mm,ss) = m.cap.map{.to_i}...
 ((hh ~~ 24.range) && (mm ~~ 60.range) && (ss ~~ 60.range)) || die "invalid time"
 (hh*3600 + mm*60 + ss) * 360 / 86400

}   func deg2time(d) {

 var sec = ((d % 360) * 86400 / 360)
 "%02d:%02d:%02d" % (sec/3600, (sec%3600)/60, sec%60)

}   func mean_time(times) {

 deg2time(mean_angle(times.map {|t| time2deg(t)}))

}   say mean_time(["23:00:17", "23:40:20", "00:12:45", "00:17:19"])</lang>

Output:
23:47:43

Tcl

<lang tcl>proc meanTime {times} {

   set secsPerRad [expr {60 * 60 * 12 / atan2(0,-1)}]
   set sumSin [set sumCos 0.0]
   foreach t $times {

# Convert time to count of seconds from midnight scan $t "%02d:%02d:%02d" h m s incr s [expr {[incr m [expr {$h * 60}]] * 60}] # Feed into averaging set sumSin [expr {$sumSin + sin($s / $secsPerRad)}] set sumCos [expr {$sumCos + cos($s / $secsPerRad)}]

   }
   # Don't need to divide by counts; atan2() cancels that out
   set a [expr {round(atan2($sumSin, $sumCos) * $secsPerRad)}]
   # Convert back to human-readable
   format "%02d:%02d:%02d" [expr {$a / 60 / 60 % 24}] [expr {$a / 60 % 60}] [expr {$a % 60}]

}

puts [meanTime {23:00:17 23:40:20 00:12:45 00:17:19}]</lang>

Output:
23:47:43

XPL0

<lang XPL0>include c:\cxpl\codes;

proc NumOut(N); \Display 2-digit N with leading zero int N; [if N<10 then ChOut(0, ^0); IntOut(0, N); ];

proc TimeOut(Sec); \Display real seconds as HH:MM:SS real Sec; [NumOut(fix(Sec)/3600); ChOut(0, ^:);

NumOut(rem(0)/60);      ChOut(0, ^:);
NumOut(rem(0));

];

func real HMS2Sec(H, M, S); \Convert hours, minutes, seconds to real seconds int H, M, S; return float(((H*60 + M)*60) + S);

func real MeanTime(A); \Return the mean of the given list of times int A; real X, Y, Sec; int I; def Pi = 3.14159265358979323846; def S2R = Pi/(12.*60.*60.); \coefficient to convert seconds to radians [X:= 0.0; Y:= 0.0; for I:= 1 to A(0) do

   [Sec:= HMS2Sec(A(I,0), A(I,1), A(I,2));
   X:= X + Cos(Sec*S2R);
   Y:= Y + Sin(Sec*S2R);
   ];

Sec:= ATan2(Y,X)/S2R; if Sec < 0.0 then Sec:= Sec + 24.*60.*60.; return Sec; ];

TimeOut(MeanTime([4, [23,00,17], [23,40,20], [00,12,45], [00,17,19]]))</lang>

Output:
23:47:43

zkl

This solution is a bit greasy, combining the solution to task "Averages/Mean angle" and some on-the-fly time-to-angle and back conversions. <lang zkl>var D=Time.Date; fcn meanT(t1,t2,etc){

  ts:=vm.arglist.apply(fcn(hms){
    (D.toFloat(hms.split(":").xplode())*15).toRad()
  });
  n:=ts.len(); 
  mt:=(ts.apply("sin").sum(0.0)/n)
      .atan2(ts.apply("cos").sum(0.0)/n)
      .toDeg() /15;
  if(mt<0) mt+=24;  //-0.204622-->23.7954
  D.toHour(mt).concat(":")

}</lang> Time.Date.toFloat/toHour convert 24hr HMS to fractional time and back. Multiplying fractional time by 360/24=15 yields angle.

Output:
meanT("23:00:17", "23:40:20", "00:12:45", "00:17:19")
23:47:43