From: Tanaka Akira Date: 2001-12-16T15:07:42+09:00 Subject: [ruby-dev:15462] Re: Time#utcoff In article , Tanaka Akira writes: > $B$^$?!"(Bmake_time_t $B$NJ}$OLq2p$G!"FsJ,C5:w$7$h$&$K$b=i4|>uBV$NHO0O$NC $B$G(B localtime/gmtime $B$,<:GT$9$k$N$GOC$K$J$j$^$;$s!#$?$V$s!#(B $B$3$N860x$,$o$+$j$^$7$?!#(B64bit $B$J(B time_t $B$@$H(B 32bit $B$J(B tm_year $B$,(B overflow $B$9$k$3$H$,$"$j!"$=$N>l9g(B localtime/gmtime $B$,(B NULL $B$rJV$7$^$9!#(B $B$D$^$j!"(B-(1<<32)+1900$BG/$N;O$^$j$+$i(B (1<<32)-1+1900$BG/$N=*$o$j$^$G$7$+07(B $B$($^$;$s!#$3$NN>C<$O;~:9$K$h$C$F0[$J$k$N$G!"FsJ,C5:w$N=i4|HO0O$r8GDj$9(B $B$k$3$H$,=PMh$^$;$s!#$H$$$&$o$1$G$5$-$K=R$Y$?DL$j(B($BB8:_$9$k>l9g$K$O(B) mktime/timegm $B$r;H$&$3$H$K$7$^$7$?!#(B $B$H$$$&$o$1$G5?Ld$O2r>C$7$?$N$G%Q%C%A$r$D$1$H$-$^$9!#(B $B$J$*!"(Btime_arg $B$,(B 2, 3$B7e(B year $B$r%5%]!<%H$7$F$$$kET9g>e!"@>Nq(B 0$BG/$+$i(B 38$BG/$*$h$S(B 69$BG/$+$i(B 138$BG/$O;XDj$G$-$^$;$s!#$$$C$=>C$9$+$H$b;W$C$?$N$G(B $B$9$,!"(Brb_warning $B$G$,$^$s$7$F$"$j$^$9!#(B (38$BG/$HH>C<$J$N$O(B 32bit time_t $B$G%(%i!<$K$J$kE[$O8_49@-$NLdBj$,$J$$$N(B $B$G$=$N$^$^@>Nq$H2r/$J$/$H$b$N%7%9%F%`$G$OJL$N7k2L$,=P$k(B $B$+$bCN$l$^$;$s!#(B $B$"$H!"(Bmissing/strftime.c $B$N%Q%C%A$O(B (1<<32) $B0J>e$NG/$r@5$7$/07$&$?$a$N(B $B$b$N$G$9!#(Bgawk-3.1.0 $B$d(B glibc $B$N$K$bF1MM$JLdBj$,;D$C$F$$$^$7$?!#Js9p$O(B $B$7$F$*$-$^$7$?$,!#(B # tzcode $B$bF1MM$JLdBj$,$"$j$^$7$?$,!"(BLinux $B$G%F%9%H$7$FJs9p$9$k$N$b2?(B # $B$J$N$G$3$C$A$O$J$K$b$7$F$J$$!#(B > > gmtoff$B$C$F$N$O(Bstruct tm$B$N%a%s%P$K$b$"$j$^$9$7!"(Bgmt$B$r(Butc$B$KCV(B > > $B$-49$($k$C$F$N$O(BTime$B%/%i%9$N$[$+$N%a%=%C%I$G$b9-$/9T$C$F$$$k(B > > $B$N$G<+A3$J7P0^$@$H;W$&$N$G$9$,!"(Butcoff$B$C$FL>A0$O$J$<$3$s$J$K(B > > $B0cOB46$,$"$k$s$G$7$g$&!)(B $B$o$?$7$@$1!)(B $B$3$l$O(B utc_offset, gmt_offset, gmtoff $B$K$7$^$7$?!#(B Index: time.c =================================================================== RCS file: /src/ruby/time.c,v retrieving revision 1.47 diff -u -r1.47 time.c --- time.c 2001/12/13 08:19:07 1.47 +++ time.c 2001/12/16 05:40:17 @@ -173,7 +173,7 @@ VALUE time, t; if (rb_scan_args(argc, argv, "11", &time, &t) == 2) { - tv.tv_sec = NUM2INT(time); + tv.tv_sec = NUM2LONG(time); tv.tv_usec = NUM2INT(t); } else { @@ -215,6 +215,7 @@ { VALUE v[7]; int i; + long year; MEMZERO(tm, struct tm, 1); if (argc == 10) { @@ -230,11 +231,23 @@ else { rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]); *usec = (argc == 7) ? NUM2INT(v[6]) : 0; + tm->tm_isdst = -1; } - tm->tm_year = obj2long(v[0]); - if (0 <= tm->tm_year && tm->tm_year < 69) tm->tm_year += 100; - if (tm->tm_year >= 1900) tm->tm_year -= 1900; + year = obj2long(v[0]); + + if (0 <= year && year < 39) { + year += 2000; + rb_warning("2 digits year is used"); + } + else if (69 <= year && year < 139) { + year += 1900; + rb_warning("2 or 3 digits year is used"); + } + + year -= 1900; + tm->tm_year = year; + if (NIL_P(v[1])) { tm->tm_mon = 0; } @@ -270,6 +283,7 @@ /* value validation */ if ( + tm->tm_year != year || #ifndef NEGATIVE_TIME_T tm->tm_year < 69 || #endif @@ -307,7 +321,7 @@ } static time_t -make_time_t(tptr, utc_p) +search_time_t(tptr, utc_p) struct tm *tptr; int utc_p; { @@ -316,10 +330,10 @@ int d, have_guess; int find_dst; - find_dst = 1; + find_dst = 0 < tptr->tm_isdst; #ifdef NEGATIVE_TIME_T - guess_lo = 1 << (8 * sizeof(time_t) - 1); + guess_lo = 1L << (8 * sizeof(time_t) - 1); #else guess_lo = 0; #endif @@ -536,6 +550,35 @@ return 0; /* not reached */ } +static time_t +make_time_t(tptr, utc_p) + struct tm *tptr; + int utc_p; +{ + time_t t; + struct tm *tmp, buf; + buf = *tptr; + if (utc_p) { +#if defined(HAVE_TIMEGM) + t = timegm(&buf); + if (t == -1) +#endif + t = search_time_t(&buf, utc_p); + if (!(tmp = gmtime(&t))) + rb_raise(rb_eArgError, "gmtime error"); + } + else { +#if defined(HAVE_MKTIME) + t = mktime(&buf); + if (t == -1) +#endif + t = search_time_t(&buf, utc_p); + if (!(tmp = localtime(&t))) + rb_raise(rb_eArgError, "localtime error"); + } + return t; +} + static VALUE time_utc_or_local(argc, argv, utc_p, klass) int argc; @@ -578,7 +621,7 @@ struct time_object *tobj; GetTimeval(time, tobj); - return INT2NUM(tobj->tv.tv_sec); + return LONG2NUM(tobj->tv.tv_sec); } static VALUE @@ -746,6 +789,8 @@ } t = tobj->tv.tv_sec; tm_tmp = localtime(&t); + if (!tm_tmp) + rb_raise(rb_eArgError, "localtime error"); tobj->tm = *tm_tmp; tobj->tm_got = 1; tobj->gmt = 0; @@ -770,6 +815,8 @@ } t = tobj->tv.tv_sec; tm_tmp = gmtime(&t); + if (!tm_tmp) + rb_raise(rb_eArgError, "gmtime error"); tobj->tm = *tm_tmp; tobj->tm_got = 1; tobj->gmt = 1; @@ -1002,7 +1049,7 @@ if (tobj->tm_got == 0) { time_get_tm(time, tobj->gmt); } - return INT2FIX(tobj->tm.tm_year+1900); + return LONG2NUM((long)tobj->tm.tm_year+1900); } static VALUE @@ -1071,6 +1118,48 @@ } static VALUE +time_utc_offset(time) + VALUE time; +{ + struct time_object *tobj; + + GetTimeval(time, tobj); + if (tobj->tm_got == 0) { + time_get_tm(time, tobj->gmt); + } + + if (tobj->gmt == 1) { + return INT2FIX(0); + } + else { +#if defined(HAVE_STRUCT_TM_TM_GMTOFF) + return INT2NUM(tobj->tm.tm_gmtoff); +#else + struct tm *u, *l; + time_t t; + int off; + l = &tobj->tm; + t = tobj->tv.tv_sec; + u = gmtime(&t); + if (!u) + rb_raise(rb_eArgError, "gmtime error"); + if (l->tm_year != u->tm_year) + off = l->tm_year < u->tm_year ? -1 : 1; + else if (l->tm_mon != u->tm_mon) + off = l->tm_mon < u->tm_mon ? -1 : 1; + else if (l->tm_mday != u->tm_mday) + off = l->tm_mday < u->tm_mday ? -1 : 1; + else + off = 0; + off = off * 24 + l->tm_hour - u->tm_hour; + off = off * 60 + l->tm_min - u->tm_min; + off = off * 60 + l->tm_sec - u->tm_sec; + return INT2FIX(off); +#endif + } +} + +static VALUE time_to_a(time) VALUE time; { @@ -1086,7 +1175,7 @@ INT2FIX(tobj->tm.tm_hour), INT2FIX(tobj->tm.tm_mday), INT2FIX(tobj->tm.tm_mon+1), - INT2FIX(tobj->tm.tm_year+1900), + LONG2NUM((long)tobj->tm.tm_year+1900), INT2FIX(tobj->tm.tm_wday), INT2FIX(tobj->tm.tm_yday+1), tobj->tm.tm_isdst?Qtrue:Qfalse, @@ -1200,6 +1289,9 @@ t = tobj->tv.tv_sec; tm = gmtime(&t); + if ((tm->tm_year & 0x1ffff) != tm->tm_year) + rb_raise(rb_eArgError, "too big year to marshal"); + p = 0x1 << 31 | /* 1 */ tm->tm_year << 14 | /* 17 */ tm->tm_mon << 10 | /* 4 */ @@ -1255,8 +1347,9 @@ tm.tm_hour = p & 0x1f; tm.tm_min = (s >> 26) & 0x3f; tm.tm_sec = (s >> 20) & 0x3f; + tm.tm_isdst = 0; - sec = make_time_t(&tm, gmtime); + sec = make_time_t(&tm, Qtrue); usec = (time_t) s & 0xfffff; return time_new_internal(klass, sec, usec); @@ -1315,6 +1408,9 @@ rb_define_method(rb_cTime, "isdst", time_isdst, 0); rb_define_method(rb_cTime, "dst?", time_isdst, 0); rb_define_method(rb_cTime, "zone", time_zone, 0); + rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0); + rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0); + rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0); rb_define_method(rb_cTime, "utc?", time_utc_p, 0); rb_define_method(rb_cTime, "gmt?", time_utc_p, 0); Index: configure.in =================================================================== RCS file: /src/ruby/configure.in,v retrieving revision 1.103 diff -u -r1.103 configure.in --- configure.in 2001/12/03 09:38:35 1.103 +++ configure.in 2001/12/16 05:40:20 @@ -300,8 +300,17 @@ setitimer setruid seteuid setreuid setresuid setproctitle\ setrgid setegid setregid setresgid pause lchown lchmod\ getpgrp setpgrp getpgid setpgid getgroups getpriority getrlimit\ - dlopen sigprocmask sigaction _setjmp setsid telldir seekdir fchmod) + dlopen sigprocmask sigaction _setjmp setsid telldir seekdir fchmod\ + mktime timegm) AC_STRUCT_TIMEZONE +AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff, + [AC_TRY_COMPILE([#include ], + [struct tm t; t.tm_gmtoff = 3600;], + [rb_cv_member_struct_tm_tm_gmtoff=yes], + [rb_cv_member_struct_tm_tm_gmtoff=no])]) +if test "$rb_cv_member_struct_tm_tm_gmtoff" = yes; then + AC_DEFINE(HAVE_STRUCT_TM_TM_GMTOFF) +fi AC_CACHE_CHECK(for external int daylight, rb_cv_have_daylight, [AC_TRY_LINK([#include int i;], @@ -337,7 +346,7 @@ struct tm *tm; check(gmtime(&t), 69, 12, 31, 23, 59); - t = -0x80000000; + t = ~(time_t)0 << 31; check(gmtime(&t), 1, 12, 13, 20, 52); return 0; } Index: missing/strftime.c =================================================================== RCS file: /src/ruby/missing/strftime.c,v retrieving revision 1.4 diff -u -r1.4 strftime.c --- missing/strftime.c 2001/01/15 07:01:00 1.4 +++ missing/strftime.c 2001/12/16 05:40:23 @@ -175,7 +175,8 @@ char *start = s; auto char tbuf[100]; long off; - int i, w, y; + int i, w; + long y; static short first = 1; #ifdef POSIX_SEMANTICS static char *savetz = NULL; @@ -378,7 +379,7 @@ break; case 'Y': /* year with century */ - sprintf(tbuf, "%d", 1900 + timeptr->tm_year); + sprintf(tbuf, "%ld", 1900L + timeptr->tm_year); break; #ifdef MAILHEADER_EXT @@ -503,10 +504,10 @@ #ifdef VMS_EXT case 'v': /* date as dd-bbb-YYYY */ - sprintf(tbuf, "%2d-%3.3s-%4d", + sprintf(tbuf, "%2d-%3.3s-%4ld", range(1, timeptr->tm_mday, 31), months_a[range(0, timeptr->tm_mon, 11)], - timeptr->tm_year + 1900); + timeptr->tm_year + 1900L); for (i = 3; i < 6; i++) if (islower(tbuf[i])) tbuf[i] = toupper(tbuf[i]); @@ -516,7 +517,7 @@ #ifdef POSIX2_DATE case 'C': - sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100); + sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100); break; @@ -550,16 +551,16 @@ */ w = iso8601wknum(timeptr); if (timeptr->tm_mon == 11 && w == 1) - y = 1900 + timeptr->tm_year + 1; + y = 1900L + timeptr->tm_year + 1; else if (timeptr->tm_mon == 0 && w >= 52) - y = 1900 + timeptr->tm_year - 1; + y = 1900L + timeptr->tm_year - 1; else - y = 1900 + timeptr->tm_year; + y = 1900L + timeptr->tm_year; if (*format == 'G') - sprintf(tbuf, "%d", y); + sprintf(tbuf, "%ld", y); else - sprintf(tbuf, "%02d", y % 100); + sprintf(tbuf, "%02ld", y % 100); break; #endif /* ISO_DATE_EXT */ default: @@ -590,10 +591,10 @@ #ifndef __STDC__ static int isleap(year) -int year; +long year; #else static int -isleap(int year) +isleap(long year) #endif { return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); @@ -684,7 +685,7 @@ dec31ly.tm_mon = 11; dec31ly.tm_mday = 31; dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; - dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900); + dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L); weeknum = iso8601wknum(& dec31ly); #endif } -- [$BEDCf(B $BE/(B][$B$?$J$+(B $B$"$-$i(B][Tanaka Akira] $B!V$U$($m(B! $B$o$+$a$A$c$s:n@o$G$9$(C"=$B!W(B(Little Worker, $B7KM7@84](B)