Skip to content
This repository
Browse code

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
  • Loading branch information...
commit 70e96c9f5c1bfcbb056c34fe7afe3d39226d1cc6 1 parent 2a8e338
Jamis Buck authored August 31, 2005
2  activesupport/CHANGELOG
... ...
@@ -1,5 +1,7 @@
1 1
 *SVN*
2 2
 
  3
+* Add Time.days_in_month, and make Time#next_month work when invoked on the 31st of a month
  4
+
3 5
 * Fixed that Time#midnight would have a non-zero usec on some platforms #1836
4 6
 
5 7
 * Fixed inflections of "index/indices" #1766 [damn_pepe@gmail.com]
33  activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -3,6 +3,23 @@ module CoreExtensions #:nodoc:
3 3
     module Time #:nodoc:
4 4
       # Enables the use of time calculations within Time itself
5 5
       module Calculations
  6
+        def self.append_features(base) #:nodoc:
  7
+          super
  8
+          base.extend(ClassMethods)
  9
+        end
  10
+
  11
+        module ClassMethods
  12
+          def days_in_month(month, year=nil)
  13
+            if month == 2
  14
+              (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) ?  29 : 28
  15
+            elsif month <= 7
  16
+              month % 2 == 0 ? 30 : 31
  17
+            else
  18
+              month % 2 == 0 ? 31 : 30
  19
+            end
  20
+          end
  21
+        end
  22
+
6 23
         # Seconds since midnight: Time.now.seconds_since_midnight
7 24
         def seconds_since_midnight
8 25
           self.hour.hours + self.min.minutes + self.sec + (self.usec/1.0e+6)
@@ -47,12 +64,18 @@ def months_ago(months)
47 64
         end
48 65
 
49 66
         def months_since(months)
50  
-          if months + self.month > 12
51  
-            old_time = self
52  
-            change(:year => self.year + 1, :month => 1).months_since(months + old_time.month - 12 - 1)
53  
-          else
54  
-            change(:year => self.year, :month => self.month + months)
  67
+          year, month, mday = self.year, self.month, self.mday
  68
+
  69
+          month += months
  70
+          while month > 12
  71
+            month -= 12
  72
+            year += 1
55 73
           end
  74
+
  75
+          max = ::Time.days_in_month(month, year)
  76
+          mday = max if mday > max
  77
+
  78
+          change(:year => year, :month => month, :mday => mday)
56 79
         end
57 80
 
58 81
         # Returns a new Time representing the time a number of specified years ago
24  activesupport/test/core_ext/time_ext_test.rb
@@ -137,4 +137,28 @@ def test_fp_inaccuracy_ticket_1836
137 137
     midnight = Time.local(2005, 2, 21, 0, 0, 0)
138 138
     assert_equal midnight.midnight, (midnight + 1.hour + 0.000001).midnight
139 139
   end
  140
+
  141
+  def test_days_in_month
  142
+    assert_equal 31, Time.days_in_month(1, 2005)
  143
+
  144
+    assert_equal 28, Time.days_in_month(2, 2005)
  145
+    assert_equal 29, Time.days_in_month(2, 2004)
  146
+    assert_equal 29, Time.days_in_month(2, 2000)
  147
+    assert_equal 28, Time.days_in_month(2, 1900)
  148
+
  149
+    assert_equal 31, Time.days_in_month(3, 2005)
  150
+    assert_equal 30, Time.days_in_month(4, 2005)
  151
+    assert_equal 31, Time.days_in_month(5, 2005)
  152
+    assert_equal 30, Time.days_in_month(6, 2005)
  153
+    assert_equal 31, Time.days_in_month(7, 2005)
  154
+    assert_equal 31, Time.days_in_month(8, 2005)
  155
+    assert_equal 30, Time.days_in_month(9, 2005)
  156
+    assert_equal 31, Time.days_in_month(10, 2005)
  157
+    assert_equal 30, Time.days_in_month(11, 2005)
  158
+    assert_equal 31, Time.days_in_month(12, 2005)
  159
+  end
  160
+
  161
+  def test_next_month_on_31st
  162
+    assert_equal Time.local(2005, 9, 30), Time.local(2005, 8, 31).next_month
  163
+  end
140 164
 end

0 notes on commit 70e96c9

Please sign in to comment.
Something went wrong with that request. Please try again.