Backports Date#>> from 1.9 so that calculations do the right thing around the calendar reform

Our next_month gives November for some late dates in September of 1582.
Related methods, last_*, and in general advance have the same issues.
This commit fixes those, see the test suite for expected behavior, which
we still run in 1.9 to ensure it matches as we do with other methods
defined in Date in 1.9.
This commit is contained in:
Xavier Noria 2010-05-09 01:20:23 +02:00
parent 605c6455ac
commit 636ffa1f08
3 changed files with 47 additions and 0 deletions

View File

@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
* Backports Date#>> from 1.9 so that calculations do the right thing around the calendar reform. [fxn]
* Date#to_time handles properly years in the range 0..138. [fxn]
* Deprecate {{}} as interpolation syntax for I18n in favor of %{} [José Valim]

View File

@ -4,6 +4,24 @@ require 'active_support/core_ext/time/zones'
require 'active_support/core_ext/object/acts_like'
class Date
if RUBY_VERSION < '1.9'
undef :>>
# Backported from 1.9. The one in 1.8 leads to incorrect next_month and
# friends for dates where the calendar reform is involved. It additionally
# prevents an infinite loop fixed in r27013.
def >>(n)
y, m = (year * 12 + (mon - 1) + n).divmod(12)
m, = (m + 1) .divmod(1)
d = mday
until jd2 = self.class.valid_civil?(y, m, d, start)
d -= 1
raise ArgumentError, 'invalid date' unless d > 0
end
self + (jd2 - jd)
end
end
class << self
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
def yesterday

View File

@ -145,6 +145,10 @@ class DateExtCalculationsTest < Test::Unit::TestCase
assert_equal Date.new(1999,2,28), Date.new(2000,2,29).last_year
end
def test_last_year_in_calendar_reform
assert_equal Date.new(1582,10,4), Date.new(1583,10,14).last_year
end
def test_next_year
assert_equal Date.new(2006,6,5), Date.new(2005,6,5).next_year
end
@ -153,16 +157,28 @@ class DateExtCalculationsTest < Test::Unit::TestCase
assert_equal Date.new(2001,2,28), Date.new(2000,2,29).next_year
end
def test_next_year_in_calendar_reform
assert_equal Date.new(1582,10,4), Date.new(1581,10,10).next_year
end
def test_yesterday
assert_equal Date.new(2005,2,21), Date.new(2005,2,22).yesterday
assert_equal Date.new(2005,2,28), Date.new(2005,3,2).yesterday.yesterday
end
def test_yesterday_in_calendar_reform
assert_equal Date.new(1582,10,4), Date.new(1582,10,15).yesterday
end
def test_tomorrow
assert_equal Date.new(2005,2,23), Date.new(2005,2,22).tomorrow
assert_equal Date.new(2005,3,2), Date.new(2005,2,28).tomorrow.tomorrow
end
def test_tomorrow_in_calendar_reform
assert_equal Date.new(1582,10,15), Date.new(1582,10,4).tomorrow
end
def test_advance
assert_equal Date.new(2006,2,28), Date.new(2005,2,28).advance(:years => 1)
assert_equal Date.new(2005,6,28), Date.new(2005,2,28).advance(:months => 4)
@ -174,6 +190,17 @@ class DateExtCalculationsTest < Test::Unit::TestCase
assert_equal Date.new(2005,2,28), Date.new(2004,2,29).advance(:years => 1) #leap day plus one year
end
def test_advance_calendar_reform
assert_equal Date.new(1582,10,15), Date.new(1582,10,4).advance(:days => 1)
assert_equal Date.new(1582,10,4), Date.new(1582,10,15).advance(:days => -1)
5.upto(14) do |day|
assert_equal Date.new(1582,10,4), Date.new(1582,9,day).advance(:months => 1)
assert_equal Date.new(1582,10,4), Date.new(1582,11,day).advance(:months => -1)
assert_equal Date.new(1582,10,4), Date.new(1581,10,day).advance(:years => 1)
assert_equal Date.new(1582,10,4), Date.new(1583,10,day).advance(:years => -1)
end
end
def test_next_week
assert_equal Date.new(2005,2,28), Date.new(2005,2,22).next_week
assert_equal Date.new(2005,3,4), Date.new(2005,2,22).next_week(:friday)