Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Monkey patch ActiveSupport::TimeZone to fix TZInfo::AmbiguousTime errors
# put this file in config/initializers/monkey_patches.rb
require 'monkey_patches/active_support/time_zone'
# put this in lib/monkey_patches/active_support/time_zone.rb
module MonkeyPatches
module ActiveSupport
module TimeZone
extend ::ActiveSupport::Concern
included do
alias_method_chain :period_for_local, :ambiguous_handling
end
# This monkey patch fixes exceptions like this one:
# TZInfo::AmbiguousTime: 2014-10-26 01:00:12 UTC is an ambiguous local time.
# They happen to appear when code like `3.days.ago` or `Time.zone.parse('some ambiguous date here')` is used,
# i.e. when some local time point can be translated into more than 1 points of time in UTC time, like it's
# happened in Europe/Moscow on October 26, 2014 when time from 01:00:00 till 01:59:59 went twice:
# 01:00:00 MSK +04:00 -> 01:59:59 MSK +04:00
# 01:59:59 MSK +04:00 -> 01:00:00 MSK +03:00
# 01:00:00 MSK +03:00 -> 02:00:00 MSK +04:00
# This change is permanent, so no daylight saving time (DST) is involved here
# See https://github.com/tzinfo/tzinfo/issues/32 for discussion
#
# Most of the time TZInfo resolves ambiguous dates by itself, but when it can't we have to choose it manually
# via supplied block, so take the earlier date by default
def period_for_local_with_ambiguous_handling(time, dst=true)
tzinfo.period_for_local(time, dst) { |results| results.first }
end
end
end
end
ActiveSupport::TimeZone.send :include, MonkeyPatches::ActiveSupport::TimeZone
# put this file in spec/lib/monkey_patches/active_support/time_zone_spec.rb
require 'spec_helper'
require 'timecop'
describe MonkeyPatches::ActiveSupport::TimeZone do
describe 'ambigious time bug' do
# I could reproduce this bug only on Rails 3.x
it 'n.days.ago should not throw exception' do
Timecop.travel(Time.zone.parse('27.10.2014 1:30:00 MSK +03:00')) do
expect { 1.day.ago }.not_to raise_error
end
end
it 'Time.zone.parse should not throw exception' do
expect { Time.zone.parse('26.10.2014 1:30:00') }.not_to raise_error
end
end
end
@almays

This comment has been minimized.

Copy link

almays commented Mar 15, 2017

Hi. In rails 5 there is this thing:

DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from block in <module:TimeZone> at lib/monkey_patches/active_support/time_zone.rb:8)
@Startouf

This comment has been minimized.

Copy link

Startouf commented Apr 1, 2018

I am using this patch only while running specs (since only my specs are affected) so I'll put it in spec/support and require it in my rails_helper.rb. I hope it will help me get rid of those flaky tests, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.