* time.c: new method gmtoff', gmt_offset' and `utc_offset'.

(time_utc_offset): new function.
(Init_Time): bind above methods to `time_utc_offset'.

* time.c: 64bit time_t support.
(time_s_at): use NUM2LONG instead of NUM2INT for tv_sec.
(time_arg): initialize tm_isdst correctly.
use long to initialize tm_year.
(search_time_t): renamed from `make_time_t'.
(make_time_t): call `timegm' and `mktime' instead of `search_time_t'
if availabe.
(time_to_i): use LONG2NUM instead of INT2NUM.
(time_localtime): check localtime failure.
(time_gmtime): check gmtime failure.
(time_year): use LONG2NUM instead of INT2FIX.
(time_to_a): use long for tm_year.
(time_dump): check tm_year which is not representable with 17bit.
(time_load): initialize tm_isdst.

* configure.in: check existence of `mktime' and `timegm'.
check existence of tm_gmtoff field of struct tm.
fix negative time_t for 64bit time_t.

* missing/strftime.c: fix overflow by tm_year + 1900.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1912 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2001-12-17 06:45:37 +00:00
parent 39c0252e04
commit b48e38c526
4 changed files with 180 additions and 27 deletions

View File

@ -1,3 +1,30 @@
Mon Dec 17 15:19:32 2001 Tanaka Akira <akr@m17n.org>
* time.c: new method `gmtoff', `gmt_offset' and `utc_offset'.
(time_utc_offset): new function.
(Init_Time): bind above methods to `time_utc_offset'.
* time.c: 64bit time_t support.
(time_s_at): use NUM2LONG instead of NUM2INT for tv_sec.
(time_arg): initialize tm_isdst correctly.
use long to initialize tm_year.
(search_time_t): renamed from `make_time_t'.
(make_time_t): call `timegm' and `mktime' instead of `search_time_t'
if availabe.
(time_to_i): use LONG2NUM instead of INT2NUM.
(time_localtime): check localtime failure.
(time_gmtime): check gmtime failure.
(time_year): use LONG2NUM instead of INT2FIX.
(time_to_a): use long for tm_year.
(time_dump): check tm_year which is not representable with 17bit.
(time_load): initialize tm_isdst.
* configure.in: check existence of `mktime' and `timegm'.
check existence of tm_gmtoff field of struct tm.
fix negative time_t for 64bit time_t.
* missing/strftime.c: fix overflow by tm_year + 1900.
Fri Dec 14 04:23:36 2001 Minero Aoki <aamine@loveruby.net> Fri Dec 14 04:23:36 2001 Minero Aoki <aamine@loveruby.net>
* lib/net/pop.rb: new method Net::POP3.APOP * lib/net/pop.rb: new method Net::POP3.APOP

View File

@ -300,8 +300,17 @@ AC_CHECK_FUNCS(fmod killpg drand48 random wait4 waitpid syscall chroot\
setitimer setruid seteuid setreuid setresuid setproctitle\ setitimer setruid seteuid setreuid setresuid setproctitle\
setrgid setegid setregid setresgid pause lchown lchmod\ setrgid setegid setregid setresgid pause lchown lchmod\
getpgrp setpgrp getpgid setpgid getgroups getpriority getrlimit\ 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_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_CACHE_CHECK(for external int daylight, rb_cv_have_daylight,
[AC_TRY_LINK([#include <time.h> [AC_TRY_LINK([#include <time.h>
int i;], int i;],
@ -337,7 +346,7 @@ main()
struct tm *tm; struct tm *tm;
check(gmtime(&t), 69, 12, 31, 23, 59); check(gmtime(&t), 69, 12, 31, 23, 59);
t = -0x80000000; t = ~(time_t)0 << 31;
check(gmtime(&t), 1, 12, 13, 20, 52); check(gmtime(&t), 1, 12, 13, 20, 52);
return 0; return 0;
} }

View File

@ -175,7 +175,8 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
char *start = s; char *start = s;
auto char tbuf[100]; auto char tbuf[100];
long off; long off;
int i, w, y; int i, w;
long y;
static short first = 1; static short first = 1;
#ifdef POSIX_SEMANTICS #ifdef POSIX_SEMANTICS
static char *savetz = NULL; static char *savetz = NULL;
@ -378,7 +379,7 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
break; break;
case 'Y': /* year with century */ case 'Y': /* year with century */
sprintf(tbuf, "%d", 1900 + timeptr->tm_year); sprintf(tbuf, "%ld", 1900L + timeptr->tm_year);
break; break;
#ifdef MAILHEADER_EXT #ifdef MAILHEADER_EXT
@ -503,10 +504,10 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
#ifdef VMS_EXT #ifdef VMS_EXT
case 'v': /* date as dd-bbb-YYYY */ 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), range(1, timeptr->tm_mday, 31),
months_a[range(0, timeptr->tm_mon, 11)], months_a[range(0, timeptr->tm_mon, 11)],
timeptr->tm_year + 1900); timeptr->tm_year + 1900L);
for (i = 3; i < 6; i++) for (i = 3; i < 6; i++)
if (islower(tbuf[i])) if (islower(tbuf[i]))
tbuf[i] = toupper(tbuf[i]); tbuf[i] = toupper(tbuf[i]);
@ -516,7 +517,7 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
#ifdef POSIX2_DATE #ifdef POSIX2_DATE
case 'C': case 'C':
sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100); sprintf(tbuf, "%02ld", (timeptr->tm_year + 1900L) / 100);
break; break;
@ -550,16 +551,16 @@ strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
*/ */
w = iso8601wknum(timeptr); w = iso8601wknum(timeptr);
if (timeptr->tm_mon == 11 && w == 1) 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) else if (timeptr->tm_mon == 0 && w >= 52)
y = 1900 + timeptr->tm_year - 1; y = 1900L + timeptr->tm_year - 1;
else else
y = 1900 + timeptr->tm_year; y = 1900L + timeptr->tm_year;
if (*format == 'G') if (*format == 'G')
sprintf(tbuf, "%d", y); sprintf(tbuf, "%ld", y);
else else
sprintf(tbuf, "%02d", y % 100); sprintf(tbuf, "%02ld", y % 100);
break; break;
#endif /* ISO_DATE_EXT */ #endif /* ISO_DATE_EXT */
default: default:
@ -590,10 +591,10 @@ out:
#ifndef __STDC__ #ifndef __STDC__
static int static int
isleap(year) isleap(year)
int year; long year;
#else #else
static int static int
isleap(int year) isleap(long year)
#endif #endif
{ {
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
@ -684,7 +685,7 @@ iso8601wknum(const struct tm *timeptr)
dec31ly.tm_mon = 11; dec31ly.tm_mon = 11;
dec31ly.tm_mday = 31; dec31ly.tm_mday = 31;
dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; 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); weeknum = iso8601wknum(& dec31ly);
#endif #endif
} }

140
time.c
View File

@ -173,7 +173,7 @@ time_s_at(argc, argv, klass)
VALUE time, t; VALUE time, t;
if (rb_scan_args(argc, argv, "11", &time, &t) == 2) { 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); tv.tv_usec = NUM2INT(t);
} }
else { else {
@ -215,6 +215,7 @@ time_arg(argc, argv, tm, usec)
{ {
VALUE v[7]; VALUE v[7];
int i; int i;
long year;
MEMZERO(tm, struct tm, 1); MEMZERO(tm, struct tm, 1);
if (argc == 10) { if (argc == 10) {
@ -225,16 +226,28 @@ time_arg(argc, argv, tm, usec)
v[4] = argv[1]; v[4] = argv[1];
v[5] = argv[0]; v[5] = argv[0];
*usec = 0; *usec = 0;
tm->tm_isdst = RTEST(argv[9]) ? 1 : 0; tm->tm_isdst = RTEST(argv[8]) ? 1 : 0;
} }
else { else {
rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]); 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; *usec = (argc == 7) ? NUM2INT(v[6]) : 0;
tm->tm_isdst = -1;
} }
tm->tm_year = obj2long(v[0]); 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; 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])) { if (NIL_P(v[1])) {
tm->tm_mon = 0; tm->tm_mon = 0;
} }
@ -270,6 +283,7 @@ time_arg(argc, argv, tm, usec)
/* value validation */ /* value validation */
if ( if (
tm->tm_year != year ||
#ifndef NEGATIVE_TIME_T #ifndef NEGATIVE_TIME_T
tm->tm_year < 69 || tm->tm_year < 69 ||
#endif #endif
@ -307,7 +321,7 @@ tmcmp(a, b)
} }
static time_t static time_t
make_time_t(tptr, utc_p) search_time_t(tptr, utc_p)
struct tm *tptr; struct tm *tptr;
int utc_p; int utc_p;
{ {
@ -316,10 +330,10 @@ make_time_t(tptr, utc_p)
int d, have_guess; int d, have_guess;
int find_dst; int find_dst;
find_dst = 1; find_dst = 0 < tptr->tm_isdst;
#ifdef NEGATIVE_TIME_T #ifdef NEGATIVE_TIME_T
guess_lo = 1 << (8 * sizeof(time_t) - 1); guess_lo = 1L << (8 * sizeof(time_t) - 1);
#else #else
guess_lo = 0; guess_lo = 0;
#endif #endif
@ -536,6 +550,55 @@ make_time_t(tptr, utc_p)
return 0; /* not reached */ 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) {
#ifdef NEGATIVE_TIME_T
if (!(tmp = gmtime(&t)) ||
tptr->tm_year != tmp->tm_year ||
tptr->tm_mon != tmp->tm_mon ||
tptr->tm_mday != tmp->tm_mday ||
tptr->tm_hour != tmp->tm_hour ||
tptr->tm_min != tmp->tm_min ||
tptr->tm_sec != tmp->tm_sec)
#endif
rb_raise(rb_eArgError, "gmtime error");
}
#else
t = search_time_t(&buf, utc_p);
#endif
}
else {
#if defined(HAVE_MKTIME)
t = mktime(&buf);
if (t == -1) {
#ifdef NEGATIVE_TIME_T
if (!(tmp = localtime(&t)) ||
tptr->tm_year != tmp->tm_year ||
tptr->tm_mon != tmp->tm_mon ||
tptr->tm_mday != tmp->tm_mday ||
tptr->tm_hour != tmp->tm_hour ||
tptr->tm_min != tmp->tm_min ||
tptr->tm_sec != tmp->tm_sec)
#endif
rb_raise(rb_eArgError, "localtime error");
}
#else
t = search_time_t(&buf, utc_p);
#endif
}
return t;
}
static VALUE static VALUE
time_utc_or_local(argc, argv, utc_p, klass) time_utc_or_local(argc, argv, utc_p, klass)
int argc; int argc;
@ -578,7 +641,7 @@ time_to_i(time)
struct time_object *tobj; struct time_object *tobj;
GetTimeval(time, tobj); GetTimeval(time, tobj);
return INT2NUM(tobj->tv.tv_sec); return LONG2NUM(tobj->tv.tv_sec);
} }
static VALUE static VALUE
@ -746,6 +809,8 @@ time_localtime(time)
} }
t = tobj->tv.tv_sec; t = tobj->tv.tv_sec;
tm_tmp = localtime(&t); tm_tmp = localtime(&t);
if (!tm_tmp)
rb_raise(rb_eArgError, "localtime error");
tobj->tm = *tm_tmp; tobj->tm = *tm_tmp;
tobj->tm_got = 1; tobj->tm_got = 1;
tobj->gmt = 0; tobj->gmt = 0;
@ -770,6 +835,8 @@ time_gmtime(time)
} }
t = tobj->tv.tv_sec; t = tobj->tv.tv_sec;
tm_tmp = gmtime(&t); tm_tmp = gmtime(&t);
if (!tm_tmp)
rb_raise(rb_eArgError, "gmtime error");
tobj->tm = *tm_tmp; tobj->tm = *tm_tmp;
tobj->tm_got = 1; tobj->tm_got = 1;
tobj->gmt = 1; tobj->gmt = 1;
@ -1002,7 +1069,7 @@ time_year(time)
if (tobj->tm_got == 0) { if (tobj->tm_got == 0) {
time_get_tm(time, tobj->gmt); time_get_tm(time, tobj->gmt);
} }
return INT2FIX(tobj->tm.tm_year+1900); return LONG2NUM((long)tobj->tm.tm_year+1900);
} }
static VALUE static VALUE
@ -1070,6 +1137,48 @@ time_zone(time)
#endif #endif
} }
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 static VALUE
time_to_a(time) time_to_a(time)
VALUE time; VALUE time;
@ -1086,7 +1195,7 @@ time_to_a(time)
INT2FIX(tobj->tm.tm_hour), INT2FIX(tobj->tm.tm_hour),
INT2FIX(tobj->tm.tm_mday), INT2FIX(tobj->tm.tm_mday),
INT2FIX(tobj->tm.tm_mon+1), 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_wday),
INT2FIX(tobj->tm.tm_yday+1), INT2FIX(tobj->tm.tm_yday+1),
tobj->tm.tm_isdst?Qtrue:Qfalse, tobj->tm.tm_isdst?Qtrue:Qfalse,
@ -1200,6 +1309,9 @@ time_dump(argc, argv, time)
t = tobj->tv.tv_sec; t = tobj->tv.tv_sec;
tm = gmtime(&t); tm = gmtime(&t);
if ((tm->tm_year & 0x1ffff) != tm->tm_year)
rb_raise(rb_eArgError, "too big year to marshal");
p = 0x1 << 31 | /* 1 */ p = 0x1 << 31 | /* 1 */
tm->tm_year << 14 | /* 17 */ tm->tm_year << 14 | /* 17 */
tm->tm_mon << 10 | /* 4 */ tm->tm_mon << 10 | /* 4 */
@ -1255,8 +1367,9 @@ time_load(klass, str)
tm.tm_hour = p & 0x1f; tm.tm_hour = p & 0x1f;
tm.tm_min = (s >> 26) & 0x3f; tm.tm_min = (s >> 26) & 0x3f;
tm.tm_sec = (s >> 20) & 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; usec = (time_t) s & 0xfffff;
return time_new_internal(klass, sec, usec); return time_new_internal(klass, sec, usec);
@ -1315,6 +1428,9 @@ Init_Time()
rb_define_method(rb_cTime, "isdst", time_isdst, 0); rb_define_method(rb_cTime, "isdst", time_isdst, 0);
rb_define_method(rb_cTime, "dst?", 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, "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, "utc?", time_utc_p, 0);
rb_define_method(rb_cTime, "gmt?", time_utc_p, 0); rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);