From: siena@... (Siena. / SHINAGAWA, Norihide) Date: 2004-01-18T03:21:14+09:00 Subject: [ruby-dev:22608] Time#[+-] when given a negative argument Siena. です。 せっかく CVS アカウントをいただいたのにいろいろあって動けずじまいでした。 改めて、今後とも宜しくお願い致します。 さて、ruby/test/test_time.rb が Time#- でエラーになるので直してみました。 |RangeError: time - -28800.000000 out of Time range うちは、time_t が unsigned long なので、 下記のキャストのために sec がとんでもない値になるのが原因でした。 ruby/time.c | time_t sec, usec; | double f, d, v; (略) | sec = (time_t)f; 不恰好ですが、とりあえず次のテストはこのパッチで通るようになりました。 time_t が負数を受け付ける環境でも大丈夫だとは思うのですが、 どなたか試してみていただけないでしょうか。 # ruby/test/test_time.rb require 'test/unit' class TestTime < Test::Unit::TestCase def test_time_add() assert_equal(Time.utc(2000, 3, 21, 3, 30) + 3 * 3600, Time.utc(2000, 3, 21, 6, 30)) assert_equal(Time.utc(2000, 3, 21, 3, 30) + (-3 * 3600), Time.utc(2000, 3, 21, 0, 30)) end def test_time_sub() assert_equal(Time.utc(2000, 3, 21, 3, 30) - 3 * 3600, Time.utc(2000, 3, 21, 0, 30)) assert_equal(Time.utc(2000, 3, 21, 3, 30) - (-3 * 3600), Time.utc(2000, 3, 21, 6, 30)) end def test_time_time() assert_equal(Time.utc(2000, 3, 21, 3, 30) \ -Time.utc(2000, 3, 21, 0, 30), 3 * 3600) assert_equal(Time.utc(2000, 3, 21, 0, 30) \ -Time.utc(2000, 3, 21, 3, 30), -3 * 3600) end end Index: ruby/time.c =================================================================== RCS file: /src/ruby/time.c,v retrieving revision 1.92 diff -u -p -2 -r1.92 time.c --- ruby/time.c 30 Dec 2003 16:36:05 -0000 1.92 +++ ruby/time.c 17 Jan 2004 17:51:27 -0000 @@ -1184,4 +1184,5 @@ time_plus(time1, time2) time_t sec, usec; double f, d, v; + int sign; GetTimeval(time1, tobj); @@ -1192,4 +1193,6 @@ time_plus(time1, time2) v = NUM2DBL(time2); d = modf(v, &f); + sign = ( f < 0 ? -1 : 1 ); + f *= sign; sec = (time_t)f; if (f != (double)sec) { @@ -1197,14 +1200,14 @@ time_plus(time1, time2) } #ifndef NEGATIVE_TIME_T - if (f < 0 && -f >= tobj->tv.tv_sec) { + if (sign < 0 && f >= tobj->tv.tv_sec) { rb_raise(rb_eArgError, "time must be positive"); } #endif usec = tobj->tv.tv_usec + (time_t)(d*1e6); - sec = tobj->tv.tv_sec + (time_t)f; + sec = tobj->tv.tv_sec + sign * sec; #ifdef NEGATIVE_TIME_T - if ((tobj->tv.tv_sec >= 0 && f >= 0 && sec < 0) || - (tobj->tv.tv_sec <= 0 && f <= 0 && sec > 0)) { + if ((tobj->tv.tv_sec >= 0 && sign >= 0 && sec < 0) || + (tobj->tv.tv_sec <= 0 && sign <= 0 && sec > 0)) { rb_raise(rb_eRangeError, "time + %f out of Time range", v); } @@ -1240,4 +1243,5 @@ time_minus(time1, time2) time_t sec, usec; double f, d, v; + int sign; GetTimeval(time1, tobj); @@ -1254,4 +1258,6 @@ time_minus(time1, time2) v = NUM2DBL(time2); d = modf(v, &f); + sign = ( f < 0 ? -1 : 1 ); + f *= sign; sec = (time_t)f; if (f != (double)sec) { @@ -1259,13 +1265,13 @@ time_minus(time1, time2) } #ifndef NEGATIVE_TIME_T - if (f > 0 && f >= tobj->tv.tv_sec) { + if (sign > 0 && f >= tobj->tv.tv_sec) { rb_raise(rb_eArgError, "time must be positive"); } #endif usec = tobj->tv.tv_usec - (time_t)(d*1e6); - sec = tobj->tv.tv_sec - (time_t)f; + sec = tobj->tv.tv_sec - sign * sec; #ifdef NEGATIVE_TIME_T - if ((tobj->tv.tv_sec <= 0 && f >= 0 && sec > 0) || - (tobj->tv.tv_sec >= 0 && f <= 0 && sec < 0)) { + if ((tobj->tv.tv_sec <= 0 && sign >= 0 && sec > 0) || + (tobj->tv.tv_sec >= 0 && sign <= 0 && sec < 0)) { rb_raise(rb_eRangeError, "time - %f out of Time range", v); } --- Siena.