mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Treat combined durations as a single unit
Prior to this commit, `3.months - 3.months` would result in a duration that has the "parts" of `[[:months, 3], [:months, -3]]`. This would mean that it was subtly different than `2.months - 2.months`. When applied to a time, the date might actually change if the resulting day doesn't exist however many months in the future, even though in both cases we just wanted to add `0`, which should always be an identity operation. With this change, we now store the parts as a hash, so `3.months - 3.months` is simply stored as `{ months: 0 }`.
This commit is contained in:
parent
4806317b65
commit
32f215c301
2 changed files with 20 additions and 3 deletions
|
@ -15,16 +15,22 @@ module ActiveSupport
|
|||
autoload :ISO8601Serializer, "active_support/duration/iso8601_serializer"
|
||||
|
||||
def initialize(value, parts) #:nodoc:
|
||||
@value, @parts = value, parts
|
||||
@value, @parts = value, parts.to_h
|
||||
@parts.default = 0
|
||||
end
|
||||
|
||||
# Adds another Duration or a Numeric to this Duration. Numeric values
|
||||
# are treated as seconds.
|
||||
def +(other)
|
||||
if Duration === other
|
||||
Duration.new(value + other.value, @parts + other.parts)
|
||||
parts = @parts.dup
|
||||
other.parts.each do |(key, value)|
|
||||
parts[key] += value
|
||||
end
|
||||
Duration.new(value + other.value, parts)
|
||||
else
|
||||
Duration.new(value + other, @parts + [[:seconds, other]])
|
||||
seconds = @parts[:seconds] + other
|
||||
Duration.new(value + other, @parts.merge(seconds: seconds))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -345,6 +345,17 @@ class DurationTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_adding_durations_do_not_hold_prior_states
|
||||
time = Time.parse("Nov 29, 2016")
|
||||
# If the implementation adds and subtracts 3 months, the
|
||||
# resulting date would have been in February so the day will
|
||||
# change to the 29th.
|
||||
d1 = 3.months - 3.months
|
||||
d2 = 2.months - 2.months
|
||||
|
||||
assert_equal time + d1, time + d2
|
||||
end
|
||||
|
||||
private
|
||||
def eastern_time_zone
|
||||
if Gem.win_platform?
|
||||
|
|
Loading…
Reference in a new issue