From: Nobuyoshi Nakada Date: 2010-01-14T13:01:18+09:00 Subject: [ruby-dev:40075] Re: [BUG] marshaling Time.utc_offset なかだです。 At Wed, 13 Jan 2010 20:03:30 +0900, Tanaka Akira wrote in [ruby-dev:40066]: > > ちなみにutc_offsetはRationalを想定しているようですが、分未満の時 > > 差を持つタイムゾーンというのは実際にあり得るんでしょうか。 > > % zdump -v Europe/Lisbon|head -1 > Europe/Lisbon Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 20:09:20 1901 > LMT isdst=0 gmtoff=-2192 > % TZ=Europe/Lisbon ruby -e 'p Time.local(1902).utc_offset' > -2192 > > 昔は各都市ごとに決めていたのだろう、と想像しています。 二三十秒くらい適当に合わせちゃえばよかったのに。 さすがに秒未満のタイムゾーンはないですよね。 Index: time.c =================================================================== --- time.c (revision 26324) +++ time.c (working copy) @@ -104,5 +104,5 @@ rb_localtime(const time_t *tm, struct tm #endif -static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den; +static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset; static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift; @@ -1840,4 +1840,6 @@ validate_utc_offset(VALUE utc_offset) if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400))) rb_raise(rb_eArgError, "utc_offset out of range"); + if (!rb_equal(mod(utc_offset, INT2FIX(1)), INT2FIX(0))) + rb_raise(rb_eArgError, "utc_offset not in seconds"); } @@ -3676,4 +3678,8 @@ time_mdump(VALUE time) rb_ivar_set(str, id_submicro, rb_str_new(buf, len)); } + if (!TIME_UTC_P(tobj)) { + VALUE min = rb_Integer(time_utc_offset(time)); + rb_ivar_set(str, id_offset, min); + } return str; } @@ -3712,5 +3718,5 @@ time_mload(VALUE time, VALUE str) int i, gmt; long nsec; - VALUE timexv, submicro, nano_num, nano_den; + VALUE timexv, submicro, nano_num, nano_den, offset; time_modify(time); @@ -3728,4 +3734,9 @@ time_mload(VALUE time, VALUE str) st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_submicro, 0); } + offset = rb_attr_get(str, id_offset); + if (offset != Qnil) { + validate_utc_offset(offset); + st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_offset, 0); + } rb_copy_generic_ivar(time, str); @@ -3746,4 +3757,5 @@ time_mload(VALUE time, VALUE str) if ((p & (1UL<<31)) == 0) { gmt = 0; + offset = Qnil; sec = p; usec = s; @@ -3798,6 +3810,12 @@ end_submicro: ; GetTimeval(time, tobj); tobj->tm_got = 0; - if (gmt) TIME_SET_UTC(tobj); tobj->timexv = timexv; + if (gmt) { + TIME_SET_UTC(tobj); + } + else if (!NIL_P(offset)) { + time_set_utc_offset(time, offset); + time_fixoff(time); + } return time; @@ -3854,4 +3872,5 @@ Init_Time(void) id_nano_num = rb_intern("nano_num"); id_nano_den = rb_intern("nano_den"); + id_offset = rb_intern("offset"); rb_cTime = rb_define_class("Time", rb_cObject); Index: test/ruby/test_time.rb =================================================================== --- test/ruby/test_time.rb (revision 26324) +++ test/ruby/test_time.rb (working copy) @@ -204,4 +204,16 @@ class TestTime < Test::Unit::TestCase end + def test_marshal_timezone + t1 = Time.gm(2000) + m = Marshal.dump(t1.getlocal("-02:00")) + t2 = Marshal.load(m) + assert_equal(t1, t2) + assert_equal(-7200, t2.utc_offset) + m = Marshal.dump(t1.getlocal("+08:15")) + t2 = Marshal.load(m) + assert_equal(t1, t2) + assert_equal(29700, t2.utc_offset) + end + # Sat Jan 01 00:00:00 UTC 2000 T2000 = Time.at(946684800).gmtime -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦