diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 45c136c..a79ed87 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -2129,6 +2129,19 @@ jd_to_nth_kday(VALUE jd, double sg, } #endif +inline static int +gregorian_end_of_period_p(int y) +{ + return (y + 4712 + 1) == CM_PERIOD_GCY; +} + +inline static void +increment_period(VALUE *nth, int *ry) +{ + *nth = f_add(*nth, INT2FIX(1)); + *ry -= CM_PERIOD_GCY; +} + static int valid_ordinal_p(VALUE y, int d, double sg, VALUE *nth, int *ry, @@ -2154,17 +2167,28 @@ valid_ordinal_p(VALUE y, int d, double sg, } else { decode_year(y, style, nth, ry); + if ((d > 327) && gregorian_end_of_period_p(*ry)) + increment_period(nth, ry); r = c_valid_ordinal_p(*ry, d, style, rd, rjd, ns); } return r; } +inline static void +ensure_gregorian_civil_period(VALUE *nth, int *ry, int m, int d) +{ + if ((m == 12 || (m == 11 && d > 23)) && gregorian_end_of_period_p(*ry)) { + increment_period(nth, ry); + } +} + static int valid_gregorian_p(VALUE y, int m, int d, VALUE *nth, int *ry, int *rm, int *rd) { decode_year(y, -1, nth, ry); + ensure_gregorian_civil_period(nth, ry, m, d); return c_valid_gregorian_p(*ry, m, d, rm, rd); } @@ -2193,8 +2217,10 @@ valid_civil_p(VALUE y, int m, int d, double sg, } else { decode_year(y, style, nth, ry); - if (style < 0) + if (style < 0) { + ensure_gregorian_civil_period(nth, ry, m, d); r = c_valid_gregorian_p(*ry, m, d, rm, rd); + } else r = c_valid_julian_p(*ry, m, d, rm, rd); if (!r) @@ -2229,6 +2255,8 @@ valid_commercial_p(VALUE y, int w, int d, double sg, } else { decode_year(y, style, nth, ry); + if ((w > 47) && gregorian_end_of_period_p(*ry)) + increment_period(nth, ry); r = c_valid_commercial_p(*ry, w, d, style, rw, rd, rjd, ns); } return r; @@ -3617,6 +3645,7 @@ date_s_today(int argc, VALUE *argv, VALUE klass) d = tm.tm_mday; decode_year(INT2FIX(y), -1, &nth, &ry); + ensure_gregorian_civil_period(&nth, &ry, m, d); ret = d_simple_new_internal(klass, nth, 0, @@ -7811,6 +7840,7 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass) } decode_year(INT2FIX(y), -1, &nth, &ry); + ensure_gregorian_civil_period(&nth, &ry, m, d); ret = d_complex_new_internal(klass, nth, 0, @@ -8541,6 +8571,7 @@ time_to_date(VALUE self) d = FIX2INT(f_mday(self)); decode_year(y, -1, &nth, &ry); + ensure_gregorian_civil_period(&nth, &ry, m, d); ret = d_simple_new_internal(cDate, nth, 0, @@ -8580,6 +8611,7 @@ time_to_datetime(VALUE self) of = FIX2INT(f_utc_offset(self)); decode_year(y, -1, &nth, &ry); + ensure_gregorian_civil_period(&nth, &ry, m, d); ret = d_complex_new_internal(cDateTime, nth, 0, diff --git a/test/date/test_date_arith.rb b/test/date/test_date_arith.rb index 745ddbd..53aa4ea 100644 --- a/test/date/test_date_arith.rb +++ b/test/date/test_date_arith.rb @@ -80,6 +80,10 @@ class TestDateArith < Test::Unit::TestCase Date.new(2001,1,17, Date::GREGORIAN))) assert_equal(0, (DateTime.new(2001,1,4,0,0,0,0,Date::JULIAN) <=> DateTime.new(2001,1,17,0,0,0,0,Date::GREGORIAN))) + + assert_equal(0, (Date.jd(0) <=> Date.civil(-4713, 11, 24, Date::GREGORIAN))) + assert_equal(0, (Date.jd(213447717) <=> Date.civil(579687, 11, 24))) + assert_equal(0, (Date.jd(-213447717) <=> Date.civil(-589113, 11, 24, Date::GREGORIAN))) end def test_prev