From cb9d0e4864fa68fad9c49b880c32e90ddf0545bd Mon Sep 17 00:00:00 2001 From: Andrey Novikov Date: Mon, 9 Jan 2017 01:43:49 +0300 Subject: Fix inconsistent results when parsing large durations and constructing durations from code ActiveSupport::Duration.parse('P3Y') == 3.years # It should be true Duration parsing made independent from any moment of time: Fixed length in seconds is assigned to each duration part during parsing. Changed duration of months and years in seconds to more accurate and logical: 1. The value of 365.2425 days in Gregorian year is more accurate as it accounts for every 400th non-leap year. 2. Month's length is bound to year's duration, which makes sensible comparisons like `12.months == 1.year` to be `true` and nonsensical ones like `30.days == 1.month` to be `false`. Calculations on times and dates with durations shouldn't be affected as duration's numeric value isn't used in calculations, only parts are used. Methods on `Numeric` like `2.days` now use these predefined durations to avoid duplicating of duration constants through the codebase and eliminate creation of intermediate durations. --- activesupport/lib/active_support/core_ext/integer/time.rb | 4 ++-- activesupport/lib/active_support/core_ext/numeric/time.rb | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'activesupport/lib/active_support/core_ext') diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index 4a64872392..66ac3ca1b4 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -18,12 +18,12 @@ class Integer # # equivalent to Time.now.advance(months: 4, years: 5) # (4.months + 5.years).from_now def months - ActiveSupport::Duration.new(self * 30.days, [[:months, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:months].to_i, [[:months, self]]) end alias :month :months def years - ActiveSupport::Duration.new(self * 365.25.days.to_i, [[:years, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:years].to_i, [[:years, self]]) end alias :year :years end diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index 809dfd4e07..6ca2468047 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -27,7 +27,7 @@ class Numeric # # 2.minutes # => 2 minutes def minutes - ActiveSupport::Duration.new(self * 60, [[:minutes, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:minutes], [[:minutes, self]]) end alias :minute :minutes @@ -35,7 +35,7 @@ class Numeric # # 2.hours # => 2 hours def hours - ActiveSupport::Duration.new(self * 3600, [[:hours, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:hours], [[:hours, self]]) end alias :hour :hours @@ -43,7 +43,7 @@ class Numeric # # 2.days # => 2 days def days - ActiveSupport::Duration.new(self * 24.hours, [[:days, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:days], [[:days, self]]) end alias :day :days @@ -51,7 +51,7 @@ class Numeric # # 2.weeks # => 2 weeks def weeks - ActiveSupport::Duration.new(self * 7.days, [[:weeks, self]]) + ActiveSupport::Duration.new(self * ActiveSupport::Duration::PARTS_IN_SECONDS[:weeks], [[:weeks, self]]) end alias :week :weeks @@ -59,7 +59,7 @@ class Numeric # # 2.fortnights # => 4 weeks def fortnights - ActiveSupport::Duration.new(self * 2.weeks, [[:weeks, self * 2]]) + ActiveSupport::Duration.new(self * 2 * ActiveSupport::Duration::PARTS_IN_SECONDS[:weeks], [[:weeks, self * 2]]) end alias :fortnight :fortnights -- cgit v1.2.3