Why?
Because it is easy to get the dates/times wrong without even realising it. Even if you don’t need to support multiple time zones, you can catch a lot of the edge cases.How?
- Randomise time zone when running specs
- Run the specific specs across the different time zones
Usage: Randomise time zone when running specs
The RSpec support file (see below) will set the Rails’Time.zone
to a random time zone. So if something is wrong then your CI should eventually fail.When it will, you should look for the message at the very beginning:
1
|
|
Then go to your failing spec and in the context of it add the following (assuming you copy pasted the “Repro” part from the message):
1
|
|
Now you can re-run the spec and it should repeatably and predictably fail (much like RSpec’s random order with a given seed).
This works without changing any of the existing specs and relies on the fact that your CI is running specs often enough.
Usage: Run the specific specs across the different time zones
You may have some specs that you want to specifically test across all the time zones. That doesn’t mean you want to support all time zone, it just means that the transitions between the dates are very important. Getting it run for all timezones will give good confidence about the correctness of the functionality, even for one time zone.This can be used, for example, with tests on reports that are quite sensitive (all financial/sales reports probably).
So how do you do it?
Just write the normal specs without thinking about the time zone. Let’s take this as an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Make sure it passes in your timezone.
Then just wrap your spec in
across_time_zones
, like so:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
You’ll be surprised how many things can go wrong. Especially if you have some more advanced DB queries that use (in PostgreSQL terms) dates, times and times with time zone, maybe
DATE_TRUNC
etc.Now that spec will be created for each time zone with the given step.
Tips/Gotchas
- The default
step
here is set to 8 hours (it is optional), meaning that only 3 time zones will be tested. It may be sufficient or may not. So prefer to provide it explicitly. - The smaller the
step
is, the more specs will be created and the slower the example will become. So choose the number wisely (less than 2 hours is usually not necessary). - Always, always use
Time.zone.now
(orTime.current
) instead ofTime.now
. - Always, always use
Date.current
instead ofDate.today
. - Move any
let!
(with bang) andbefore
blocks under theacross_time_zones
to ensure the correct time zone is used at all times.