Today — Touch on time related libraries — Set up Rails to work with user's time zone — Play with Time in Rails — Introduce a feature and work through it Just in time
$ rake time:zones:all * UTC -11:00 * American Samoa International Date Line West Midway Island Samoa * UTC -10:00 * Hawaii * UTC -09:00 * Alaska ... Just in time
Setting a custom time zone # in console > Time.zone = "Perth" # in config/application.rb config.time_zone = "Perth" # ^ the default is "utc" Just in time
Custom user time zone: setting # app/controllers/application_controller.rb around_action :set_time_zone, if: :current_user private def set_time_zone(&block) Time.use_zone(current_user.time_zone, &block) end Just in time
Time zone related querying Post.where("published_at > ?", Time.current) # SELECT "posts".* FROM "posts" # WHERE (published_at > # '2015-07-04 17:45:01.452465') Just in time
DON'T * Time.parse("2015-07-04 17:05:37") * Time.strptime(string, "%Y-%m-%dT%H:%M:%S%z") DO * Time.zone.parse("2015-07-04 17:05:37") * Time.strptime( string, "%Y-%m-%dT%H:%M:%S%z" ).in_time_zone Just in time
Testing time zones: gems # Timecop Timecop.freeze new_time Timecop.travel new_time Timecop.return Time.use_zone("Sydney") do … end # Delorean Delorean.time_travel_to("1 month ago") do … end Delorean.back_to_the_present # Zonebie Zonebie.set_random_timezone Just in time
First go — Test suites that needed to run daily or weekly, — at a set time (1AM or 2AM), — and use ResqueScheduler to set the schedule to run the background workers. Just in time
Second go — Test runs according to user's settings, at a specific week day, hour, and time zone. — ResqueScheduler to run hourly and look for test suites that are due to run. — The ResqueScheduler to look for test runs where the background job failed and thus due to be run as well. Just in time
Still second go # lib/extensions.rb module ActiveSupport class TimeZone def self.current_zones(hour) all.select { |zone| t = Time.current.in_time_zone(zone) t.hour == hour }.map(&:tzinfo).map(&:name) end end end Just in time
Still second go # app/models/schedule_rule.rb class ScheduleRule < ActiveRecord::Base def self.find_rules(options={}) hour = options[:hour] where(zone: ActiveSupport::TimeZone.current_zones(hour)). where(options) end def self.suites_to_run(time_ago=Time.current, options={}) find_rules(options). older_than(time_ago). map(&:suite) end end Just in time
Still second go # app/workers/scheduled_runs_worker.rb class ScheduledRunsWorker def self.perform ScheduleRule. run_scheduled. daily. suites_to_run(yesterday, {hour: Time.now.utc.hour}) end end Just in time
Still third go # app/models/schedule_rule.rb class ScheduleRule < ActiveRecord::Base before_save :set_hour_in_utc private def set_hour_in_utc self.hour_in_utc = ActiveSupport::TimeZone[zone]. parse("#{hour}:00:00"). utc. hour end end Just in time
Still third go # app/models/schedule_rule.rb class ScheduleRule < ActiveRecord::Base def self.suites_to_run(time_ago=Time.current, options={}) where(options). older_than(time_ago). map(&:suite) end end Just in time
Worker didn't change # app/workers/scheduled_runs_worker.rb class ScheduledRunsWorker def self.perform ScheduleRule. run_scheduled. daily. suites_to_run(yesterday, {hour: Time.now.utc.hour}) end end Just in time
Previously # app/models/schedule_rule.rb class ScheduleRule < ActiveRecord::Base def self.find_rules(options={}) hour = options[:hour] where(zone: ActiveSupport::TimeZone.current_zones(hour)). where(options) end def self.suites_to_run(time_ago=Time.current, options={}) find_rules(options). older_than(time_ago). map(&:suite) end end Just in time
Currently class ScheduleRule < ActiveRecord::Base def self.suites_to_run(time_ago=Time.current, options={}) where(options). older_than(time_ago). map(&:suite) end end Just in time