[#15357] Regexp literal and Regexp.new() — TAKAHASHI Masayoshi <maki@...>

高橋征義です。

14 messages 2001/12/05
[#15358] Regexp in UTF-8 (Re: Regexp literal and Regexp.new()) — TAKAHASHI Masayoshi <maki@...> 2001/12/05

高橋征義です。むーん、問題のありかが違ったかも。

[#15435] Time#utcoff — Tanaka Akira <akr@...17n.org>

In article <hvosnahj702.fsf@coulee.a02.aist.go.jp>,

20 messages 2001/12/13
[#15436] Re: Time#utcoff — matz@... (Yukihiro Matsumoto) 2001/12/14

まつもと ゆきひろです

[#15505] ERb — m_seki@...

74 messages 2001/12/20
[#15560] Re: ERb — Tanaka Akira <akr@...17n.org> 2001/12/27

In article <20011220114249J.seki@mr.nasu.toshiba.co.jp>,

[#15879] Re: ERb — m_seki@... 2002/02/12

[#15884] Re: ERb — Tanaka Akira <akr@...17n.org> 2002/02/14

In article <m3eljr5o9m.wl@edwin.mva.biglobe.ne.jp>,

[#15885] Re: ERb — m_seki@... 2002/02/14

[#15886] Re: ERb — m_seki@... 2002/02/14

[#15887] Re: ERb — TAKAHASHI Masayoshi <maki@...> 2002/02/14

高橋征義です。

[#15888] Re: ERb — m_seki@... 2002/02/14

[#15896] Re: ERb — Tanaka Akira <akr@...17n.org> 2002/02/15

In article <20020215085405G.seki@mr.nasu.toshiba.co.jp>,

[#15898] Re: ERb — m_seki@... 2002/02/15

[#15900] Re: ERb — TADA Tadashi <sho@...> 2002/02/16

ただただしです。

[#15901] Re: ERb — m_seki@... 2002/02/16

[#15906] Re: ERb — matz@... (Yukihiro Matsumoto) 2002/02/17

まつもと ゆきひろです

[#15909] 1.6 の寿命 (Re: Re: ERb) — Koji Arai <JCA02266@...> 2002/02/17

新井です。

[#15507] fileutils (2) — Minero Aoki <aamine@...>

あおきです。

30 messages 2001/12/20
[#15512] Re: fileutils (2) — TAKAHASHI Masayoshi <maki@...> 2001/12/20

高橋征義です。

[#15513] Re: fileutils (2) — Minero Aoki <aamine@...> 2001/12/21

あおきです。

[#15515] Re: fileutils (2) — TAKAHASHI Masayoshi <maki@...> 2001/12/21

高橋征義です。結論は最後に。

[#15516] Re: fileutils (2) — Minero Aoki <aamine@...> 2001/12/21

あおきです。

[#15533] Re: fileutils (2) — TAKAHASHI Masayoshi <maki@...> 2001/12/22

高橋征義です。

[#15536] Re: fileutils (2) — Minero Aoki <aamine@...> 2001/12/24

あおきです。

[#15540] Re: fileutils (2) — TAKAHASHI Masayoshi <maki@...> 2001/12/24

高橋征義です。

[#15545] Re: fileutils (2) — Minero Aoki <aamine@...> 2001/12/24

あおきです。

[#15557] Re: fileutils (2) — TAKAHASHI Masayoshi <maki@...> 2001/12/26

高橋征義です。

[#15567] Re: fileutils (2) — Minero Aoki <aamine@...> 2001/12/27

あおきです。

[#15573] [patch] resolv.rb for win32 platform — Tietew <tietew-ml-ruby-dev@...>

Tietew です。

22 messages 2001/12/28

[ruby-dev:15462] Re: Time#utcoff

From: Tanaka Akira <akr@...17n.org>
Date: 2001-12-16 06:07:42 UTC
List: ruby-dev #15462
In article <hvosnaeblzu.fsf@coulee.a02.aist.go.jp>,
  Tanaka Akira <akr@m17n.org> writes:

> また、make_time_t の方は厄介で、二分探索しようにも初期状態の範囲の端点
> で localtime/gmtime が失敗するので話になりません。たぶん。

この原因がわかりました。64bit な time_t だと 32bit な tm_year が
overflow することがあり、その場合 localtime/gmtime が NULL を返します。
つまり、-(1<<32)+1900年の始まりから (1<<32)-1+1900年の終わりまでしか扱
えません。この両端は時差によって異なるので、二分探索の初期範囲を固定す
ることが出来ません。というわけでさきに述べた通り(存在する場合には)
mktime/timegm を使うことにしました。

というわけで疑問は解消したのでパッチをつけときます。

なお、time_arg が 2, 3桁 year をサポートしている都合上、西暦 0年から
38年および 69年から 138年は指定できません。いっそ消すかとも思ったので
すが、rb_warning でがまんしてあります。
(38年と半端なのは 32bit time_t でエラーになる奴は互換性の問題がないの
でそのまま西暦と解釈するようにしたからです。)

また、make_time_t の速度を計測したところ、少なくとも手元の FreeBSD で
は、さらに低下しました。この速度は mktime/timegm の速度によって決まる
ので、私のせいじゃない、と思っています。他のシステムでは別の結果が出る
かも知れません。

あと、missing/strftime.c のパッチは (1<<32) 以上の年を正しく扱うための
ものです。gawk-3.1.0 や glibc のにも同様な問題が残っていました。報告は
しておきましたが。
# tzcode も同様な問題がありましたが、Linux でテストして報告するのも何
# なのでこっちはなにもしてない。

> > gmtoffってのはstruct tmのメンバにもありますし、gmtをutcに置
> > き換えるってのはTimeクラスのほかのメソッドでも広く行っている
> > ので自然な経緯だと思うのですが、utcoffって名前はなぜこんなに
> > 違和感があるんでしょう? わたしだけ?

これは utc_offset, gmt_offset, gmtoff にしました。

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 <time.h>],
+    [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 <time.h>
   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
 		}
-- 
[田中 哲][たなか あきら][Tanaka Akira]
「ふえろ! わかめちゃん作戦です$(C⊇」(Little Worker, 桂遊生丸)

In This Thread