Article summary
Recently, I wrote a script to produce a timeline of upcoming events that would help our Office Coordinator, Terri Vruggink, prepare and plan for guests visiting our building. The timeline is simple, but it provides more details about upcoming events than the standard Google Calendar print view.
My script queries the Google Calendar API to retrieve events from several different calendars (particularly our conference rooms), then lists the events in order by start time, with details about the organizer, attendees, location, and duration.
While this is all information that we could pull directly from the Google Calendar web interface, a printed timeline provides a more concrete reference which is easier to survey when determining where to direct a guest. The implementation details of the timeline generator are not particularly exciting, but the output is incredibly helpful for smoothing our front desk operations.
How to Generate the Timeline
The heavy lifting occurs in the calls to the Google Calendar API; iterating through all specified calendars, and all events for the day, storing pertinent event details as hashes in the events
array.
events = []
calendar_ids.each do |calendar_id|
calendar_name = service.get_calendar(calendar_id).summary
# Returns only events for today
response = service.list_events(calendar_id,
single_events: true,
order_by: 'startTime',
time_min: Date.today.to_time.iso8601,
time_max: (Date.today + 1).to_time.iso8601)
response.items.each do |event|
name = event.summary
start_time = event.start.date_time || event.start.date
stop_time = event.end.date_time || event.end.date
# If the stop_time / start_time are not DateTime objects, this
# represents an all-day event, which we do not wish to display
# so we skip them
next unless (stop_time.instance_of? DateTime) && \
(start_time.instance_of? DateTime)
# Human friendly formatting of duration
duration = distance_of_time_in_words(stop_time.to_time -
start_time.to_time)
# Formats the start_time and stop_time in a very human
# friendly format: 1:00 PM; 10:00 AM, etc.
display_start_time = start_time.strftime('%l:%M %p').strip
display_stop_time = stop_time.strftime('%l:%M %p').strip
attendees = []
organizer = ''
event&.attendees&.each do |attendee|
# We do not want to list attendees that are room resources
unless attendee.resource
attendees << (attendee.display_name || attendee.email)
end
# Set organizer if an attendee is labeled as the organizer
if attendee.organizer
organizer = (attendee.display_name || attendee.email)
end
end
events << { name: name,
start_time: start_time,
stop_time: stop_time,
display_start_time: display_start_time,
display_stop_time: display_stop_time,
duration: duration,
attendees: attendees,
organizer: organizer,
calendar: calendar_name }
end
end
I sort all events by start time, filtering out duplicate events (with the same start time and name):
events = events.sort_by { |event| event[:start_time] }
events = events.uniq do |event|
"#{event[:start_time]} #{event[:name]}"
end
The events
array is rendered as HTML with an ERB template. The HTML template groups the events by hour of the day to ease navigating in a timely fashion:
<h1>Timeline for <%= Date.today %></h1>
<div class="timeblock">
<% (8..18).each do |hour| %>
<% if events.find{|event|event[:start_time].hour == hour} %>
<h1 class="hour"><%= hour_as_time(hour) %></h1>
<div class="events">
<% events.find_all{|event|event[:start_time].hour == hour}.each do |event| %>
<div class="event">
<h2><%= event[:display_start_time] %> :: <%= event[:name] %></h2>
<h3><%= event[:calendar] %></h3>
<ul>
<li>End Time: <%= event[:display_stop_time] %></li>
<li>Duration: <%= event[:duration] %></li>
<% unless event[:organizer].blank? %>
<li>Organizer: <%= event[:organizer] %></li>
<% end %>
</ul>
<% unless event[:attendees].empty? %>
<h3>Attendees</h3>
<ul>
<% event[:attendees].each do |attendee| %>
<li><%= attendee %></li>
<% end %>
</ul>
<% end %>
</div>
<% end %>
</div>
<% end %>
<% end %>
</div>
Timeline Output
When run against a few calendars, the rendered HTML output of the script populated with sample events as follows:
If you are interested, I have published the full source for my script along with instructions for how to customize it for specific Google Calendars.
Justin, this is so cool. It’s funny, I’m desperately trying to find a good timeline tool and I am not liking the options out there so far. Any chance you can show me what this would look like when you’re looking at a longer duration (e.g. 4 months)?