Skip to content

Instantly share code, notes, and snippets.

@campbell
Created October 8, 2009 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save campbell/0b30034d3f1e56fb4add to your computer and use it in GitHub Desktop.
Save campbell/0b30034d3f1e56fb4add to your computer and use it in GitHub Desktop.
require 'time'
TWELVE_HOURS = 12*60*60
TWENTYFOUR_HOURS = TWELVE_HOURS*2
def average_time_of_day(times)
# Since all times are relative, we don't know if the AM times occur before/after the PM times.
# We'll make an assumption that all times are somewhat related and thus should occur at about the
# same time, so we will choose start and end times that create the smallest possible time window.
# To do this, we will calculate the total time range with the AM times occurring before the PM times,
# then we'll compare this to the time range when the AM times occur after the PM times.
#
# If the AM times occur first, then the time window is the maximum PM time minus the minimum AM time.
# If the AM times occur after the PM times, then the time window is the maximum AM time plus 24 hours
# and minus the minimum PM time, eg.
#
# should_we_shift_the_AM_times = ( PM_MAX_TIME - AM_MAX_TIME ) < ( (AM_MIN_TIME+24) - PM_MIN_TIME)
#
# Of course, this only applies if we have both AM and PM times....
midnight = Time.parse('12:00am') # Midnight today, needed since all times are relative
# Get each time relative to midnight today (since the input times are relative)
times = times.collect { |t| Time.parse(t)-midnight } # Convert the original array into relative times
am_times, pm_times = times.partition { |t| t < TWELVE_HOURS }
# Adjust any AM times by 24 hours if that makes the total time window smaller
if ( !am_times.empty? && !pm_times.empty? && (pm_times.max-am_times.min) > (am_times.max-pm_times.min+24*60*60) )
am_times.each_index { |t| am_times[t] += TWENTYFOUR_HOURS }
times = pm_times + am_times
end
# Uncomment the next line to see the times for the selected shortest time window
# print "Debug: Time range: #{Time.at(times.min)+midnight.to_i} to #{Time.at(times.max)+midnight.to_i}\n"
# Calculate the average - we must add the relative average time to the baseline midnight time so we can
# get the correct absolute time
sum = times.inject(0) { |s,i| s+i }
average_time = Time.at(sum.to_f/times.length)+midnight.to_i # TO_I needed for time addition operator
average_time.strftime('%I:%M%p').downcase
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment