Timezones!
Closed this issue ยท 1 comments
Trigger warning!! Timezones. ๐
We ran into some issues with the times being off for OUC JRs. I had a similar issue with the recent GGM Beach Worlds. I figured it was time to deep dive and understand how timezones work.
Background
Several years ago when I started the app I wasn't sure how to deal with timezones so I tried to avoid it all together. I told rails to save times using the local
option (more on what this does later) and added a gem to always set the Rails timezone to the user's browser timezone. The gem injects into all controllers to set the time zone.
In theory this worked and totally negated timezones as long as the tournament was built and ran in the same timezone. However now I've found myself working across timezones regularly and its not working out.
Investigating
After @patrickkenzie fixed the data by scheduling from Canada I checked the records in the Rails console:
record print out (with some fields removed)
#<Game
id: 6088,
pool: "A",
home_pool_seed: "1",
away_pool_seed: "2",
start_time: "2018-07-07 13:00:00",
end_time: "2018-07-07 14:00:00"
>
Printing the start_time
directly does say UTC.
game.start_time
=> Sat, 07 Jul 2018 13:00:00 UTC +00:00
I also checked the database directly:
ultimate-tournament::DATABASE=> SELECT start_time from GAMES WHERE ID = 6088;
start_time
---------------------
2018-07-07 13:00:00
(1 row)
In the Admin A1 vs A2
should be at 9:00 AM on Saturday and instead it's saved as 13:00 UTC and it actually shows as 15:00 in the browser for me which makes sense because Germany is +2 and Ottawa is -4. I messed up my initial sanity check because I did see a 9:00 AM game it just wasn't the right game.
So we know that Rails converts into UTC when saving to the database and back into the user's current timezone when loading the records.
What does config.active_record.default_timezone = :local
actually do? Well on production it turns out nothing because this :local
actually means the server's timezone which Heroku has set to UTC. Otherwise my understanding is this timezone is what Rails converts into and back from. I wasted a ton of time being confused by this option locally until I realised it meant the constant server timezone and not the dynamic timezone based on the user.
What now
After all of this research here is what I think should be done:
-
The config should be changed to:
config.active_record.default_timezone = :utc
or removed sinceutc
is the default. This removes the weirdness when investigating time issues locally and should be a no-op on production. This should be done in a standalone step to double check that I am actually right. -
The timezone should be set from the tournament setting (which currently does nothing) not the browser to enable working on tournaments from different timezones. The timezone should be automatically set on signup and editable from the settings page. The timezone should be surfaced on the schedule editor as well.
- Based on how Tournament timezone was set I suspect there is a lot of NULL values on production. We should backfill with the right timezone. There have only been a dozen or so real tournaments so this isn't too bad to do correctly. We can manually set the timezone for the real tournaments and put EST for all the rest.
-
browser-time-zone rails needs to be removed because it injects into all controllers. The admin needs to use the tournaments timezone. The player-app client can still use the browser timezone since people might be viewing scores etc from afar.
-
All of this should be done after OUC JRs is over to avoid messing anything up
Not as bad as I thought:
irb(main):001:0> Tournament.where(timezone: nil).count
(2.9ms) SELECT COUNT(*) FROM "tournaments" WHERE "tournaments"."timezone" IS NULL
=> 42
irb(main):002:0> Tournament.count
(1.8ms) SELECT COUNT(*) FROM "tournaments"
=> 188
irb(main):003:0>