diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 0d69633..909d5b8 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -2636,8 +2636,17 @@ offset_to_sec(VALUE vof, int *rof) VALUE vs = date_zone_to_diff(vof); long n; - if (!FIXNUM_P(vs)) - return 0; + if (!FIXNUM_P(vs)) { + VALUE vr; + if (!k_rational_p(vs)) + return 0; + vr = f_round(vs); + if (!f_eqeq_p(vr, vs)) + rb_warning("fraction of offset is ignored"); + if (!FIXNUM_P(vr)) + return 0; + vs = vr; + } n = FIX2LONG(vs); if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) return 0; diff --git a/test/date/test_date_new.rb b/test/date/test_date_new.rb index b839c52..1d65a3b 100644 --- a/test/date/test_date_new.rb +++ b/test/date/test_date_new.rb @@ -213,6 +213,32 @@ def test_civil__offset assert_equal(0, d.offset) end + def test_civil__string_fractional_offset + # A fractional-hour zone with more than two digits yields a Rational from + # date_zone_to_diff; it must be rounded with a warning, the way the Float + # and Rational forms of the same quantity already are. + d = nil + assert_warning(/fraction of offset/) do + d = DateTime.civil(2001,2,3, 0,0,0, '+00.123') # 442.8 seconds + end + assert_equal(443, (d.offset * 86400).to_i) + assert_equal(DateTime.civil(2001,2,3, 0,0,0, 442.8/86400).offset, d.offset) + assert_equal(DateTime.civil(2001,2,3, 0,0,0, Rational(2214, 5*86400)).offset, d.offset) + + assert_warning(/fraction of offset/) do + d = DateTime.civil(2001,2,3, 0,0,0, '-00.123') + end + assert_equal(-443, (d.offset * 86400).to_i) + + # Zones that are already an integral number of seconds are unaffected. + assert_equal(5400, (DateTime.civil(2001,2,3, 0,0,0, '+01.5').offset * 86400).to_i) + assert_equal(86399, (DateTime.civil(2001,2,3, 0,0,0, '+23:59:59').offset * 86400).to_i) + + # Not a widening: a zone that date_zone_to_diff rejects stays rejected. + assert_equal(0, DateTime.civil(2001,2,3, 0,0,0, '+24:00').offset) + assert_equal(0, DateTime.civil(2001,2,3, 0,0,0, '+99:00').offset) + end + def test_civil__reform d = Date.jd(Date::ENGLAND, Date::ENGLAND) dt = DateTime.jd(Date::ENGLAND, 0,0,0,0, Date::ENGLAND)