[BUG] marshaling Time.utc_offset

e$B$J$+$@$G$9!#e(B

Marshale$B$Ge(BTimee$B$Ne(Butc_offsete$B$,J]B8$5$l$^$;$s!#e(B

$ ./ruby -v -e ‘p t=Time.now.localtime("-05:00"); p t.utc_offset; p
t=Marshal.load(Marshal.dump(t)); p t.utc_offset’
ruby 1.9.2dev (2010-01-13 trunk 26311) [universal.x86_64-darwin9.8.0]
2010-01-12 23:17:02 -0500
-18000
2010-01-13 13:17:02 +0900
32400

utc_offsete$B$rJ,C10L$Ge(Bdumpe$B$5$;$k%Q%C%A$G$9!#e(B

e$B$A$J$_$Ke(Butc_offsete$B$Oe(BRationale$B$rA[Dj$7$F$$$k$h$&$G$9$,!“J,L$K~$N;~e(B
e$B:9$r;}$D%?%$%`%>!<%s$H$$$&$N$O<B:]$K$”$jF@$k$s$G$7$g$&$+!#e(B

Index: time.c

— time.c (revision 26311)
+++ 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_subnano;
+static ID id_divmod, id_mul, id_submicro, id_subnano, id_offset;
static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;

@@ -1826,4 +1826,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(60)), INT2FIX(0)))
  • rb_raise(rb_eArgError, “utc_offset not in minutes”);
    }

@@ -3648,4 +3650,8 @@ time_mdump(VALUE time)
rb_ivar_set(str, id_subnano, subnano);
}

  • if (!TIME_UTC_P(tobj)) {
  • VALUE min = rb_Integer(rb_funcall(time_utc_offset(time),
    rb_intern(“div”), 1, INT2FIX(60)));
  • rb_ivar_set(str, id_offset, min);
  • }
    return str;
    }
    @@ -3684,5 +3690,5 @@ time_mload(VALUE time, VALUE str)
    int i, gmt;
    long nsec;
  • VALUE timexv, submicro, subnano;
  • VALUE timexv, submicro, subnano, offset;

    time_modify(time);
    @@ -3696,4 +3702,10 @@ time_mload(VALUE time, VALUE str)
    st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_subnano,
    0);
    }

  • offset = rb_attr_get(str, id_offset);

  • if (offset != Qnil) {

  •    offset = mul(offset, INT2FIX(60));
    
  •    validate_utc_offset(offset);
    
  •    st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_offset, 
    

0);

  • }
    rb_copy_generic_ivar(time, str);

@@ -3713,4 +3725,5 @@ time_mload(VALUE time, VALUE str)

 if ((p & (1UL<<31)) == 0) {
  • offset = Qnil;
    gmt = 0;
    sec = p;
    @@ -3766,6 +3779,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;
    @@ -3821,4 +3840,5 @@ Init_Time(void)
    id_submicro = rb_intern(“submicro”);
    id_subnano = rb_intern(“subnano”);

  • id_offset = rb_intern(“offset”);

    rb_cTime = rb_define_class(“Time”, rb_cObject);

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:40063] [BUG] marshaling Time.utc_offset”
on Wed, 13 Jan 2010 13:27:51 +0900, Nobuyoshi N.
[email protected] writes:

|Marshale$B$Ge(BTimee$B$Ne(Butc_offsete$B$,J]B8$5$l$^$;$s!#e(B

e$B?75!G=DI2C$K$O8+Mn$H$7$,$D$-$^$H$$$^$9$M!#e(B

|$ ./ruby -v -e ‘p t=Time.now.localtime(“-05:00”); p t.utc_offset; p t=Marshal.load(Marshal.dump(t)); p t.utc_offset’
|ruby 1.9.2dev (2010-01-13 trunk 26311) [universal.x86_64-darwin9.8.0]
|2010-01-12 23:17:02 -0500
|-18000
|2010-01-13 13:17:02 +0900
|32400
|
|utc_offsete$B$rJ,C10L$Ge(Bdumpe$B$5$;$k%Q%C%A$G$9!#e(B
|
|e$B$A$J$_$Ke(Butc_offsete$B$Oe(BRationale$B$rA[Dj$7$F$$$k$h$&$G$9$,!“J,L$K~$N;~e(B
|e$B:9$r;}$D%?%$%`%>!<%s$H$$$&$N$O<B:]$K$”$jF@$k$s$G$7$g$&$+!#e(B

e$B$&!<$s!“e(B30e$BJ,$:$l$F$k$H$3$m$O$”$k$_$?$$$G$9$1$I!"J,L$K~$C$F!#e(B

2010e$BG/e(B1e$B7ne(B13e$BF|e(B13:27 Nobuyoshi N.
[email protected]:

utc_offsete$B$rJ,C10L$Ge(Bdumpe$B$5$;$k%Q%C%A$G$9!#e(B

e$B$A$J$_$Ke(Butc_offsete$B$Oe(BRationale$B$rA[Dj$7$F$$$k$h$&$G$9$,!“J,L$K~$N;~e(B
e$B:9$r;}$D%?%$%`%>!<%s$H$$$&$N$O<B:]$K$”$jF@$k$s$G$7$g$&$+!#e(B

% 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

e$B@N$O3FET;T$4$H$K7h$a$F$$$?$N$@$m$&!"$HA[A|$7$F$$$^$9!#e(B

e$B$J$+$@$G$9!#e(B

At Wed, 13 Jan 2010 20:03:30 +0900,
Tanaka A. wrote in [ruby-dev:40066]:

e$B$A$J$_$Ke(Butc_offsete$B$Oe(BRationale$B$rA[Dj$7$F$$$k$h$&$G$9$,!“J,L$K~$N;~e(B
e$B:9$r;}$D%?%$%`%>!<%s$H$$$&$N$O<B:]$K$”$jF@$k$s$G$7$g$&$+!#e(B

% 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

e$B@N$O3FET;T$4$H$K7h$a$F$$$?$N$@$m$&!"$HA[A|$7$F$$$^$9!#e(B

e$BFs;0==IC$/$i$$E,Ev$K9g$o$;$A$c$($P$h$+$C$?$N$K!#e(B
e$B$5$9$,$KICL$K~$N%?%$%`%>!<%s$O$J$$$G$9$h$M!#e(B

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

2010e$BG/e(B1e$B7ne(B14e$BF|e(B13:01 Nobuyoshi N.
[email protected]:

e$BFs;0==IC$/$i$$E,Ev$K9g$o$;$A$c$($P$h$+$C$?$N$K!#e(B
e$B$5$9$,$KICL$K~$N%?%$%`%>!<%s$O$J$$$G$9$h$M!#e(B

e$B$D$/$l$P$"$k$b$s!#e(B

% ./ruby -e ‘p Time.new(2000,1,1,0,0,0, Rational(1,3)).utc_offset’
(1/3)

e$B;~:9$Ne(B1e$BIC$O@VF;>e$GLse(B463m
e$B$J$N$G!"$=$l$h$j:Y$+$/0LCV$rI=8=$7$?$$$+$I$&$+e(B
e$B$G$7$g$&$+!#e(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:40079] Re: [BUG] marshaling Time.utc_offset”
on Thu, 14 Jan 2010 14:54:13 +0900, Urabe S.
[email protected] writes:

|>> e$B$5$9$,$KICL$K~$N%?%$%`%>!<%s$O$J$$$G$9$h$M!#e(B
|>
|> e$B$D$/$l$P$"$k$b$s!#e(B
|
|e$B$=$N:n$l$F$7$^$&$H$$$&e(BRubye$BB&$Ne(BAPIe$B$N@'Hs$K$D$$$FLd$&$F$$$k$N$@$H;W$$$^$9$,e(B?

e$B%?%$%`%>!<%s$NJ,2rG=$K$D$$$F$N:,5r$H$J$k5,3J$J$jJ8=q$J$j$,B8e(B
e$B:_$9$k$+$I$&$+CN$i$J$$$N$G$9$,!“$”$l$P$=$l$K=>$($P$h$$$G$9$7!“e(B
e$B$J$1$l$P@'Hs$rLd$&$3$H$O$G$-$J$$$N$G!”$J$K$+LdBj$,$"$k$N$G$Je(B
e$B$1$l$P!"8=>u$N$^$^$G$h$$$N$G$J$$$G$7$g$&$+!#e(B

e$B$“$k$s$G$9$+$M!”:,5r$K$7$F$b!"LdBj$K$7$F$b!#e(B

e$BLdBj$H8@$($P!“e(B1.8e$B$H$N$d$j$H$j$G@0?t$NJ}$,$h$$$H8@$&$N$O$”$k$+!#e(B

Tanaka A. さんは書きました:

2010å¹´1月14æ—¥13:01 Nobuyoshi N. [email protected]:

二三十秒くらい適当に合わせちゃえばよかったのに。
さすがに秒未満のタイムゾーンはないですよね。

つくればあるもん。

その作れてしまうというRuby側のAPIの是非について問うているのだと思いますが?

2010e$BG/e(B1e$B7ne(B14e$BF|e(B14:54 Urabe S.
[email protected]:

e$B$=$N:n$l$F$7$^$&$H$$$&e(BRubye$BB&$Ne(BAPIe$B$N@'Hs$K$D$$$FLd$&$F$$$k$N$@$H;W$$$^$9$,e(B?

e$B@h$N%a!<%k$GLse(B483m
e$B0J2<$N0c$$$rI=8=$G$-$J$/$J$k$H$$$&LdBj$r=R$Y!“e(B
e$B$=$l$,I,MW$G$”$k$+$I$&$+$rLd$$$+$1$^$7$?!#e(B

e$B$^$?!“e(BDateTime e$B$H$NAj8_JQ49$NLdBj$,$”$j$^$9$M!#e(B

% ruby -rdate -e ‘p
DateTime.new(2000,1,1,0,0,0,Rational(1,3243600)).offset’
(1/259200)

Time e$B$@$1$Ge(B
1e$BIC$rC10L$K$9$l$P!"Aj8_JQ49$G>pJs$,Mn$A$k$3$H$K$J$j$^$9!#e(B

e$B$J$+$@$G$9!#e(B

At Thu, 14 Jan 2010 15:13:53 +0900,
Tanaka A. wrote in [ruby-dev:40081]:

e$B@h$N%a!<%k$GLse(B483m e$B0J2<$N0c$$$rI=8=$G$-$J$/$J$k$H$$$&LdBj$r=R$Y!“e(B
e$B$=$l$,I,MW$G$”$k$+$I$&$+$rLd$$$+$1$^$7$?!#e(B

e$B%?%$%`%>!<%s$H$$$&$b$N$OJM}E$J0LCV$rI=8=$9$k$?$a$N$b$N$G$O$J$/!“e(B
e$B$”$/$^$G@)EYE*$J<h$j7h$a$H$7$F;H$o$l$F$$$k$3$H$+$i$9$l$P!"ITMW$Ge(B
e$B$O$J$$$+$H;W$$$^$9!#e(B

e$B$^$?!“e(BDateTime e$B$H$NAj8_JQ49$NLdBj$,$”$j$^$9$M!#e(B

% ruby -rdate -e ‘p DateTime.new(2000,1,1,0,0,0,Rational(1,3243600)).offset’
(1/259200)

Time e$B$@$1$Ge(B 1e$BIC$rC10L$K$9$l$P!"Aj8_JQ49$G>pJs$,Mn$A$k$3$H$K$J$j$^$9!#e(B

e$B$H$j$"$($:!#e(B

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;

@@ -3676,4 +3676,11 @@ time_mdump(VALUE time)
rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
}

  • if (!TIME_UTC_P(tobj)) {
  • VALUE off = time_utc_offset(time), div, mod;
  • divmodv(off, INT2FIX(1), &div, &mod);
  • if (rb_equal(mod, INT2FIX(0)))
  •  off = rb_Integer(div);
    
  • rb_ivar_set(str, id_offset, off);
  • }
    return str;
    }
    @@ -3712,5 +3719,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 +3735,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 +3758,5 @@ time_mload(VALUE time, VALUE str)
if ((p & (1UL<<31)) == 0) {
gmt = 0;

  • offset = Qnil;
    sec = p;
    usec = s;
    @@ -3798,6 +3811,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 +3873,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);

2010e$BG/e(B1e$B7ne(B14e$BF|e(B15:12 Yukihiro M.
[email protected]:

e$BLdBj$H8@$($P!“e(B1.8e$B$H$N$d$j$H$j$G@0?t$NJ}$,$h$$$H8@$&$N$O$”$k$+!#e(B

Rational e$B$Oe(B 1.8 - 1.9 e$B4V$Ge(B marshal
e$B$G$-$^$;$s$+$i$M$'!#e(B

% ./ruby -e ‘Marshal.dump(Rational(1,2), STDOUT)’|ruby-1.8 -rrational
-e ‘p Marshal.load(STDIN)’
-e:1:in load': instance of Rational needs to have method marshal_load’ (TypeError)
from -e:1
% ruby-1.8 -rrational -e ‘Marshal.dump(Rational(1,2), STDOUT)’|./ruby
-e ‘p Marshal.load(STDIN)’
-e:1:in load': dump format error (ArgumentError) from -e:1:in

% ./ruby -v
ruby 1.9.2dev (2010-01-14 trunk 26319) [i686-linux]
% ruby-1.8 -v
ruby 1.8.8dev (2010-01-13 revision 26317) [i686-linux]

e$B%^%$%/%mICL$K~$N;~9o$OJ,;R$HJ,Jl$r5-O?$9$k$h$&$K$7$?$N$Ge(B
marshal e$B$7$?%G!<%?Fb$K$Oe(B Rational e$B$O8=$l$:!“e(B
1.8 e$B$G$OL5;k$5$l$k$@$1$K$7$F$”$j$^$9!#e(B

utc_offset
e$B$G$bAGKQ$K$d$k$HLdBj$,$*$-$^$9$,!"F1MM$NBP=h$O2DG=$G$9!#e(B

e$BK\Ev$Oe(B Rational e$B<+BN$,e(B 1.8 - 1.9 e$B4V$Ge(B marshal
e$B2DG=$@$H$$$$$s$G$9$,!#e(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:40082] Re: [BUG] marshaling Time.utc_offset”
on Thu, 14 Jan 2010 17:10:17 +0900, Nobuyoshi N.
[email protected] writes:

|e$B%?%$%`%>!<%s$H$$$&$b$N$OJM}E$J0LCV$rI=8=$9$k$?$a$N$b$N$G$O$J$/!“e(B
|e$B$”$/$^$G@)EYE*$J<h$j7h$a$H$7$F;H$o$l$F$$$k$3$H$+$i$9$l$P!"ITMW$Ge(B
|e$B$O$J$$$+$H;W$$$^$9!#e(B
|
|> e$B$^$?!“e(BDateTime e$B$H$NAj8_JQ49$NLdBj$,$”$j$^$9$M!#e(B
|>
|> % ruby -rdate -e ‘p DateTime.new(2000,1,1,0,0,0,Rational(1,3243600)).offset’
|> (1/259200)
|>
|> Time e$B$@$1$Ge(B 1e$BIC$rC10L$K$9$l$P!“Aj8_JQ49$G>pJs$,Mn$A$k$3$H$K$J$j$^$9!#e(B
|
|e$B$H$j$”$($:!#e(B

e$B$&!<$s!“ICL$K~$N%?%$%`%>!<%s%%U%;%C%H$,8=<BE$G$J$$0J>e!”>pe(B
e$BJs$,Mn$A$k$N$O8=<BE*$J%G%a%j%C%H$O$J$$$h$&$J5$$,$7$F$-$^$7$?!#e(B
e$B%3%_%C%H$7$F$/$@$5$$!#e(B