提交 5cd3bbbb 编写于 作者: S Sean Griffin

Time columns should support time zone aware attributes

The types that are affected by `time_zone_aware_attributes` (which is on
by default) have been made configurable, in case this is a breaking
change for existing applications.
上级 d8e71041
* `time` columns can now affected by `time_zone_aware_attributes`. If you have
set `config.time_zone` to a value other than `'UTC'`, they will be treated
as in that time zone by default in Rails 5.0. If this is not the desired
behavior, you can set
ActiveRecord::Base.time_zone_aware_types = [:datetime]
A deprecation warning will be emitted if you have a `:time` column, and have
not explicitly opted out.
Fixes #3145
*Sean Griffin*
* `nil` as a value for a binary column in a query no longer logs as
"<NULL binary data>", and instead logs as just "nil".
......
......@@ -13,7 +13,7 @@ def type_cast_from_user(value)
value.map { |v| type_cast_from_user(v) }
elsif value.respond_to?(:in_time_zone)
begin
value.in_time_zone || super
user_input_in_time_zone(value) || super
rescue ArgumentError
nil
end
......@@ -39,6 +39,9 @@ def convert_time_to_time_zone(value)
class_attribute :skip_time_zone_conversion_for_attributes, instance_writer: false
self.skip_time_zone_conversion_for_attributes = []
class_attribute :time_zone_aware_types, instance_writer: false
self.time_zone_aware_types = [:datetime, :not_explicitly_configured]
end
module ClassMethods
......@@ -59,9 +62,31 @@ def inherited(subclass)
end
def create_time_zone_conversion_attribute?(name, cast_type)
time_zone_aware_attributes &&
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym) &&
(:datetime == cast_type.type)
enabled_for_column = time_zone_aware_attributes &&
!self.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
result = enabled_for_column &&
time_zone_aware_types.include?(cast_type.type)
if enabled_for_column &&
!result &&
cast_type.type == :time &&
time_zone_aware_types.include?(:not_explicitly_configured)
ActiveSupport::Deprecation.warn(<<-MESSAGE)
Time columns will become time zone aware in Rails 5.1. This
sill cause `String`s to be parsed as if they were in `Time.zone`,
and `Time`s to be converted to `Time.zone`.
To keep the old behavior, you must add the following to your initializer:
config.active_record.time_zone_aware_types = [:datetime]
To silence this deprecation warning, add the following:
config.active_record.time_zone_aware_types << :time
MESSAGE
end
result
end
end
end
......
......@@ -18,7 +18,7 @@ class Array < Type::Value # :nodoc:
end
attr_reader :subtype, :delimiter
delegate :type, to: :subtype
delegate :type, :user_input_in_time_zone, to: :subtype
def initialize(subtype, delimiter = ',')
@subtype = subtype
......
......@@ -7,6 +7,19 @@ def type
:time
end
def user_input_in_time_zone(value)
return unless value.present?
case value
when ::String
value = "2000-01-01 #{value}"
when ::Time
value = value.change(year: 2000, day: 1, month: 1)
end
super(value)
end
private
def cast_value(value)
......
......@@ -9,6 +9,10 @@ def type_cast_for_schema(value)
"'#{value.to_s(:db)}'"
end
def user_input_in_time_zone(value)
value.in_time_zone
end
private
def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
......
......@@ -657,7 +657,7 @@ def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_i
end
end
def test_setting_time_zone_aware_attribute_in_current_time_zone
def test_setting_time_zone_aware_datetime_in_current_time_zone
utc_time = Time.utc(2008, 1, 1)
in_time_zone "Pacific Time (US & Canada)" do
record = @target.new
......@@ -676,6 +676,47 @@ def test_yaml_dumping_record_with_time_zone_aware_attribute
end
end
def test_setting_time_zone_aware_time_in_current_time_zone
in_time_zone "Pacific Time (US & Canada)" do
record = @target.new
time_string = "10:00:00"
expected_time = Time.zone.parse("2000-01-01 #{time_string}")
record.bonus_time = time_string
assert_equal expected_time, record.bonus_time
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.bonus_time.time_zone
record.bonus_time = ''
assert_nil record.bonus_time
end
end
def test_setting_time_zone_aware_time_with_dst
in_time_zone "Pacific Time (US & Canada)" do
current_time = Time.zone.local(2014, 06, 15, 10)
record = @target.new(bonus_time: current_time)
time_before_save = record.bonus_time
record.save
record.reload
assert_equal time_before_save, record.bonus_time
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.bonus_time.time_zone
end
end
def test_removing_time_zone_aware_types
with_time_zone_aware_types(:datetime) do
in_time_zone "Pacific Time (US & Canada)" do
record = @target.new(bonus_time: "10:00:00")
expected_time = Time.utc(2000, 01, 01, 10)
assert_equal expected_time, record.bonus_time
assert record.bonus_time.utc?
end
end
end
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
......@@ -908,6 +949,14 @@ def new_topic_like_ar_class(&block)
klass
end
def with_time_zone_aware_types(*types)
old_types = ActiveRecord::Base.time_zone_aware_types
ActiveRecord::Base.time_zone_aware_types = types
yield
ensure
ActiveRecord::Base.time_zone_aware_types = old_types
end
def cached_columns
Topic.columns.map(&:name)
end
......
......@@ -30,6 +30,9 @@
# Quote "type" if it's a reserved word for the current connection.
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type')
# FIXME: Remove this when the deprecation cycle on TZ aware types by default ends.
ActiveRecord::Base.time_zone_aware_types << :time
def current_adapter?(*types)
types.any? do |type|
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
......
......@@ -250,8 +250,8 @@ def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attr
}
topic = Topic.find(1)
topic.attributes = attributes
assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
assert topic.bonus_time.utc?
assert_equal Time.zone.local(2000, 1, 1, 16, 24, 0), topic.bonus_time
assert_not topic.bonus_time.utc?
end
end
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册