secret
Last active

  • Download Gist
michaellang.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
# Given a series of times, computes the average time for the series, returning the
# calculated average time as a string.
#
# >> average_time_of_day(["11:51pm", "11:56pm", "12:01am", "12:06am", "12:11am"])
# => "12:01am"
#
# >> average_time_of_day(["6:41am", "6:51am", "7:01am"])
# => "6:51am"
 
require 'time'
 
DEGREES_IN_CIRCLE = 360.0
TWENTY_FOUR_HOUR_MINUTES = 24 * 60
DEGREES_PER_MINUTE = DEGREES_IN_CIRCLE / TWENTY_FOUR_HOUR_MINUTES
 
class Time
 
# Treats hours and minutes as "one hand" on a analog clock for 1440 minute clockface
def degrees
(self.hour * 60 + self.min) * DEGREES_PER_MINUTE
end
# converts degrees to radians
def radians
self.degrees * Math::PI / 180
end
# computes point on circumference of the imaginary 1440 minute clockface
def point
[Math::sin(self.radians), Math::cos(self.radians)]
end
# given a point on the imaginary 1440 minute clockface, returns time object
# corresponding to that point.
def self.at_point(point)
degrees = Math::atan2(point[0], point[1]) * 180 / Math::PI
hr = (degrees / DEGREES_PER_MINUTE / 60).to_i
m = (degrees / DEGREES_PER_MINUTE).round - hr * 60
parse("#{hr}:#{m}")
end
end
 
def average_time_of_day(times)
# parse the given time strings into Time objects
real_times = times.map{|m| Time.parse(m)}
# sum up and then take average of the points in the time series
sum_pt = real_times.inject([0, 0]) do |pt, t|
pt[0] += t.point[0]
pt[1] += t.point[1]
pt
end
avg_pt = [sum_pt[0] / times.size, sum_pt[1] / times.size]
# translate the computed average back into time object and print
Time.at_point(avg_pt).strftime("%I:%M%p").downcase
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.