From c3c69d90626dd5ac16231b1d53615547df678f76 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 16 Mar 2006 03:04:00 +0000 Subject: Added Time#advance to do precise time time calculations for cases where a month being approximated to 30 days won't do (closes #1860) [Rick Olson] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3887 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activesupport/CHANGELOG | 2 ++ activesupport/lib/active_support/core_ext/numeric/time.rb | 3 +++ .../lib/active_support/core_ext/time/calculations.rb | 9 +++++++++ activesupport/test/core_ext/time_ext_test.rb | 14 ++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 36db4dc605..ec676773bb 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added Time#advance to do precise time time calculations for cases where a month being approximated to 30 days won't do #1860 [Rick Olson] + * Enhance Inflector.underscore to convert '-' into '_' (as the inverse of Inflector.dasherize) [Jamis Buck] * Switched to_xml to use the xml schema format for datetimes. This allows the encoding of time zones and should improve operability. [Koz] diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index a69a6c5f64..b4954e943f 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -2,6 +2,9 @@ module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module Numeric #:nodoc: # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. + # + # If you need precise date calculations that doesn't just treat months as 30 days, then have + # a look at Time#advance. # # Some of these methods are approximations, Ruby's core # Date[http://stdlib.rubyonrails.org/libdoc/date/rdoc/index.html] and diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 6a80762a62..7c60d5bed5 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -44,6 +44,15 @@ module ActiveSupport #:nodoc: options[:usec] || ((options[:hour] || options[:min] || options[:sec]) ? 0 : self.usec) ) end + + # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with + # any of these keys: :months, :days, :years. + def advance(options) + d = ::Date.new(year + (options.delete(:years) || 0), month, day) + d = d >> options.delete(:months) if options[:months] + d = d + options.delete(:days) if options[:days] + change(options.merge(:year => d.year, :month => d.month, :mday => d.day)) + end # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension # Do not use this method in combination with x.months, use months_ago instead! diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 2100409dba..dee0a1f84e 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -129,7 +129,21 @@ class TimeExtCalculationsTest < Test::Unit::TestCase assert_equal Time.utc(2005,2,22,16,45), Time.utc(2005,2,22,15,15,10).change(:hour => 16, :min => 45) assert_equal Time.utc(2005,2,22,15,45), Time.utc(2005,2,22,15,15,10).change(:min => 45) end + + def test_plus + assert_equal Time.local(2006,2,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 1) + assert_equal Time.local(2005,6,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:months => 4) + assert_equal Time.local(2012,9,28,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 7) + assert_equal Time.local(2013,10,3,15,15,10), Time.local(2005,2,28,15,15,10).advance(:years => 7, :months => 19, :days => 5) + end + def test_utc_plus + assert_equal Time.utc(2006,2,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 1) + assert_equal Time.utc(2005,6,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:months => 4) + assert_equal Time.utc(2012,9,22,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 7) + assert_equal Time.utc(2013,10,3,15,15,10), Time.utc(2005,2,22,15,15,10).advance(:years => 7, :months => 19, :days => 11) + end + def test_next_week assert_equal Time.local(2005,2,28), Time.local(2005,2,22,15,15,10).next_week assert_equal Time.local(2005,2,29), Time.local(2005,2,22,15,15,10).next_week(:tuesday) -- cgit v1.2.3