0

I am trying to calculate the average time from a list using the code from this thread. All the other code suggestions do not work for me as they consider duration and not time.

import datetime
import math
import numpy

def datetime_to_radians(x):
    # radians are calculated using a 24-hour circle, not 12-hour, starting at north and moving clockwise
    time_of_day = x.time()
    seconds_from_midnight = 3600 * time_of_day.hour + 60 * time_of_day.minute + time_of_day.second
    radians = float(seconds_from_midnight) / float(12 * 60 * 60) * 2.0 * math.pi
    return radians

def average_angle(angles):
    # angles measured in radians
    x_sum = numpy.sum([math.sin(x) for x in angles])
    y_sum = numpy.sum([math.cos(x) for x in angles])
    x_mean = x_sum / float(len(angles))
    y_mean = y_sum / float(len(angles))
    return numpy.arctan2(x_mean, y_mean)

def radians_to_time_of_day(x):
    # radians are measured clockwise from north and represent time in a 24-hour circle
    seconds_from_midnight = int(float(x) / (2.0 * math.pi) * 12.0 * 60.0 * 60.0)
    hour = seconds_from_midnight / 3600
    minute = (seconds_from_midnight % 3600) / 60
    second = seconds_from_midnight % 60
    return datetime.time(hour, minute, second)

def average_times_of_day(x):
    # input datetime.datetime array and output datetime.time value
    angles = [datetime_to_radians(y) for y in x]
    avg_angle = average_angle(angles)
    return radians_to_time_of_day(avg_angle)

average_times_of_day([datetime.datetime(2017, 6, 9, 0, 10), datetime.datetime(2017, 6, 9, 0, 20)])
# datetime.time(0, 15)

average_times_of_day([datetime.datetime(2017, 6, 9, 23, 50), datetime.datetime(2017, 6, 9, 0, 10)])
# datetime.time(0, 0)

I am getting the following error:

TypeError: integer argument expected, got float

Can someone help?

Peterhack
  • 941
  • 4
  • 15
  • 34

3 Answers3

1

Here is another solution that can handle a list of datetime-objects only considering hours and minutes:

from cmath import phase
from cmath import rect
import datetime
from math import degrees
from math import radians

dfList = ([datetime.datetime(2017, 9, 15, 8, 8),
           datetime.datetime(2017, 9, 14, 8, 5),
           datetime.datetime(2017, 9, 13, 6, 56),
           datetime.datetime(2017, 12, 9, 6, 14),
           datetime.datetime(2017, 11, 9, 6, 42)])

dfList = [item.strftime("%H:%M") for item in dfList]


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 = ((int(m) * 60 + int(h) * 3600)
               for h, m 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' % (h, m)


print(mean_time(dfList))
Peterhack
  • 941
  • 4
  • 15
  • 34
0

Your code works well in Python 2.7 but not Python 3.6.

The error threw at line 26, return datetime.time(hour, minute, second).

After cast the value of hour, minute and second to int(), it works fine.

def radians_to_time_of_day(x):
    # radians are measured clockwise from north and represent time in a 24-hour circle
    seconds_from_midnight = int(float(x) / (2.0 * math.pi) * 12.0 * 60.0 * 60.0)
    hour = int(seconds_from_midnight / 3600)
    minute = int((seconds_from_midnight % 3600) / 60)
    second = int(seconds_from_midnight % 60)
    return datetime.time(hour, minute, second)
thewaywewere
  • 8,128
  • 11
  • 41
  • 46
0

In Python 3, / does true (floating) division even if both operands are integers.

Use // instead

def radians_to_time_of_day(x):
    # radians are measured clockwise from north and represent time in a 24-hour circle
    seconds_from_midnight = int(float(x) / (2.0 * math.pi) * 12.0 * 60.0 * 60.0)
    hour = seconds_from_midnight // 3600
    minute = (seconds_from_midnight % 3600) // 60
    second = seconds_from_midnight % 60
    return datetime.time(hour, minute, second)
pacholik
  • 8,607
  • 9
  • 43
  • 55