ruby-changes:53757
From: naruse <ko1@a...>
Date: Mon, 26 Nov 2018 01:23:34 +0900 (JST)
Subject: [ruby-changes:53757] naruse:r65974 (trunk): Normalize month-mday before finding epoch
naruse 2018-11-26 01:23:18 +0900 (Mon, 26 Nov 2018) New Revision: 65974 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65974 Log: Normalize month-mday before finding epoch Especially over the year 2038, 30 Feb and so on may cause odd behavior on validating found epoch with given year-month-day [Bug #15340] Modified files: trunk/test/ruby/test_time.rb trunk/time.c Index: time.c =================================================================== --- time.c (revision 65973) +++ time.c (revision 65974) @@ -2876,6 +2876,29 @@ time_arg(int argc, const VALUE *argv, st https://github.com/ruby/ruby/blob/trunk/time.c#L2876 vtm->mday = obj2ubits(v[2], 5); } + /* normalize month-mday */ + switch (vtm->mon) { + case 2: + { + /* this drops higher bits but it's not a problem to calc leap year */ + unsigned int mday2 = leap_year_v_p(vtm->year) ? 29 : 28; + if (vtm->mday > mday2) { + vtm->mday -= mday2; + vtm->mon++; + } + } + break; + case 4: + case 6: + case 9: + case 11: + if (vtm->mday == 31) { + vtm->mon++; + vtm->mday = 1; + } + break; + } + vtm->hour = NIL_P(v[3])?0:obj2ubits(v[3], 5); vtm->min = NIL_P(v[4])?0:obj2ubits(v[4], 6); Index: test/ruby/test_time.rb =================================================================== --- test/ruby/test_time.rb (revision 65973) +++ test/ruby/test_time.rb (revision 65974) @@ -1056,6 +1056,29 @@ class TestTime < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_time.rb#L1056 assert_equal(min, t.min) assert_equal(sec, t.sec) } + assert_equal(Time.local(2038,3,1), Time.local(2038,2,29)) + assert_equal(Time.local(2038,3,2), Time.local(2038,2,30)) + assert_equal(Time.local(2038,3,3), Time.local(2038,2,31)) + assert_equal(Time.local(2040,2,29), Time.local(2040,2,29)) + assert_equal(Time.local(2040,3,1), Time.local(2040,2,30)) + assert_equal(Time.local(2040,3,2), Time.local(2040,2,31)) + n = 2 ** 64 + n += 400 - n % 400 # n is over 2^64 and multiple of 400 + assert_equal(Time.local(n,2,29),Time.local(n,2,29)) + assert_equal(Time.local(n,3,1), Time.local(n,2,30)) + assert_equal(Time.local(n,3,2), Time.local(n,2,31)) + n += 100 + assert_equal(Time.local(n,3,1), Time.local(n,2,29)) + assert_equal(Time.local(n,3,2), Time.local(n,2,30)) + assert_equal(Time.local(n,3,3), Time.local(n,2,31)) + n += 4 + assert_equal(Time.local(n,2,29),Time.local(n,2,29)) + assert_equal(Time.local(n,3,1), Time.local(n,2,30)) + assert_equal(Time.local(n,3,2), Time.local(n,2,31)) + n += 1 + assert_equal(Time.local(n,3,1), Time.local(n,2,29)) + assert_equal(Time.local(n,3,2), Time.local(n,2,30)) + assert_equal(Time.local(n,3,3), Time.local(n,2,31)) end def test_future -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/