From 70e96c9f5c1bfcbb056c34fe7afe3d39226d1cc6 Mon Sep 17 00:00:00 2001 From: Jamis Buck Date: Wed, 31 Aug 2005 10:36:35 +0000 Subject: Add Time.days_in_month, and make Time#next_month work when invoked on the 31st of a month git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2082 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activesupport/CHANGELOG | 2 ++ .../active_support/core_ext/time/calculations.rb | 33 ++++++++++++++++++---- activesupport/test/core_ext/time_ext_test.rb | 24 ++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 315ea30568..b1f81fdf1b 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Add Time.days_in_month, and make Time#next_month work when invoked on the 31st of a month + * Fixed that Time#midnight would have a non-zero usec on some platforms #1836 * Fixed inflections of "index/indices" #1766 [damn_pepe@gmail.com] diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 503717f4fe..76d6d4c176 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -3,6 +3,23 @@ module ActiveSupport #:nodoc: module Time #:nodoc: # Enables the use of time calculations within Time itself module Calculations + def self.append_features(base) #:nodoc: + super + base.extend(ClassMethods) + end + + module ClassMethods + def days_in_month(month, year=nil) + if month == 2 + (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ? 29 : 28 + elsif month <= 7 + month % 2 == 0 ? 30 : 31 + else + month % 2 == 0 ? 31 : 30 + end + end + end + # Seconds since midnight: Time.now.seconds_since_midnight def seconds_since_midnight self.hour.hours + self.min.minutes + self.sec + (self.usec/1.0e+6) @@ -47,12 +64,18 @@ module ActiveSupport #:nodoc: end def months_since(months) - if months + self.month > 12 - old_time = self - change(:year => self.year + 1, :month => 1).months_since(months + old_time.month - 12 - 1) - else - change(:year => self.year, :month => self.month + months) + year, month, mday = self.year, self.month, self.mday + + month += months + while month > 12 + month -= 12 + year += 1 end + + max = ::Time.days_in_month(month, year) + mday = max if mday > max + + change(:year => year, :month => month, :mday => mday) end # Returns a new Time representing the time a number of specified years ago diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index dca810d67e..ca58cd0a8a 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -137,4 +137,28 @@ class TimeExtCalculationsTest < Test::Unit::TestCase midnight = Time.local(2005, 2, 21, 0, 0, 0) assert_equal midnight.midnight, (midnight + 1.hour + 0.000001).midnight end + + def test_days_in_month + assert_equal 31, Time.days_in_month(1, 2005) + + assert_equal 28, Time.days_in_month(2, 2005) + assert_equal 29, Time.days_in_month(2, 2004) + assert_equal 29, Time.days_in_month(2, 2000) + assert_equal 28, Time.days_in_month(2, 1900) + + assert_equal 31, Time.days_in_month(3, 2005) + assert_equal 30, Time.days_in_month(4, 2005) + assert_equal 31, Time.days_in_month(5, 2005) + assert_equal 30, Time.days_in_month(6, 2005) + assert_equal 31, Time.days_in_month(7, 2005) + assert_equal 31, Time.days_in_month(8, 2005) + assert_equal 30, Time.days_in_month(9, 2005) + assert_equal 31, Time.days_in_month(10, 2005) + assert_equal 30, Time.days_in_month(11, 2005) + assert_equal 31, Time.days_in_month(12, 2005) + end + + def test_next_month_on_31st + assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month + end end -- cgit v1.2.3