Skip to content

Timezone controls (optional, default turned on)#1327

Open
cwant wants to merge 9 commits into
ElixirTeSS:masterfrom
cwant:cwant/timezone-controls
Open

Timezone controls (optional, default turned on)#1327
cwant wants to merge 9 commits into
ElixirTeSS:masterfrom
cwant:cwant/timezone-controls

Conversation

@cwant

@cwant cwant commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary of changes

This ports over the timezone controls from Explora to Elixir/TeSS.

Motivation and context

It's helpful to see events in your own timezone. This PR gives a toggle between showing times in the timezone of each event, and showing times in the timezone detected by the webbrowser.

The timezone control widget shows up on any page where there is an event listed (e.g. events#index, events#show, upcoming events, etc.).

The timezone controls can be opened and closed for visibility.

An added feature: the event edit page allows you to enter times in the timezone of the event (rather than having to do the mental math of entering it in GMT and hoping you've done that correctly).

Note : this uses the ffi-icu gem. For our TeSS we use this so that the timezone names appear in the language that is selected in our user interface. E.g. heure d’été du Pacifique nord-américain when French is selected instead of Pacific Daylight Time.

Screenshots

Here is the initial hit on event#index, with option "event timezones" selected by default. Two events with different timezones are shown.

timezones1

Here is the same page, with the timezones controls displayed via the Change... link. (Clicking the x hides the controls again.)

timezones2

Here is the page with my timezone (detected by the browser) is clicked:

timezones3

Here is the editing link for start/end times, done in the timezone selected for the event (converted to GMT when saved to the database):

timezones4

Checklist

  • I have read and followed the CONTRIBUTING guide.
  • I confirm that I have the authority necessary to make this contribution on behalf of its copyright owner and agree to license it to the TeSS codebase under the BSD license.

@kennethrioja

Copy link
Copy Markdown
Contributor

Many thanks @cwant for taking the time to do this PR – really appreciated and really helpful!

Before this PR, I tried on my side to cherry-pick some of your commits from your forked TeSS, so far I picked up almost the same one :

I'll test on my side if everything seems ok for me and if I don't need the last I've added on my side.

I can definitely help review this PR @fbacall – if you want to throw a copilot, please do so.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports “timezone controls” UI and server-side support into TeSS so event times can be displayed either in each event’s own timezone (default) or in the browser-detected timezone, and allows editing event start/end in the event’s specified timezone.

Changes:

  • Added timezone toggle UI + AJAX endpoint to re-render event time blocks and controls.
  • Updated event edit/create flow to interpret entered datetimes as being in the selected event timezone.
  • Added ICU-based localized timezone naming (ffi-icu) and new i18n strings.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
test/controllers/events_controller_test.rb Adds controller test asserting edit/create respect event timezone for entered datetimes.
Gemfile Adds ffi-icu dependency for localized timezone display names.
Gemfile.lock Locks ffi-icu and dependency graph updates.
config/tess.example.yml Introduces feature.timezone_controls default configuration.
config/routes.rb Adds events#event_time_data route for AJAX timezone updates.
config/locales/en.yml Adds new strings for timezone UI and event form labels.
app/views/static/home/_upcoming_events.html.erb Adds timezone controls to the home “upcoming events” section and localizes the header.
app/views/events/show.html.erb Uses timezone-aware partials when the feature is enabled.
app/views/events/index.html.erb Renders timezone controls above results when enabled.
app/views/events/_form.html.erb Changes labels and assumes start/end are entered in selected timezone.
app/views/events/_event.html.erb Uses timezone-aware time rendering in event cards when enabled.
app/views/events/_event_timezone_control.html.erb New timezone control widget (collapse/choice UI).
app/views/events/_event_time_div.html.erb New per-event “time + timezone” rendering block used for AJAX replacement.
app/views/common/_associated_events.html.erb Adds timezone controls to associated-events blocks when enabled.
app/models/event.rb Updates start_local/end_local conversion logic.
app/helpers/events_helper.rb Localizes date formatting and adds ICU-based timezone display helper.
app/controllers/events_controller.rb Shifts times for edit/save and adds event_time_data JSON endpoint.
app/controllers/application_controller.rb Adds session timezone selection from params/session.
app/assets/stylesheets/application.scss Adds styling for timezone controls.
app/assets/javascripts/events.js Adds client-side AJAX to fetch updated HTML and wire up timezone control behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

include PublicActivity::StoreController

before_action :configure_permitted_parameters, if: :devise_controller?
before_action :timezone_from_params_or_session
Comment on lines +242 to +250
# Render times for the following event ids
out = (event_ids || []).map do |event_id|
event = Event.find(event_id.to_i)
html = render_to_string partial: 'events/event_time_div',
formats: [:html],
locals: { event: event, timezone: timezone }
{ id: "#event-time-#{event.id}",
html: html}
end
Comment on lines +271 to +283
def shift_times_to_timezone_for_editing
if (@event&.timezone)
@event.start = @event.start&.in_time_zone(@event.timezone.to_s)
@event.end = @event.end&.in_time_zone(@event.timezone.to_s)
end
end

def shift_times_to_utc_for_saving
if (@event&.timezone)
@event.start = @event.start&.change(zone: @event.timezone.to_s)
@event.end = @event.end&.change(zone: @event.timezone.to_s)
end
end
Comment thread app/models/event.rb
Comment on lines 188 to 190
def start_local
set_to_local start
start&.in_time_zone(self&.timezone)
end
Comment thread app/models/event.rb
Comment on lines 192 to 194
def end_local
set_to_local self.end
self.end&.in_time_zone(self&.timezone)
end
@@ -1,7 +1,14 @@
<% cache(['home', 'upcoming_events', @events]) do %>
Comment on lines +19 to +31
<a data-toggle="collapse" href="#timezone-select" class="show-timezone-controls"
role="button" aria-expanded="false" aria-controls="collapseExample">
<%= t('events.timezone_controls.controls_show') %>
</a>
<% end %>
</p>

<% if local_assigns[:browser_timezone] %>
<div class="collapse" id="timezone-select">
<hr>
<i class="fa fa-window-close close-timezone-controls"
aria-label="<%= t('events.timezone_controls.close') %>"></i>

Comment on lines +178 to +179
# The ICU library we use want's underscores not spaces ...
tz_name = tz_name.gsub(' ', '_')
Comment on lines +43 to +45
$.ajax({
url: "/events/event_time_data.json",
data: data,
Comment on lines +10 to +12
<% unless event.timezone %>
<%= t('events.no_timezone_provided_gmt_assumed') %>
<% end %>
@kennethrioja

Copy link
Copy Markdown
Contributor

UI functionality

What I checked in the UI

  1. OK ☑️ : When timezone_controls is set to false, it must not show controls in events/event/upcoming_events/test
  2. When timezone_controls is commented or not present, it must not show controls in events/event/upcoming_events/test
    a. ACTION ⚠️ : For now, as the default is set to true on tess.example.yml, when I comment the timezone_controls line, I still see the timezone controls, this is a strange behavior: one might be surprised when pulling from origin/main to see these controls enables without having updated their own tess.yml – Change timezone_controls to false in tess.example.yml to avoid this? But I also understand having it enabled by default, this is a discussion to have with @fbacall
  3. When timezone_controls is set to true, it must show controls in events/event/upcoming_events/test
    a. OK ☑️ : In Events, everything was correct, either in my timezone, either in the timezone in which the event occurs
    b. ACTION ⚠️ : In test it is not showing the box
    i. When you do the test with a content provider, after clicking on ‘Preview’ you see this
    image
  4. When UTC/London, CEST, Pacific, converts well + it is in the db in GMT/UTC
    a. OK ☑️ : I tested with BST, CEST and PDT, it works as expected and saved as GMT/UTC in the db

Testing ingestion

  1. OK ☑️ : When ingesting https://heptraining.cern.ch/events/unit-tests-a-philosophy-and-help-on-our-applications, it displays the right time converted to CEST (detected): 10-11:30, the value in db is 9-10:30

Other Issues

  1. ACTION ⚠️ : When you have a content provider, with no current event, and at least one past event, you see this
image

Questions

  1. ACTION ⚠️ : In app/views/events/show.html.erb, l.62, what is the event_time_div? and why isn’t here in the other places?

Code review

  1. ACTION ⚠️ : Why did you change app/models/event.rb, l.189? I can only see <date>.asctime which is different (asked by copilot)
  2. Nothing to say on the code other than that – maybe if I wanted to be picky, code coverage decreased by .04%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants