Averages/Mean time of day
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
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.
|
11l
F mean_angle(angles)
V x = sum(angles.map(a -> cos(radians(a)))) / angles.len
V y = sum(angles.map(a -> sin(radians(a)))) / angles.len
R degrees(atan2(y, x))
F mean_time(times)
V t = (times.map(time -> time.split(‘:’)))
V seconds = (t.map(hms -> (Float(hms[2]) + Int(hms[1]) * 60 + Int(hms[0]) * 3600)))
V day = 24 * 60 * 60
V to_angles = seconds.map(s -> s * 360.0 / @day)
V mean_as_angle = mean_angle(to_angles)
V mean_seconds = round(mean_as_angle * day / 360.0)
I mean_seconds < 0
mean_seconds += day
V h = mean_seconds I/ 3600
V m = mean_seconds % 3600
V s = m % 60
m = m I/ 60
R ‘#02:#02:#02’.format(h, m, s)
print(mean_time([‘23:00:17’, ‘23:40:20’, ‘00:12:45’, ‘00:17:19’]))
- Output:
23:47:43
Action!
Action! does not support trigonometry, therefore a simple arithmetic solution has been proposed.
INCLUDE "H6:REALMATH.ACT"
DEFINE PTR="CARD"
TYPE Time=[BYTE s,m,h]
REAL r60
PROC PrintB2(BYTE b)
IF b<10 THEN Put('0) FI
PrintB(b)
RETURN
PROC PrintTime(Time POINTER t)
PrintB2(t.h) Put(':)
PrintB2(t.m) Put(':)
PrintB2(t.s)
RETURN
PROC Decode(CHAR ARRAY st Time POINTER t)
CHAR ARRAY tmp
IF st(0)#8 THEN Break() FI
SCopyS(tmp,st,1,2) t.h=ValB(tmp)
SCopyS(tmp,st,4,5) t.m=ValB(tmp)
SCopyS(tmp,st,7,8) t.s=ValB(tmp)
RETURN
PROC TimeToSeconds(Time POINTER t REAL POINTER seconds)
REAL r
IntToReal(t.h,seconds)
RealMult(seconds,r60,seconds)
IntToReal(t.m,r)
RealAdd(seconds,r,seconds)
RealMult(seconds,r60,seconds)
IntToReal(t.s,r)
RealAdd(seconds,r,seconds)
RETURN
PROC SecondsToTime(REAL POINTER seconds Time POINTER t)
REAL tmp1,tmp2
RealAssign(seconds,tmp1)
RealMod(tmp1,r60,tmp2)
t.s=RealToInt(tmp2)
RealDivInt(tmp1,r60,tmp2)
RealMod(tmp2,r60,tmp1)
t.m=RealToInt(tmp1)
RealDivInt(tmp2,r60,tmp1)
t.h=RealToInt(tmp1)
RETURN
PROC AverageTime(PTR ARRAY times BYTE count Time POINTER res)
BYTE i
Time t
REAL avg,rcount,seconds,halfDay,day
IntToReal(0,avg)
IntToReal(count,rcount)
ValR("43200",halfDay) ;seconds in the half of day
ValR("86400",day) ;seconds in the whole day
FOR i=0 TO count-1
DO
Decode(times(i),t)
TimeToSeconds(t,seconds)
IF RealLess(seconds,halfDay) THEN
RealAdd(seconds,day,seconds) ;correction of time
FI
RealAdd(avg,seconds,avg)
OD
RealDivInt(avg,rcount,avg)
WHILE RealGreaterOrEqual(avg,day)
DO
RealSub(avg,day,avg) ;correction of time
OD
SecondsToTime(avg,res)
RETURN
PROC Main()
DEFINE COUNT="4"
PTR ARRAY times(COUNT)
Time t
Put(125) PutE() ;clear the screen
IntToReal(60,r60)
times(0)="23:00:17" times(1)="23:40:20"
times(2)="00:12:45" times(3)="00:17:19"
AverageTime(times,COUNT,t)
Print("Mean time is ") PrintTime(t)
RETURN
- Output:
Screenshot from Atari 8-bit computer
Mean time is 23:47:40
Ada
with Ada.Calendar.Formatting;
with Ada.Command_Line;
with Ada.Numerics.Elementary_Functions;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure Mean_Time_Of_Day is
subtype Time is Ada.Calendar.Time;
subtype Time_Of_Day is Ada.Calendar.Day_Duration;
subtype Time_String is String (1 .. 8); -- "HH:MM:SS"
type Time_List is array (Positive range <>) of Time_String;
function Average_Time (List : Time_List) return Time_String is
function To_Time (Time_Image : Time_String) return Time
is (Ada.Calendar.Formatting.Value ("2000-01-01 " & Time_Image));
function To_Time_Of_Day (TS : Time) return Time_Of_Day is
use Ada.Calendar.Formatting;
Hour_Part : constant Time_Of_Day := 60.0 * 60.0 * Hour (TS);
Min_Part : constant Time_Of_Day := 60.0 * Minute (TS);
Sec_Part : constant Time_Of_Day := Time_Of_Day (Second (TS));
begin
return Hour_Part + Min_Part + Sec_Part;
end To_Time_Of_Day;
function To_Time_Image (Angle : Time_Of_Day) return Time_String
is
use Ada.Calendar.Formatting;
TOD : constant Time := Time_Of
(Year => 2000, Month => 1, Day => 1, -- Not used
Seconds => Angle);
begin
return Ada.Strings.Fixed.Tail (Image (TOD), Time_String'Length);
end To_Time_Image;
function Average_Time_Of_Day (List : Time_List) return Time_Of_Day is
use Ada.Numerics.Elementary_Functions;
Cycle : constant Float := Float (Time_Of_Day'Last);
X_Sum, Y_Sum : Float := 0.0;
Angle : Float;
begin
for Time_Stamp of List loop
Angle := Float (To_Time_Of_Day (To_Time (Time_Stamp)));
X_Sum := X_Sum + Cos (Angle, Cycle => Cycle);
Y_Sum := Y_Sum + Sin (Angle, Cycle => Cycle);
end loop;
Angle := Arctan (Y_Sum, X_Sum, Cycle => Cycle);
if Angle < 0.0 then
Angle := Angle + Cycle;
elsif Angle > Cycle then
Angle := Angle - Cycle;
end if;
return Time_Of_Day (Angle);
end Average_Time_Of_Day;
begin
return To_Time_Image (Average_Time_Of_Day (List));
end Average_Time;
use Ada.Command_Line;
List : Time_List (1 .. Argument_Count);
begin
if Argument_Count = 0 then
raise Constraint_Error;
end if;
for A in 1 .. Argument_Count loop
List (A) := Argument (A);
end loop;
Ada.Text_IO.Put_Line (Average_Time (List));
exception
when others =>
Ada.Text_IO.Put_Line ("Usage: mean_time_of_day <time-1> ...");
Ada.Text_IO.Put_Line (" <time-1> ... 'HH:MM:SS' format");
end Mean_Time_Of_Day;
- Output:
% ./mean_time_of_day 23:00:17 23:40:20 00:12:45 00:17:19 23:47:43
ALGOL 68
Uses code from the Averages/Mean angle task, included here for convenience.
BEGIN # Mean time of day mapping time to angles #
# code from the Averages/Mean angle task - angles are in degrees #
PROC mean angle = ([]REAL angles)REAL:
(
INT size = UPB angles - LWB angles + 1;
REAL y part := 0, x part := 0;
FOR i FROM LWB angles TO UPB angles DO
x part +:= cos (angles[i] * pi / 180);
y part +:= sin (angles[i] * pi / 180)
OD;
arc tan2 (y part / size, x part / size) * 180 / pi
);
# end code from the Averages/Mean angle task #
MODE TIME = STRUCT( INT hh, mm, ss );
OP TOANGLE = ( TIME t )REAL: ( ( ( ( ( ss OF t / 60 ) + mm OF t ) / 60 ) + hh OF t ) * 360 ) / 24;
OP TOTIME = ( REAL a )TIME:
BEGIN
REAL t := ( a * 24 ) / 360;
WHILE t < 0 DO t +:= 24 OD;
WHILE t > 24 DO t -:= 24 OD;
INT hh = ENTIER t;
t -:= hh *:= 60;
INT mm = ENTIER t;
INT ss = ENTIER ( ( t - mm ) * 60 );
( hh, mm, ss )
END # TOTIME # ;
PROC mean time = ( []TIME times )TIME:
BEGIN
[ LWB times : UPB times ]REAL angles;
FOR i FROM LWB times TO UPB times DO angles[ i ] := TOANGLE times[ i ] OD;
TOTIME mean angle( angles )
END # mean time # ;
OP SHOW = ( TIME t )VOID:
BEGIN
PROC d2 = ( INT n )STRING: IF n < 10 THEN "0" ELSE "" FI + whole( n, 0 );
print( ( d2( hh OF t ), ":", d2( mm OF t ), ":", d2( ss OF t ) ) )
END # show time # ;
SHOW mean time( ( ( 23,00,17 ), ( 23,40,20 ), ( 00,12,45 ), ( 00,17,19 ) ) )
END
- Output:
23:47:43
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")
}
- Output:
The mean time is: 23:47:43
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);
}
$ 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
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
- Output:
Mean time is 23:47:43
C
#include<stdlib.h>
#include<math.h>
#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;
}
- 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#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static System.Math;
namespace RosettaCode;
class Program
{
private const int SecondsPerDay = 60 * 60 * 24;
static void Main()
{
var digitimes = new List<TimeSpan>();
Console.WriteLine("Enter times, end with no input: ");
while (true) {
string input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) break;
if (TimeSpan.TryParse(input, out var digitime)) {
digitimes.Add(digitime);
} else {
Console.WriteLine("Seems this is wrong input: ignoring time");
}
}
if(digitimes.Count() > 0)
Console.WriteLine($"The mean time is : {MeanTime(digitimes)}");
}
public static TimeSpan MeanTime(IEnumerable<TimeSpan> ts) => FromDegrees(MeanAngle(ts.Select(ToDegrees)));
public static double ToDegrees(TimeSpan ts) => ts.TotalSeconds * 360d / SecondsPerDay;
public static TimeSpan FromDegrees(double degrees) => TimeSpan.FromSeconds((int)(degrees * SecondsPerDay / 360));
public static double MeanAngle(IEnumerable<double> angles)
{
var x = angles.Average(a => Cos(a * PI / 180));
var y = angles.Average(a => Sin(a * PI / 180));
return (Atan2(y, x) * 180 / PI + 360) % 360;
}
}
- 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
C++
#include <iomanip>
#include <iostream>
#include <vector>
#define _USE_MATH_DEFINES
#include <math.h>
struct Time {
int hour, minute, second;
friend std::ostream &operator<<(std::ostream &, const Time &);
};
std::ostream &operator<<(std::ostream &os, const Time &t) {
return os << std::setfill('0')
<< std::setw(2) << t.hour << ':'
<< std::setw(2) << t.minute << ':'
<< std::setw(2) << t.second;
}
double timeToDegrees(Time &&t) {
return 360.0 * t.hour / 24.0
+ 360.0 * t.minute / (24 * 60.0)
+ 360.0 * t.second / (24 * 3600.0);
}
Time degreesToTime(double angle) {
while (angle < 0.0) {
angle += 360.0;
}
while (angle > 360.0) {
angle -= 360.0;
}
double totalSeconds = 24.0 * 60 * 60 * angle / 360;
Time t;
t.second = (int)totalSeconds % 60;
t.minute = ((int)totalSeconds % 3600 - t.second) / 60;
t.hour = (int)totalSeconds / 3600;
return t;
}
double meanAngle(const std::vector<double> &angles) {
double yPart = 0.0, xPart = 0.0;
for (auto a : angles) {
xPart += cos(a * M_PI / 180);
yPart += sin(a * M_PI / 180);
}
return atan2(yPart / angles.size(), xPart / angles.size()) * 180 / M_PI;
}
int main() {
std::vector<double> tv;
tv.push_back(timeToDegrees({ 23, 0, 17 }));
tv.push_back(timeToDegrees({ 23, 40, 20 }));
tv.push_back(timeToDegrees({ 0, 12, 45 }));
tv.push_back(timeToDegrees({ 0, 17, 19 }));
double ma = meanAngle(tv);
auto mt = degreesToTime(ma);
std::cout << mt << '\n';
return 0;
}
- Output:
23:47:43
Common Lisp
;; * Loading the split-sequence library
(eval-when (:compile-toplevel :load-toplevel :execute)
(ql:quickload '("split-sequence")))
;; * The package definition
(defpackage :mean-time-of-day
(:use :common-lisp :iterate :split-sequence))
(in-package :mean-time-of-day)
;; * The data
(defparameter *time-values*
'("23:00:17" "23:40:20" "00:12:45" "00:17:19"))
(defun time->radian (time)
"Returns the radian value for TIME given as a STRING like HH:MM:SS. Assuming a
valid input value."
(destructuring-bind (h m s)
(mapcar #'parse-integer (split-sequence #\: time))
(+ (* h (/ PI 12)) (* m (/ PI 12 60)) (* s (/ PI 12 3600)))))
(defun radian->time (radian)
"Returns the corresponding time as a string like HH:MM:SS for RADIAN."
(let* ((time (if (plusp radian)
(round (/ (* 12 3600 radian) PI))
(round (/ (* 12 3600 (+ radian (* 2 PI))) PI))))
(h (floor time 3600))
(m (floor (- time (* h 3600)) 60))
(s (- time (* h 3600) (* m 60))))
(format nil "~2,'0D:~2,'0D:~2,'0D" h m s)))
(defun make-polar (rho theta)
"Returns a complex representing the polar coordinates."
(complex (* rho (cos theta)) (* rho (sin theta))))
(defun mean-time (times)
"Returns the mean time value within 24h of the list of TIMES given as strings
HH:MM:SS."
(radian->time (phase
(reduce #'+ (mapcar (lambda (time)
(make-polar 1 (time->radian time))) times)))))
- Output:
MEAN-TIME-OF-DAY> (mean-time *time-values*) "23:47:43"
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;
}
- Output:
23:47:43
Delphi
program Averages_Mean_time_of_day;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Math;
const
Inputs: TArray<string> = ['23:00:17', '23:40:20', '00:12:45', '00:17:19'];
function ToTimes(ts: TArray<string>): TArray<TTime>;
begin
SetLength(result, length(ts));
for var i := 0 to High(ts) do
Result[i] := StrToTime(ts[i]);
end;
function MeanTime(times: TArray<TTime>): TTime;
var
ssum, csum: TTime;
h, m, s, ms: word;
dayFrac, fsec, ssin, ccos: double;
begin
if Length(times) = 0 then
exit(0);
ssum := 0;
csum := 0;
for var t in times do
begin
DecodeTime(t, h, m, s, ms);
fsec := (h * 60 + m) * 60 + s + ms / 1000;
ssin := sin(fsec * Pi / (12 * 60 * 60));
ccos := cos(fsec * Pi / (12 * 60 * 60));
ssum := ssum + ssin;
csum := csum + ccos;
end;
if (ssum = 0) and (csum = 0) then
raise Exception.Create('Error MeanTime: Mean undefined');
dayFrac := frac(1 + ArcTan2(ssum, csum) / (2 * Pi));
fsec := dayFrac * 24 * 3600;
ms := Trunc(frac(fsec) * 1000);
s := trunc(fsec) mod 60;
m := trunc(fsec) div 60 mod 60;
h := trunc(fsec) div 3600;
Result := EncodeTime(h, m, s, ms);
end;
begin
writeln(TimeToStr(MeanTime(ToTimes(Inputs))));
readln;
end.
DuckDB
The function mean_time(t1,t2) defined here assumes that t1 and t2 are strings giving the time-of-day using a 24 hour clock, and that t1 occurs shortly before t2, and possibly the day before, but no more than 24 hours before. So if t2 seems to be greater than t1, then it is the day after.
create or replace function mean_time(t1, t2) as (
select if (diff >= 0, t1::TIME + INTERVAL (diff/2) seconds,
t1::TIME + INTERVAL ((86400 + diff)/2) seconds)
from
( select datediff('seconds', t1::TIME, t2::TIME) as diff )
);
## Examples:
select times[1], times[2], mean_time(times[1], times[2]) as mean
from values
( ['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'] )
t(times);
- Output:
┌──────────┬──────────┬──────────┐ │ times[1] │ times[2] │ mean │ │ varchar │ varchar │ time │ ├──────────┼──────────┼──────────┤ │ 0:0:0 │ 12:0:0 │ 06:00:00 │ │ 0:0:0 │ 24:0:0 │ 12:00:00 │ │ 1:0:0 │ 1:0:0 │ 01:00:00 │ │ 20:0:0 │ 4:0:0 │ 00:00:00 │ │ 20:0:0 │ 4:0:2 │ 00:00:01 │ │ 23:0:0 │ 23:0:0 │ 23:00:00 │ └──────────┴──────────┴──────────┘
select mean_time( mean_time('23:00:17', '23:40:20'), mean_time('00:12:45', '00:17:19')) as mean; ┌────────────┐ │ mean │ │ time │ ├────────────┤ │ 23:47:40.5 │ └────────────┘
EasyLang
func tm2deg t$ .
t[] = number strsplit t$ ":"
return 360 * t[1] / 24.0 + 360 * t[2] / (24 * 60.0) + 360 * t[3] / (24 * 3600.0)
.
func$ deg2tm deg .
len t[] 3
h = floor (24 * 60 * 60 * deg / 360)
t[3] = h mod 60
h = h div 60
t[2] = h mod 60
t[1] = h div 60
for h in t[]
if h < 10
s$ &= 0
.
s$ &= h
s$ &= ":"
.
return substr s$ 1 8
.
func mean ang[] .
for ang in ang[]
x += cos ang
y += sin ang
.
return atan2 (y / len ang[]) (x / len ang[])
.
in$ = "23:00:17 23:40:20 00:12:45 00:17:19"
for s$ in strsplit in$ " "
ar[] &= tm2deg s$
.
print deg2tm (360 + mean ar[])
EchoLisp
;; 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"
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]) ).
- 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
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
- 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#
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
- 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
Factor
USING: arrays formatting kernel math math.combinators
math.functions math.libm math.parser math.trig qw sequences
splitting ;
IN: rosetta-code.mean-time
CONSTANT: input qw{ 23:00:17 23:40:20 00:12:45 00:17:19 }
: time>deg ( hh:mm:ss -- x )
":" split [ string>number ] map first3
[ 15 * ] [ 1/4 * ] [ 1/240 * ] tri* + + ;
: mean-angle ( seq -- x )
[ deg>rad ] map [ [ sin ] map-sum ] [ [ cos ] map-sum ]
[ length ] tri recip [ * ] curry bi@ fatan2 rad>deg ;
: cutf ( x -- str y )
[ >integer number>string ] [ dup floor - ] bi ;
: mean-time ( seq -- str )
[ time>deg ] map mean-angle [ 360 + ] when-negative 24 *
360 / cutf 60 * cutf 60 * round cutf drop 3array ":" join ;
: mean-time-demo ( -- )
input dup mean-time "Mean time for %u is %s.\n" printf ;
MAIN: mean-time-demo
- Output:
Mean time for { "23:00:17" "23:40:20" "00:12:45" "00:17:19" } is 23:47:43.
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
- Output:
23:47:43
FreeBASIC
' FB 1.05.0 Win64
Const pi As Double = 3.1415926535897932
Function meanAngle(angles() As Double) As Double
Dim As Integer length = Ubound(angles) - Lbound(angles) + 1
Dim As Double sinSum = 0.0
Dim As Double cosSum = 0.0
For i As Integer = LBound(angles) To UBound(angles)
sinSum += Sin(angles(i) * pi / 180.0)
cosSum += Cos(angles(i) * pi / 180.0)
Next
Return Atan2(sinSum / length, cosSum / length) * 180.0 / pi
End Function
' time string assumed to be in format "hh:mm:ss"
Function timeToSecs(t As String) As Integer
Dim As Integer hours = Val(Left(t, 2))
Dim As Integer mins = Val(Mid(t, 4, 2))
Dim As Integer secs = Val(Right(t, 2))
Return 3600 * hours + 60 * mins + secs
End Function
' 1 second of time = 360/(24 * 3600) = 1/240th degree
Function timeToDegrees(t As String) As Double
Dim secs As Integer = timeToSecs(t)
Return secs/240.0
End Function
Function degreesToTime(d As Double) As String
If d < 0 Then d += 360.0
Dim secs As Integer = d * 240.0
Dim hours As Integer = secs \ 3600
Dim mins As Integer = secs Mod 3600
secs = mins Mod 60
mins = mins \ 60
Dim hBuffer As String = Right("0" + Str(hours), 2)
Dim mBuffer As String = Right("0" + Str(mins), 2)
Dim sBuffer As String = Right("0" + Str(secs), 2)
Return hBuffer + ":" + mBuffer + ":" + sBuffer
End Function
Dim tm(1 To 4) As String = {"23:00:17", "23:40:20", "00:12:45", "00:17:19"}
Dim angles(1 To 4) As Double
For i As Integer = 1 To 4
angles(i) = timeToDegrees(tm(i))
Next
Dim mean As Double = meanAngle(angles())
Print "Average time is : "; degreesToTime(mean)
Print
Print "Press any key to quit"
Sleep
- Output:
Average time is : 23:47:43
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
}
- Output:
23:47:43
Groovy
Solution:
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)
}
Test:
println (meanTime("23:00:17", "23:40:20", "00:12:45", "00:17:19"))
- Output:
23:47:43
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"]
- Output:
23:47:43
Icon and Unicon
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
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
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
- Example Use:
meanTime '23:00:17 23:40:20 00:12:45 00:17:19 '
23:47:43
Java
public class MeanTimeOfDay {
static double meanAngle(double[] angles) {
int len = angles.length;
double sinSum = 0.0;
for (int i = 0; i < len; i++) {
sinSum += Math.sin(angles[i] * Math.PI / 180.0);
}
double cosSum = 0.0;
for (int i = 0; i < len; i++) {
cosSum += Math.cos(angles[i] * Math.PI / 180.0);
}
return Math.atan2(sinSum / len, cosSum / len) * 180.0 / Math.PI;
}
/* time string assumed to be in format "hh:mm:ss" */
static int timeToSecs(String t) {
int hours = Integer.parseInt(t.substring(0, 2));
int mins = Integer.parseInt(t.substring(3, 5));
int secs = Integer.parseInt(t.substring(6, 8));
return 3600 * hours + 60 * mins + secs;
}
/* 1 second of time = 360/(24 * 3600) = 1/240th degree */
static double timeToDegrees(String t) {
return timeToSecs(t) / 240.0;
}
static String degreesToTime(double d) {
if (d < 0.0) d += 360.0;
int secs = (int)(d * 240.0);
int hours = secs / 3600;
int mins = secs % 3600;
secs = mins % 60;
mins /= 60;
return String.format("%2d:%2d:%2d", hours, mins, secs);
}
public static void main(String[] args) {
String[] tm = {"23:00:17", "23:40:20", "00:12:45", "00:17:19"};
double[] angles = new double[4];
for (int i = 0; i < 4; i++) angles[i] = timeToDegrees(tm[i]);
double mean = meanAngle(angles);
System.out.println("Average time is : " + degreesToTime(mean));
}
}
- Output:
Average time is : 23:47:43
JavaScript
var args = process.argv.slice(2);
function time_to_seconds( hms ) {
var parts = hms.split(':');
var h = parseInt(parts[0]);
var m = parseInt(parts[1]);
var s = parseInt(parts[2]);
if ( h < 12 ) {
h += 24;
}
var seconds = parseInt(parts[0]) * 60 * 60 + parseInt(parts[1]) * 60 + parseInt(parts[2]);
return seconds;
}
function seconds_to_time( s ) {
var h = Math.floor( s/(60 * 60) );
if ( h < 10 ) {
h = '0' + h;
}
s = s % (60 * 60);
var m = Math.floor( s/60 );
if ( m < 10 ) {
m = '0' + m;
}
s = s % 60
if ( s < 10 ) {
s = '0' + s;
}
return h + ':' + m + ':' + s;
}
var sum = 0, count = 0, idx;
for (idx in args) {
var seconds = time_to_seconds( args[idx] );
sum += seconds;
count++;
}
var seconds = Math.floor( sum / count )
console.log( 'Mean time is ', seconds_to_time(seconds));
- Output:
$ node mean_time.js 23:00:17 23:40:20 00:12:45 00:17:19 Mean time is 23:47:40
jq
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.
# 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 ;
Examples
["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
- Output:
$ 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
Julia
using Statistics
function meantime(times::Array, dlm::String=":")
c = π / (12 * 60 * 60)
a = map(x -> parse.(Int, x), split.(times, dlm))
ϕ = collect(3600t[1] + 60t[2] + t[3] for t in a)
d = angle(mean(exp.(c * im * ϕ))) / 2π # days
if d < 0 d += 1 end
# Convert to h:m:s
h = trunc(Int, d * 24)
m = trunc(Int, d * 24 * 60) - h * 60
s = trunc(Int, d * 24 * 60 * 60) - h * 60 * 60 - m * 60
return "$h:$m:$s"
end
times = String["23:00:17", "23:40:20", "00:12:45", "00:17:19"]
mtime = meantime(times)
println("Times:")
println.(times)
println("Mean: $mtime")
- Output:
Times: 23:00:17 23:40:20 00:12:45 00:17:19 Mean: 23:47:43
Kotlin
// version 1.0.6
fun meanAngle(angles: DoubleArray): Double {
val sinSum = angles.sumByDouble { Math.sin(it * Math.PI / 180.0) }
val cosSum = angles.sumByDouble { Math.cos(it * Math.PI / 180.0) }
return Math.atan2(sinSum / angles.size, cosSum / angles.size) * 180.0 / Math.PI
}
/* time string assumed to be in format "hh:mm:ss" */
fun timeToSecs(t: String): Int {
val hours = t.slice(0..1).toInt()
val mins = t.slice(3..4).toInt()
val secs = t.slice(6..7).toInt()
return 3600 * hours + 60 * mins + secs
}
/* 1 second of time = 360/(24 * 3600) = 1/240th degree */
fun timeToDegrees(t: String): Double = timeToSecs(t) / 240.0
fun degreesToTime(d: Double): String {
var dd = d
if (dd < 0.0) dd += 360.0
var secs = (dd * 240.0).toInt()
val hours = secs / 3600
var mins = secs % 3600
secs = mins % 60
mins /= 60
return String.format("%2d:%2d:%2d", hours, mins, secs)
}
fun main(args: Array<String>) {
val tm = arrayOf("23:00:17", "23:40:20", "00:12:45", "00:17:19")
val angles = DoubleArray(4) { timeToDegrees(tm[it]) }
val mean = meanAngle(angles)
println("Average time is : ${degreesToTime(mean)}")
}
- Output:
Average time is : 23:47:43
Liberty BASIC
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
- Output:
Average of: 23:00:17 23:40:20 00:12:45 00:17:19 is 23:47:43
Lua
local times = {"23:00:17","23:40:20","00:12:45","00:17:19"}
-- returns time converted to a radian format
local function timeToAngle(str)
local h,m,s = str:match("(..):(..):(..)")
return (h + m / 60 + s / 3600)/12 * math.pi
end
-- computes the mean of the angles inside a list
local function meanAngle(angles)
local sumSin,sumCos = 0,0
for k,v in pairs(angles) do
sumSin = sumSin + math.sin(v)
sumCos = sumCos + math.cos(v)
end
return math.atan2(sumSin,sumCos)
end
-- converts and angle back to a time string
local function angleToTime(angle)
local abs = angle % (math.pi * 2)
local time = abs / math.pi * 12
local h = math.floor(time)
local m = math.floor(time * 60) % 60
local s = math.floor(time * 3600) % 60
return string.format("%02d:%02d:%02d", h, m, s)
end
-- convert times to angles
for k,v in pairs(times) do
times[k] = timeToAngle(v)
end
print(angleToTime(meanAngle(times)))
- Output:
23:47:43
Mathematica / Wolfram Language
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"}]
- Output:
23:47:43
MATLAB / Octave
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;
mean_time_of_day({'23:00:17', '23:40:20', '00:12:45', '00:17:19'}) ans = 23:47:43
Nim
import math, complex, strutils, sequtils
proc meanAngle(deg: openArray[float]): float =
var c: Complex[float]
for d in deg:
c += rect(1.0, degToRad(d))
radToDeg(phase(c / float(deg.len)))
proc meanTime(times: openArray[string]): 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"])
- Output:
23:47:43
Oberon-2
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.
- Output:
:> 23:47:43
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)))
- Output:
The mean time of [23:00:17; 23:40:20; 00:12:45; 00:17:19] is: 23:47:43
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
- Output:
23:47:43
PARI/GP
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]])
- Output:
[23, 47, 43]
Perl
Traditional
Using the core module Math::Complex
to enable use of complex numbers. The POSIX
CPAN module provides the fmod
routine for non-integer modulus calculations.
use strict;
use warnings;
use POSIX 'fmod';
use Math::Complex;
use List::Util qw(sum);
use utf8;
use constant τ => 2 * 3.1415926535;
# time-of-day to radians
sub tod2rad {
($h,$m,$s) = split /:/, @_[0];
(3600*$h + 60*$m + $s) * τ / 86400;
}
# radians to time-of-day
sub rad2tod {
my $x = $_[0] * 86400 / τ;
sprintf '%02d:%02d:%02d', fm($x/3600,24), fm($x/60,60), fm($x,60);
}
# float modulus, normalized to positive values
sub fm {
my($n,$b) = @_;
$x = fmod($n,$b);
$x += $b if $x < 0;
}
sub phase { arg($_[0]) } # aka theta
sub cis { cos($_[0]) + i*sin($_[0]) }
sub mean_time { rad2tod phase sum map { cis tod2rad $_ } @_ }
@times = ("23:00:17", "23:40:20", "00:12:45", "00:17:19");
print mean_time(@times) . " is the mean time of " . join(' ', @times) . "\n";
- Output:
23:47:43 is the mean time of 23:00:17 23:40:20 00:12:45 00:17:19
v5.36
As previous, but using features from an up-to-date release of Perl, e.g. strict/warn/subroutine signatures without the use
boilerplate.
use v5.36;
use POSIX 'fmod';
use Math::Complex;
use List::Util 'sum';
use utf8;
use constant τ => 2 * 2 * atan2(1, 0);
sub R_to_ToD ($radians) { my $x = $radians * 86400 / τ; sprintf '%02d:%02d:%02d', fm($x/3600,24), fm($x/60,60), fm($x,60) }
sub ToD_to_R ($h,$m,$s) { (3600*$h + 60*$m + $s) * τ / 86400 }
sub fm ($n,$b) { my $x = fmod($n,$b); $x += $b if $x < 0 }
sub cis ($radians) { cos($radians) + i*sin($radians) }
sub phase ($Θ) { arg( $Θ ) }
sub mean_time(@t) { R_to_ToD phase sum map { cis ToD_to_R split ':', $_ } @t }
my @times = <23:00:17 23:40:20 00:12:45 00:17:19>;
say my $result = mean_time(@times) . ' is the mean time of ' . join ' ', @times;
- Output:
23:47:43 is the mean time of 23:00:17 23:40:20 00:12:45 00:17:19
Phix
with javascript_semantics function MeanAngle(sequence angles) atom x = 0, y = 0 for i=1 to length(angles) do atom 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 atom hours = floor(s/3600), mins = floor(remainder(s,3600)/60), secs = remainder(s,60) s = sprintf("%02d:%02d:%02d",{hours,mins,secs}) end if return s end function printf(1,"Mean Time is %s\n",{toHMS(MeanAngle(Times))})
- Output:
Mean Time is 23:47:43
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";
?>
- Output:
The mean time of day is 23:47:43 (angle 356.9306730355).
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) ) )
- Test:
: (meanTime '("23:00:17" "23:40:20" "00:12:45" "00:17:19"))
-> "23:47:43"
PL/I
*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;
- Output:
23:47:43
PowerShell
function Get-MeanTimeOfDay
{
[CmdletBinding()]
[OutputType([timespan])]
Param
(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[ValidatePattern("(?:2[0-3]|[01]?[0-9])[:.][0-5]?[0-9][:.][0-5]?[0-9]")]
[string[]]
$Time
)
Begin
{
[double[]]$angles = @()
function ConvertFrom-Time ([timespan]$Time)
{
[double]((360 * $Time.Hours / 24) + (360 * $Time.Minutes / (24 * 60)) + (360 * $Time.Seconds / (24 * 3600)))
}
function ConvertTo-Time ([double]$Angle)
{
$t = New-TimeSpan -Hours ([int](24 * 60 * 60 * $Angle / 360) / 3600) `
-Minutes (([int](24 * 60 * 60 * $Angle / 360) % 3600 - [int](24 * 60 * 60 * $Angle / 360) % 60) / 60) `
-Seconds ([int]((24 * 60 * 60 * $Angle / 360) % 60))
if ($t.Days -gt 0)
{
return ($t - (New-TimeSpan -Hours 1))
}
$t
}
function Get-MeanAngle ([double[]]$Angles)
{
[double]$x,$y = 0
for ($i = 0; $i -lt $Angles.Count; $i++)
{
$x += [Math]::Cos($Angles[$i] * [Math]::PI / 180)
$y += [Math]::Sin($Angles[$i] * [Math]::PI / 180)
}
$result = [Math]::Atan2(($y / $Angles.Count), ($x / $Angles.Count)) * 180 / [Math]::PI
if ($result -lt 0)
{
return ($result + 360)
}
$result
}
}
Process
{
$angles += ConvertFrom-Time $_
}
End
{
ConvertTo-Time (Get-MeanAngle $angles)
}
}
[timespan]$meanTimeOfDay = "23:00:17","23:40:20","00:12:45","00:17:19" | Get-MeanTimeOfDay
"Mean time is {0}" -f (Get-Date $meanTimeOfDay.ToString()).ToString("hh:mm:ss tt")
- Output:
Mean time is 11:47:43 PM
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"]) )
- Output:
23:47:43
Racket
#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"))
- Output:
"23:47:43"
Raku
(formerly Perl 6)
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[]";
- Output:
23:47:43 is the mean time of 23:00:17 23:40:20 00:12:45 00:17:19
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
- Output:
23:47:43
RPL
≪ → angles ≪ 0 1 angles SIZE FOR j 1 angles j GET R→C P→R + NEXT angles SIZE / ARG ≫ ≫ 'MEANG' STO
≪ → times ≪ { } 1 times SIZE FOR j 1 times j GET HMS→ 15 * + NEXT MEANG 15 / 24 MOD →HMS 4 FIX RND STD ≫ ≫ 'MTIME' STO
{23.0017 23.4020 0.1245 0.1719 } MTIME
- Output:
1: 23.4743
Ruby
Using the methods at [angle]
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"]
- Output:
23:47:43
Run BASIC
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
Rust
use std::f64::consts::PI;
#[derive(Debug, PartialEq, Eq)]
struct Time {
h: u8,
m: u8,
s: u8,
}
impl Time {
/// Create a Time from equivalent radian measure
fn from_radians(mut rads: f64) -> Time {
rads %= 2.0 * PI;
if rads < 0.0 {
rads += 2.0 * PI
}
Time {
h: (rads * 12.0 / PI) as u8,
m: ((rads * 720.0 / PI) % 60.0) as u8,
s: ((rads * 43200.0 / PI) % 60.0).round() as u8,
}
}
/// Create a Time from H/M/S
fn from_parts(h: u8, m: u8, s: u8) -> Result<Time, ()> {
if h > 23 || m > 59 || s > 59 {
return Err(());
}
Ok(Time { h, m, s })
}
/// Return time as measure in radians
fn as_radians(&self) -> f64 {
((self.h as f64 / 12.0) + (self.m as f64 / 720.0) + (self.s as f64 / 43200.0)) * PI
}
}
/// Compute the mean time from a slice of times
fn mean_time(times: &[Time]) -> Time {
// compute sum of sines and cosines
let (ss, sc) = times
.iter()
.map(Time::as_radians)
.map(|a| (a.sin(), a.cos()))
.fold((0.0, 0.0), |(ss, sc), (s, c)| (ss + s, sc + c));
// scaling does not matter for atan2, meaning we do not have to divide sums by len
Time::from_radians(ss.atan2(sc))
}
fn main() {
let times = [
Time::from_parts(23, 00, 17).unwrap(),
Time::from_parts(23, 40, 20).unwrap(),
Time::from_parts(00, 12, 45).unwrap(),
Time::from_parts(00, 17, 19).unwrap(),
];
let mean = mean_time(×);
println!("{:02}:{:02}:{:02}", mean.h, mean.m, mean.s);
}
- Output:
23:47:43
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]")
}
Scheme
To be self-contained, this starts with the functions from Averages/Mean angle
(import (scheme base)
(scheme inexact)
(scheme read)
(scheme write)
(srfi 1)) ; for fold
;; functions copied from "Averages/Mean angle" task
(define (average l)
(/ (fold + 0 l) (length l)))
(define pi 3.14159265358979323846264338327950288419716939937510582097)
(define (radians a)
(* pi 1/180 a))
(define (degrees a)
(* 180 (/ 1 pi) a))
(define (mean-angle angles)
(let* ((angles (map radians angles))
(cosines (map cos angles))
(sines (map sin angles)))
(degrees (atan (average sines) (average cosines)))))
;; -- new functions for this task
(define (time->angle time)
(let* ((time2 ; replaces : with space in string
(string-map (lambda (c) (if (char=? c #\:) #\space c)) time))
(string-port (open-input-string time2))
(hour (read string-port))
(minutes (read string-port))
(seconds (read string-port)))
(/ (* 360 (+ (* hour 3600) (* minutes 60) seconds))
(* 24 60 60))))
(define (angle->time angle)
(let* ((nom-angle (if (negative? angle) (+ 360 angle) angle))
(time (/ (* nom-angle 24 60 60) 360))
(hour (exact (floor (/ time 3600))))
(minutes (exact (floor (/ (- time (* 3600 hour)) 60))))
(seconds (exact (floor (- time (* 3600 hour) (* 60 minutes))))))
(string-append (number->string hour)
":"
(number->string minutes)
":"
(number->string seconds))))
(define (mean-time-of-day times)
(angle->time (mean-angle (map time->angle times))))
(write (mean-time-of-day '("23:00:17" "23:40:20" "00:12:45" "00:17:19")))
(newline)
- Output:
"23:47:43"
Sidef
Using the mean_angle() function from: "Averages/Mean angle"
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"])
- Output:
23:47:43
SQL /PostgreSQL
--Setup table for testing
CREATE TABLE time_table(times time);
INSERT INTO time_table values ('23:00:17'::time),('23:40:20'::time),('00:12:45'::time),('00:17:19'::time)
--Compute mean time
SELECT to_timestamp((degrees(atan2(AVG(sin),AVG(cos))))* (24*60*60)/360)::time
FROM
(SELECT
cos(radians(t*360/(24*60*60))),sin(radians(t*360/(24*60*60)))
FROM
(SELECT EXTRACT(epoch from times) t
FROM time_table) T1
)T2
Output:
23:47:43.361529
Swift
import Foundation
@inlinable public func d2r<T: FloatingPoint>(_ f: T) -> T { f * .pi / 180 }
@inlinable public func r2d<T: FloatingPoint>(_ f: T) -> T { f * 180 / .pi }
public func meanOfAngles(_ angles: [Double]) -> Double {
let cInv = 1 / Double(angles.count)
let (y, x) =
angles.lazy
.map(d2r)
.map({ (sin($0), cos($0)) })
.reduce(into: (0.0, 0.0), { $0.0 += $1.0; $0.1 += $1.1 })
return r2d(atan2(cInv * y, cInv * x))
}
struct DigitTime {
var hour: Int
var minute: Int
var second: Int
init?(fromString str: String) {
let split = str.components(separatedBy: ":").compactMap(Int.init)
guard split.count == 3 else {
return nil
}
(hour, minute, second) = (split[0], split[1], split[2])
}
init(fromDegrees angle: Double) {
let totalSeconds = 24 * 60 * 60 * angle / 360
second = Int(totalSeconds.truncatingRemainder(dividingBy: 60))
minute = Int((totalSeconds.truncatingRemainder(dividingBy: 3600) - Double(second)) / 60)
hour = Int(totalSeconds / 3600)
}
func toDegrees() -> Double {
return 360 * Double(hour) / 24.0 + 360 * Double(minute) / (24 * 60.0) + 360 * Double(second) / (24 * 3600.0)
}
}
extension DigitTime: CustomStringConvertible {
var description: String { String(format: "%02i:%02i:%02i", hour, minute, second) }
}
let times = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"].compactMap(DigitTime.init(fromString:))
guard times.count == 4 else {
fatalError()
}
let meanTime = DigitTime(fromDegrees: 360 + meanOfAngles(times.map({ $0.toDegrees() })))
print("Given times \(times), the mean time is \(meanTime)")
- Output:
Given times [23:00:17, 23:40:20, 00:12:45, 00:17:19], the mean time is 23:47:43
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}]
- Output:
23:47:43
Uiua
Not much native support for trig in Uiua, so much of the code is just setting that up.
# Find mean time of day using 'mean angle'
ParseTS ← setinv(/(+×60)⊜⋕≠@:.|/(◇⊂◇⊂)@:≡(□↙¯2⊂"00"°⋕)⌊[⍥(⊃÷◿60)2])
RpS ← ×π÷180÷240 1 # Radians per second
SpD ← ×× 24 60 60 # Seconds per day
Cos ← setinv(∿+η|-:η°∿)
# Polar to (complex) cartesian, and inverse.
PtoC ← setinv(
ℂ⍜⊟×⊃∿Cos:°⊟
| √+∩(×.),⟜:°ℂ
⍤("undefined for r=0")≠0.
⊟⟜(⍥¯<0:°Cos÷)
)
Ts ← "23:00:17, 23:40:20, 00:12:45, 00:17:19"
⊜(PtoC ⊟1 ×RpS ParseTS)¬⦷", ".Ts # Get TSs as unit complex numbers.
⁅÷RpS⊡1°PtoC÷⊃(⧻|/+) # Average them and convert back to seconds.
°ParseTS+×SpD<0. # Ensure its >0, format as TS.
- Output:
"23:47:43"
VBA
Uses Excel and mean angle.
Public Sub mean_time()
Dim angles() As Double
s = [{"23:00:17","23:40:20","00:12:45","00:17:19"}]
For i = 1 To UBound(s)
s(i) = 360 * TimeValue(s(i))
Next i
Debug.Print Format(mean_angle(s) / 360 + 1, "hh:mm:ss")
End Sub
- Output:
23:47:43
Visual Basic .NET
Module Module1
Function TimeToDegrees(time As TimeSpan) As Double
Return 360 * time.Hours / 24.0 + 360 * time.Minutes / (24 * 60.0) + 360 * time.Seconds / (24 * 3600.0)
End Function
Function DegreesToTime(angle As Double) As TimeSpan
Return New TimeSpan((24 * 60 * 60 * angle \ 360) \ 3600, ((24 * 60 * 60 * angle \ 360) Mod 3600 - (24 * 60 * 60 * angle \ 360) Mod 60) \ 60, (24 * 60 * 60 * angle \ 360) Mod 60)
End Function
Function MeanAngle(angles As List(Of Double)) As Double
Dim y_part = 0.0
Dim x_part = 0.0
Dim numItems = angles.Count
For Each angle In angles
x_part += Math.Cos(angle * Math.PI / 180)
y_part += Math.Sin(angle * Math.PI / 180)
Next
Return Math.Atan2(y_part / numItems, x_part / numItems) * 180 / Math.PI
End Function
Sub Main()
Dim digitimes As New List(Of Double)
Dim digitime As TimeSpan
Dim input As String
Console.WriteLine("Enter times, end with no input: ")
Do
input = Console.ReadLine
If Not String.IsNullOrWhiteSpace(input) Then
If TimeSpan.TryParse(input, digitime) Then
digitimes.Add(TimeToDegrees(digitime))
Else
Console.WriteLine("Seems this is wrong input: ingnoring time")
End If
End If
Loop Until String.IsNullOrWhiteSpace(input)
If digitimes.Count > 0 Then
Console.WriteLine("The mean time is : {0}", DegreesToTime(360 + MeanAngle(digitimes)))
End If
End Sub
End Module
- 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
V (Vlang)
import math
const inputs = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"]
fn main() {
angles := inputs.map(time_to_degs(it))
println('Mean time of day is: ${degs_to_time(mean_angle(angles))}')
}
fn mean_angle(angles []f64) f64 {
n := angles.len
mut sin_sum := f64(0)
mut cos_sum := f64(0)
for angle in angles {
sin_sum += math.sin(angle * math.pi / 180)
cos_sum += math.cos(angle * math.pi / 180)
}
return math.atan2(sin_sum/n, cos_sum/n) * 180 / math.pi
}
fn degs_to_time(dd f64) string{
mut d := dd
for d < 0 {
d += 360
}
mut s := math.round(d * 240)
h := math.floor(s/3600)
mut m := math.fmod(s, 3600)
s = math.fmod(m, 60)
m = math.floor(m / 60)
return "${h:02}:${m:02}:${s:02}"
}
fn time_to_degs(time string) f64 {
t := time.split(":")
h := t[0].f64() * 3600
m := t[1].f64() * 60
s := t[2].f64()
return (h + m + s) / 240
}
- Output:
Mean time of day is: 23:47:43
Wren
import "./fmt" for Fmt
var timeToDegs = Fn.new { |time|
var t = time.split(":")
var h = Num.fromString(t[0]) * 3600
var m = Num.fromString(t[1]) * 60
var s = Num.fromString(t[2])
return (h + m + s) / 240
}
var degsToTime = Fn.new { |d|
while (d < 0) d = d + 360
var s = (d * 240).round
var h = (s/3600).floor
var m = s % 3600
s = m % 60
m = (m / 60).floor
return Fmt.swrite("$2d:$2d:$2d", h, m, s)
}
var meanAngle = Fn.new { |angles|
var n = angles.count
var sinSum = 0
var cosSum = 0
for (angle in angles) {
sinSum = sinSum + (angle * Num.pi / 180).sin
cosSum = cosSum + (angle * Num.pi / 180).cos
}
return (sinSum/n).atan(cosSum/n) * 180 / Num.pi
}
var times = ["23:00:17", "23:40:20", "00:12:45", "00:17:19"]
var angles = times.map { |t| timeToDegs.call(t) }.toList
System.print("Mean time of day is : %(degsToTime.call(meanAngle.call(angles)))")
- Output:
Mean time of day is : 23:47:43
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]]))
- Output:
23:47:43
Yabasic
sub atan2(y, x)
return 2 * atan((sqrt(x **2 + y ** 2) - x) / y)
end sub
sub MeanAngle(angles())
local x, y, ai_rad, l, i
l = arraysize(angles(), 1)
for i = 1 to l
ai_rad = angles(i) * PI / 180
x = x + cos(ai_rad)
y = y + sin(ai_rad)
next i
if abs(x) < 1e-16 return false
return atan2(y, x) * 180 / PI
end sub
sub toSecAngle(hours, minutes, seconds)
return ((hours * 60 + minutes) * 60 + seconds) / (24 * 60 * 60) * 360
end sub
dim Times(4)
Times(1) = toSecAngle(23,00,17)
Times(2) = toSecAngle(23,40,20)
Times(3) = toSecAngle(00,12,45)
Times(4) = toSecAngle(00,17,19)
sub toHMS$(t)
local s$
if t then
if t < 0 t = t + 360
t = 24 * 60 * 60 * t / 360
s$ = str$(int(t / 3600), "%02g") + ":" + str$(int(mod(t, 3600) / 60), "%02g") + ":" + str$(int(mod(t, 60)), "%02g")
else
s$ = "not meaningful"
end if
return s$
end sub
print "Mean Time is ", toHMS$(MeanAngle(Times()))
// Output: Mean Time is 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.
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(":")
}
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
- Programming Tasks
- Date and time
- 11l
- Action!
- Action! Tool Kit
- Action! Real Math
- Ada
- ALGOL 68
- AutoHotkey
- AWK
- BBC BASIC
- C
- C sharp
- C++
- Common Lisp
- D
- Delphi
- System.SysUtils
- System.Math
- DuckDB
- EasyLang
- EchoLisp
- Erlang
- Euphoria
- F Sharp
- Factor
- Fortran
- FreeBASIC
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Julia
- Kotlin
- Liberty BASIC
- Lua
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Nim
- Oberon-2
- OCaml
- OoRexx
- PARI/GP
- Perl
- Phix
- PHP
- PicoLisp
- PL/I
- PowerShell
- Python
- Racket
- Raku
- REXX
- RPL
- Ruby
- Run BASIC
- Rust
- Scala
- Java.time.LocalTime
- Scheme
- Scheme/SRFIs
- Sidef
- SQL
- PostgreSQL
- Swift
- Tcl
- Uiua
- VBA
- Visual Basic .NET
- V (Vlang)
- Wren
- Wren-fmt
- XPL0
- Yabasic
- Zkl