mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
fix: equivalent negative durations add to the same time (#43795)
* bug: illustrate negative durations don't add to the same time * fix: equivalent negative durations add to the same time Co-authored-by: Caleb <me@cpb.ca> Co-authored-by: Braden Staudacher <braden.staudacher@chime.com> * Updates CHANGELOG with fix to `ActiveSupport::Duration.build`
This commit is contained in:
parent
1410c3fd1d
commit
ffc1e5f889
3 changed files with 22 additions and 3 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
* Fix `ActiveSupport::Duration.build` to support negative values.
|
||||||
|
|
||||||
|
The algorithm to collect the `parts` of the `ActiveSupport::Duration`
|
||||||
|
ignored the sign of the `value` and accumulated incorrect part values. This
|
||||||
|
impacted `ActiveSupport::Duration#sum` (which is dependent on `parts`) but
|
||||||
|
not `ActiveSupport::Duration#eql?` (which is dependent on `value`).
|
||||||
|
|
||||||
|
*Caleb Buxton*, *Braden Staudacher*
|
||||||
|
|
||||||
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activesupport/CHANGELOG.md) for previous changes.
|
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activesupport/CHANGELOG.md) for previous changes.
|
||||||
|
|
|
@ -191,13 +191,14 @@ module ActiveSupport
|
||||||
end
|
end
|
||||||
|
|
||||||
parts = {}
|
parts = {}
|
||||||
remainder = value.round(9)
|
remainder_sign = value <=> 0
|
||||||
|
remainder = value.round(9).abs
|
||||||
variable = false
|
variable = false
|
||||||
|
|
||||||
PARTS.each do |part|
|
PARTS.each do |part|
|
||||||
unless part == :seconds
|
unless part == :seconds
|
||||||
part_in_seconds = PARTS_IN_SECONDS[part]
|
part_in_seconds = PARTS_IN_SECONDS[part]
|
||||||
parts[part] = remainder.div(part_in_seconds)
|
parts[part] = remainder.div(part_in_seconds) * remainder_sign
|
||||||
remainder %= part_in_seconds
|
remainder %= part_in_seconds
|
||||||
|
|
||||||
unless parts[part].zero?
|
unless parts[part].zero?
|
||||||
|
@ -206,7 +207,7 @@ module ActiveSupport
|
||||||
end
|
end
|
||||||
end unless value == 0
|
end unless value == 0
|
||||||
|
|
||||||
parts[:seconds] = remainder
|
parts[:seconds] = remainder * remainder_sign
|
||||||
|
|
||||||
new(value, parts, variable)
|
new(value, parts, variable)
|
||||||
end
|
end
|
||||||
|
|
|
@ -752,6 +752,17 @@ class DurationTest < ActiveSupport::TestCase
|
||||||
assert (1.day + 12.hours).variable?
|
assert (1.day + 12.hours).variable?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_duration_symmetry
|
||||||
|
time = Time.parse("Dec 7, 2021")
|
||||||
|
expected_time = Time.parse("2021-12-06 23:59:59")
|
||||||
|
|
||||||
|
assert_equal expected_time, time + -1.second
|
||||||
|
assert_equal expected_time, time + ActiveSupport::Duration.build(1) * -1
|
||||||
|
assert_equal expected_time, time + -ActiveSupport::Duration.build(1)
|
||||||
|
assert_equal expected_time, time + ActiveSupport::Duration::Scalar.new(-1)
|
||||||
|
assert_equal expected_time, time + ActiveSupport::Duration.build(-1)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def eastern_time_zone
|
def eastern_time_zone
|
||||||
if Gem.win_platform?
|
if Gem.win_platform?
|
||||||
|
|
Loading…
Reference in a new issue