Skip to content

Instantly share code, notes, and snippets.

@djibouti33
Last active December 14, 2015 17:19
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 djibouti33/5121436 to your computer and use it in GitHub Desktop.
Save djibouti33/5121436 to your computer and use it in GitHub Desktop.
solution to convert place hours of operation from google place details api to a human readable format.
# the data we get from google looks like:
# - close:
# day: 0
# time: '1700'
# open:
# day: 0
# time: '1000'
# - close:
# day: 3
# time: '1700'
# open:
# day: 3
# time: '1000'
# - close:
# day: 4
# time: '1700'
# open:
# day: 4
# time: '1000'
# - close:
# day: 5
# time: '1700'
# open:
# day: 5
# time: '1000'
# - close:
# day: 6
# time: '1700'
# open:
# day: 6
# time: '1000'
# and we need to be able to display it as:
# Wed-Sun : 10am - 5pm
# - or -
# Mon,Wed,Fri : 8am - 7pm
# Tue,Thur : 10am - 11pm
# - or -
# Mon - Fri : 10am - 2pm, 4pm - 8pm
# easiest way to test this is to load the functions below into a rails console, then copy and paste the one of the following:
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 3,"time" => "1700"},"open" => {"day" => 3,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1700"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1700"},"open" => {"day" => 5,"time" => "1000"}},{"close" => {"day" => 6,"time" => "1700"},"open" => {"day" => 6,"time" => "1000"}}]}["periods"])
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 2,"time" => "1700"},"open" => {"day" => 2,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1700"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1700"},"open" => {"day" => 5,"time" => "1000"}},{"close" => {"day" => 6,"time" => "1700"},"open" => {"day" => 6,"time" => "1000"}}]}["periods"])
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 2,"time" => "1700"},"open" => {"day" => 2,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1915"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1700"},"open" => {"day" => 5,"time" => "1000"}},{"close" => {"day" => 6,"time" => "1700"},"open" => {"day" => 6,"time" => "1000"}}]}["periods"])
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 2,"time" => "1700"},"open" => {"day" => 2,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1915"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1700"},"open" => {"day" => 5,"time" => "1000"}}]}["periods"])
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 1,"time" => "1700"},"open" => {"day" => 1,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1700"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1700"},"open" => {"day" => 5,"time" => "1000"}}]}["periods"])
# helper.operating_hours({"periods" => [{"close" => {"day" => 0,"time" => "1400"},"open" => {"day" => 0,"time" => "1000"}},{"close" => {"day" => 0,"time" => "1900"},"open" => {"day" => 0,"time" => "1700"}},{"close" => {"day" => 1,"time" => "1400"},"open" => {"day" => 1,"time" => "1000"}},{"close" => {"day" => 1,"time" => "1900"},"open" => {"day" => 1,"time" => "1700"}},{"close" => {"day" => 2,"time" => "1400"},"open" => {"day" => 2,"time" => "1000"}},{"close" => {"day" => 2,"time" => "1900"},"open" => {"day" => 2,"time" => "1700"}},{"close" => {"day" => 3,"time" => "1400"},"open" => {"day" => 3,"time" => "1000"}},{"close" => {"day" => 3,"time" => "1900"},"open" => {"day" => 3,"time" => "1700"}},{"close" => {"day" => 4,"time" => "1400"},"open" => {"day" => 4,"time" => "1000"}},{"close" => {"day" => 4,"time" => "1900"},"open" => {"day" => 4,"time" => "1700"}},{"close" => {"day" => 5,"time" => "1400"},"open" => {"day" => 5,"time" => "1000"}},{"close" => {"day" => 5,"time" => "1900"},"open" => {"day" => 5,"time" => "1700"}},{"close" => {"day" => 6,"time" => "1400"},"open" => {"day" => 6,"time" => "1000"}},{"close" => {"day" => 6,"time" => "1900"},"open" => {"day" => 6,"time" => "1700"}}]}["periods"])
# convert place hours data from google into a displayable format
# [{"close" => {"day" => 0,"time" => "1700"},"open" => {"day" => 0,"time" => "1000"}}] = { "Sun" => "10am - 5pm"}
def operating_hours(periods)
# group similar periods together in a hash
# key = formatted time (open - close)
# value = array of days (as digits)
hours_of_op = periods.inject({}) { |memo, period|
time = format_time(period)
(memo[time] ||= []) << period["open"]["day"]; memo
}
# now that our hash's values are an array of day digits,
# convert that array into a readable string
hours_of_op = hours_of_op.reduce({}) { |memo, (key, value)|
memo[key] = format_days(value); memo
}
# displaying the data will be grouped by similar days, then hours.
# right now, our data strucutre is organized by the hours, so we need
# to do an invert/combine while ensuring we preserve each time span.
# this is primarily for those hours of operations that have breaks
# (i.e. siestas). as our structure is now, we'd have to say:
# Mon - Fri : 10, 2, Mon - Fri : 4 - 8.
# with this invert/combine, we'll be able to say:
# Mon - Fri : 10-2, 4-8.
hours_of_op = hours_of_op.reduce({}) { |memo,(key,value)|
(memo[value] ||=[]) << key; memo
}.reduce({}) { |memo, (key,value)|
memo[key] = value.join(', '); memo
}
end
# convert 24h span ( 1000 - 1700 ) to 12h span ( 10am - 5pm )
def format_time(val)
[val["open"]["time"], val["close"]["time"]].inject([]) { |memo, time|
memo << Time.strptime(time, "%H%M").strftime("%l:%M%P").gsub(/:00/, '').strip
memo
}.join(' - ')
end
# take day digits and turn them into day words,
# while combining consecutive days into spans,
def format_days(open_days)
days_array = %w[Sun Mon Tue Wed Thur Fri Sat]
# group by consecutive days
prev = open_days[0]
consecutive_groups = open_days.slice_before { |cur|
prev, prev2 = cur, prev
prev2 + 1 != prev
}.to_a
# if a place is closed in the middle of the week, but open on sunday and saturday,
# bring the sunday group around to the last group
# so instead of "Sun, Mon, Wed-Sat", you'll have "Wed-Mon"
if consecutive_groups.length > 1 and consecutive_groups.first.first == 0 and consecutive_groups.last.last == 6
consecutive_groups.last.concat(consecutive_groups.delete(consecutive_groups.first))
end
# convert day digits into day words, creating spans where appropriate
consecutive_groups.map! { |range|
range.map! { |parts| days_array[parts] }
range.length <= 2 ? range.join(', ') : "#{range.first} - #{range.last}"
}.join(', ')
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment