00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include <sys/types.h>
00014 #include <time.h>
00015 #include <errno.h>
00016 #include "ruby/encoding.h"
00017 #include "internal.h"
00018
00019 #ifdef HAVE_UNISTD_H
00020 #include <unistd.h>
00021 #endif
00022
00023 #include <float.h>
00024 #include <math.h>
00025
00026 #ifdef HAVE_STRINGS_H
00027 #include <strings.h>
00028 #endif
00029
00030 #include "timev.h"
00031
00032 static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset;
00033 static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;
00034
00035 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
00036 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
00037 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
00038 #define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
00039
00040 static int
00041 eq(VALUE x, VALUE y)
00042 {
00043 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00044 return x == y;
00045 }
00046 return RTEST(rb_funcall(x, id_eq, 1, y));
00047 }
00048
00049 static int
00050 cmp(VALUE x, VALUE y)
00051 {
00052 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00053 if ((long)x < (long)y)
00054 return -1;
00055 if ((long)x > (long)y)
00056 return 1;
00057 return 0;
00058 }
00059 return rb_cmpint(rb_funcall(x, id_cmp, 1, y), x, y);
00060 }
00061
00062 #define ne(x,y) (!eq((x),(y)))
00063 #define lt(x,y) (cmp((x),(y)) < 0)
00064 #define gt(x,y) (cmp((x),(y)) > 0)
00065 #define le(x,y) (cmp((x),(y)) <= 0)
00066 #define ge(x,y) (cmp((x),(y)) >= 0)
00067
00068 static VALUE
00069 add(VALUE x, VALUE y)
00070 {
00071 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00072 long l = FIX2LONG(x) + FIX2LONG(y);
00073 if (FIXABLE(l)) return LONG2FIX(l);
00074 return LONG2NUM(l);
00075 }
00076 if (TYPE(x) == T_BIGNUM) return rb_big_plus(x, y);
00077 return rb_funcall(x, '+', 1, y);
00078 }
00079
00080 static VALUE
00081 sub(VALUE x, VALUE y)
00082 {
00083 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00084 long l = FIX2LONG(x) - FIX2LONG(y);
00085 if (FIXABLE(l)) return LONG2FIX(l);
00086 return LONG2NUM(l);
00087 }
00088 if (TYPE(x) == T_BIGNUM) return rb_big_minus(x, y);
00089 return rb_funcall(x, '-', 1, y);
00090 }
00091
00092 #if !(HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG)
00093 static int
00094 long_mul(long x, long y, long *z)
00095 {
00096 unsigned long a, b, c;
00097 int s;
00098 if (x == 0 || y == 0) {
00099 *z = 0;
00100 return 1;
00101 }
00102 if (x < 0) {
00103 s = -1;
00104 a = (unsigned long)-x;
00105 }
00106 else {
00107 s = 1;
00108 a = (unsigned long)x;
00109 }
00110 if (y < 0) {
00111 s = -s;
00112 b = (unsigned long)-y;
00113 }
00114 else {
00115 b = (unsigned long)y;
00116 }
00117 if (a <= ULONG_MAX / b) {
00118 c = a * b;
00119 if (s < 0) {
00120 if (c <= (unsigned long)LONG_MAX + 1) {
00121 *z = -(long)c;
00122 return 1;
00123 }
00124 }
00125 else {
00126 if (c <= (unsigned long)LONG_MAX) {
00127 *z = (long)c;
00128 return 1;
00129 }
00130 }
00131 }
00132 return 0;
00133 }
00134 #endif
00135
00136 static VALUE
00137 mul(VALUE x, VALUE y)
00138 {
00139 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00140 #if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
00141 LONG_LONG ll = (LONG_LONG)FIX2LONG(x) * FIX2LONG(y);
00142 if (FIXABLE(ll))
00143 return LONG2FIX(ll);
00144 return LL2NUM(ll);
00145 #else
00146 long z;
00147 if (long_mul(FIX2LONG(x), FIX2LONG(y), &z))
00148 return LONG2NUM(z);
00149 #endif
00150 }
00151 if (TYPE(x) == T_BIGNUM)
00152 return rb_big_mul(x, y);
00153 return rb_funcall(x, '*', 1, y);
00154 }
00155
00156 #define div(x,y) (rb_funcall((x), id_div, 1, (y)))
00157
00158 static VALUE
00159 mod(VALUE x, VALUE y)
00160 {
00161 switch (TYPE(x)) {
00162 case T_BIGNUM: return rb_big_modulo(x, y);
00163 default: return rb_funcall(x, '%', 1, y);
00164 }
00165 }
00166
00167 #define neg(x) (sub(INT2FIX(0), (x)))
00168 #define lshift(x,y) (rb_funcall((x), id_lshift, 1, (y)))
00169
00170 static VALUE
00171 quo(VALUE x, VALUE y)
00172 {
00173 VALUE ret;
00174 if (FIXNUM_P(x) && FIXNUM_P(y)) {
00175 long a, b, c;
00176 a = FIX2LONG(x);
00177 b = FIX2LONG(y);
00178 if (b == 0) rb_num_zerodiv();
00179 c = a / b;
00180 if (c * b == a) {
00181 return LONG2NUM(c);
00182 }
00183 }
00184 ret = rb_funcall(x, id_quo, 1, y);
00185 if (TYPE(ret) == T_RATIONAL &&
00186 RRATIONAL(ret)->den == INT2FIX(1)) {
00187 ret = RRATIONAL(ret)->num;
00188 }
00189 return ret;
00190 }
00191
00192 #define mulquo(x,y,z) (((y) == (z)) ? (x) : quo(mul((x),(y)),(z)))
00193
00194 static void
00195 divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
00196 {
00197 VALUE tmp, ary;
00198 tmp = rb_funcall(n, id_divmod, 1, d);
00199 ary = rb_check_array_type(tmp);
00200 if (NIL_P(ary)) {
00201 rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
00202 rb_obj_classname(tmp));
00203 }
00204 *q = rb_ary_entry(ary, 0);
00205 *r = rb_ary_entry(ary, 1);
00206 }
00207
00208 #if SIZEOF_LONG == 8
00209 # define INT64toNUM(x) LONG2NUM(x)
00210 # define UINT64toNUM(x) ULONG2NUM(x)
00211 #elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
00212 # define INT64toNUM(x) LL2NUM(x)
00213 # define UINT64toNUM(x) ULL2NUM(x)
00214 #endif
00215
00216 #if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T
00217 typedef uint64_t uwideint_t;
00218 typedef int64_t wideint_t;
00219 typedef uint64_t WIDEVALUE;
00220 typedef int64_t SIGNED_WIDEVALUE;
00221 # define WIDEVALUE_IS_WIDER 1
00222 # define UWIDEINT_MAX UINT64_MAX
00223 # define WIDEINT_MAX INT64_MAX
00224 # define WIDEINT_MIN INT64_MIN
00225 # define FIXWINT_P(tv) ((tv) & 1)
00226 # define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
00227 # define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG))
00228 # define FIXWV_MAX (((int64_t)1 << 62) - 1)
00229 # define FIXWV_MIN (-((int64_t)1 << 62))
00230 # define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi))
00231 # define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i))
00232 # define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w))
00233 #else
00234 typedef unsigned long uwideint_t;
00235 typedef long wideint_t;
00236 typedef VALUE WIDEVALUE;
00237 typedef SIGNED_VALUE SIGNED_WIDEVALUE;
00238 # define WIDEVALUE_IS_WIDER 0
00239 # define UWIDEINT_MAX ULONG_MAX
00240 # define WIDEINT_MAX LONG_MAX
00241 # define WIDEINT_MIN LONG_MIN
00242 # define FIXWINT_P(v) FIXNUM_P(v)
00243 # define FIXWV_MAX FIXNUM_MAX
00244 # define FIXWV_MIN FIXNUM_MIN
00245 # define FIXWVABLE(i) FIXABLE(i)
00246 # define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i))
00247 # define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
00248 #endif
00249
00250 #define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
00251 #define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
00252 #define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
00253
00254
00255 #ifdef STRUCT_WIDEVAL
00256
00257 typedef struct {
00258 WIDEVALUE value;
00259 } wideval_t;
00260 static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; }
00261 # define WIDEVAL_GET(w) ((w).value)
00262 #else
00263 typedef WIDEVALUE wideval_t;
00264 # define WIDEVAL_WRAP(v) (v)
00265 # define WIDEVAL_GET(w) (w)
00266 #endif
00267
00268 #if WIDEVALUE_IS_WIDER
00269 static inline wideval_t
00270 wint2wv(wideint_t wi)
00271 {
00272 if (FIXWVABLE(wi))
00273 return WINT2FIXWV(wi);
00274 else
00275 return WIDEVAL_WRAP(INT64toNUM(wi));
00276 }
00277 # define WINT2WV(wi) wint2wv(wi)
00278 #else
00279 # define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi))
00280 #endif
00281
00282 static inline VALUE
00283 w2v(wideval_t w)
00284 {
00285 #if WIDEVALUE_IS_WIDER
00286 if (FIXWV_P(w))
00287 return INT64toNUM(FIXWV2WINT(w));
00288 return (VALUE)WIDEVAL_GET(w);
00289 #else
00290 return WIDEVAL_GET(w);
00291 #endif
00292 }
00293
00294 #if WIDEVALUE_IS_WIDER
00295 static int
00296 bdigit_find_maxbit(BDIGIT d)
00297 {
00298 int res = 0;
00299 if (d & ~(BDIGIT)0xffff) {
00300 d >>= 16;
00301 res += 16;
00302 }
00303 if (d & ~(BDIGIT)0xff) {
00304 d >>= 8;
00305 res += 8;
00306 }
00307 if (d & ~(BDIGIT)0xf) {
00308 d >>= 4;
00309 res += 4;
00310 }
00311 if (d & ~(BDIGIT)0x3) {
00312 d >>= 2;
00313 res += 2;
00314 }
00315 if (d & ~(BDIGIT)0x1) {
00316 d >>= 1;
00317 res += 1;
00318 }
00319 return res;
00320 }
00321
00322 static VALUE
00323 rb_big_abs_find_maxbit(VALUE big)
00324 {
00325 BDIGIT *ds = RBIGNUM_DIGITS(big);
00326 BDIGIT d;
00327 long len = RBIGNUM_LEN(big);
00328 VALUE res;
00329 while (0 < len && ds[len-1] == 0)
00330 len--;
00331 if (len == 0)
00332 return Qnil;
00333 res = mul(LONG2NUM(len-1), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT));
00334 d = ds[len-1];
00335 res = add(res, LONG2FIX(bdigit_find_maxbit(d)));
00336 return res;
00337 }
00338
00339 static VALUE
00340 rb_big_abs_find_minbit(VALUE big)
00341 {
00342 BDIGIT *ds = RBIGNUM_DIGITS(big);
00343 BDIGIT d;
00344 long len = RBIGNUM_LEN(big);
00345 long i;
00346 VALUE res;
00347 for (i = 0; i < len; i++)
00348 if (ds[i])
00349 break;
00350 if (i == len)
00351 return Qnil;
00352 res = mul(LONG2NUM(i), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT));
00353 d = ds[i];
00354 res = add(res, LONG2FIX(ffs(d)-1));
00355 return res;
00356 }
00357
00358 static wideval_t
00359 v2w_bignum(VALUE v)
00360 {
00361 long len = RBIGNUM_LEN(v);
00362 BDIGIT *ds;
00363 wideval_t w;
00364 VALUE maxbit;
00365 ds = RBIGNUM_DIGITS(v);
00366 w = WIDEVAL_WRAP(v);
00367 maxbit = rb_big_abs_find_maxbit(v);
00368 if (NIL_P(maxbit))
00369 return WINT2FIXWV(0);
00370 if (lt(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) ||
00371 (eq(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) &&
00372 RBIGNUM_NEGATIVE_P(v) &&
00373 eq(rb_big_abs_find_minbit(v), INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)))) {
00374 wideint_t i;
00375 i = 0;
00376 while (len)
00377 i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len];
00378 if (RBIGNUM_NEGATIVE_P(v)) {
00379 i = -i;
00380 }
00381 w = WINT2FIXWV(i);
00382 }
00383 return w;
00384 }
00385 #endif
00386
00387 static inline wideval_t
00388 v2w(VALUE v)
00389 {
00390 #if WIDEVALUE_IS_WIDER
00391 if (FIXNUM_P(v)) {
00392 return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(long)v);
00393 }
00394 else if (TYPE(v) == T_BIGNUM &&
00395 RBIGNUM_LEN(v) * sizeof(BDIGIT) <= sizeof(WIDEVALUE)) {
00396 return v2w_bignum(v);
00397 }
00398 #endif
00399 return WIDEVAL_WRAP(v);
00400 }
00401
00402 static int
00403 weq(wideval_t wx, wideval_t wy)
00404 {
00405 #if WIDEVALUE_IS_WIDER
00406 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00407 return WIDEVAL_GET(wx) == WIDEVAL_GET(wy);
00408 }
00409 return RTEST(rb_funcall(w2v(wx), id_eq, 1, w2v(wy)));
00410 #else
00411 return eq(WIDEVAL_GET(wx), WIDEVAL_GET(wy));
00412 #endif
00413 }
00414
00415 static int
00416 wcmp(wideval_t wx, wideval_t wy)
00417 {
00418 VALUE x, y;
00419 #if WIDEVALUE_IS_WIDER
00420 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00421 wideint_t a, b;
00422 a = FIXWV2WINT(wx);
00423 b = FIXWV2WINT(wy);
00424 if (a < b)
00425 return -1;
00426 if (a > b)
00427 return 1;
00428 return 0;
00429 }
00430 #endif
00431 x = w2v(wx);
00432 y = w2v(wy);
00433 return rb_cmpint(rb_funcall(x, id_cmp, 1, y), x, y);
00434 }
00435
00436 #define wne(x,y) (!weq((x),(y)))
00437 #define wlt(x,y) (wcmp((x),(y)) < 0)
00438 #define wgt(x,y) (wcmp((x),(y)) > 0)
00439 #define wle(x,y) (wcmp((x),(y)) <= 0)
00440 #define wge(x,y) (wcmp((x),(y)) >= 0)
00441
00442 static wideval_t
00443 wadd(wideval_t wx, wideval_t wy)
00444 {
00445 VALUE x;
00446 #if WIDEVALUE_IS_WIDER
00447 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00448 wideint_t r = FIXWV2WINT(wx) + FIXWV2WINT(wy);
00449 return WINT2WV(r);
00450 }
00451 else
00452 #endif
00453 x = w2v(wx);
00454 if (TYPE(x) == T_BIGNUM) return v2w(rb_big_plus(x, w2v(wy)));
00455 return v2w(rb_funcall(x, '+', 1, w2v(wy)));
00456 }
00457
00458 static wideval_t
00459 wsub(wideval_t wx, wideval_t wy)
00460 {
00461 VALUE x;
00462 #if WIDEVALUE_IS_WIDER
00463 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00464 wideint_t r = FIXWV2WINT(wx) - FIXWV2WINT(wy);
00465 return WINT2WV(r);
00466 }
00467 else
00468 #endif
00469 x = w2v(wx);
00470 if (TYPE(x) == T_BIGNUM) return v2w(rb_big_minus(x, w2v(wy)));
00471 return v2w(rb_funcall(x, '-', 1, w2v(wy)));
00472 }
00473
00474 static int
00475 wi_mul(wideint_t x, wideint_t y, wideint_t *z)
00476 {
00477 uwideint_t a, b, c;
00478 int s;
00479 if (x == 0 || y == 0) {
00480 *z = 0;
00481 return 1;
00482 }
00483 if (x < 0) {
00484 s = -1;
00485 a = (uwideint_t)-x;
00486 }
00487 else {
00488 s = 1;
00489 a = (uwideint_t)x;
00490 }
00491 if (y < 0) {
00492 s = -s;
00493 b = (uwideint_t)-y;
00494 }
00495 else {
00496 b = (uwideint_t)y;
00497 }
00498 if (a <= UWIDEINT_MAX / b) {
00499 c = a * b;
00500 if (s < 0) {
00501 if (c <= (uwideint_t)WIDEINT_MAX + 1) {
00502 *z = -(wideint_t)c;
00503 return 1;
00504 }
00505 }
00506 else {
00507 if (c <= (uwideint_t)WIDEINT_MAX) {
00508 *z = (wideint_t)c;
00509 return 1;
00510 }
00511 }
00512 }
00513 return 0;
00514 }
00515
00516 static wideval_t
00517 wmul(wideval_t wx, wideval_t wy)
00518 {
00519 VALUE x, z;
00520 #if WIDEVALUE_IS_WIDER
00521 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00522 wideint_t z;
00523 if (wi_mul(FIXWV2WINT(wx), FIXWV2WINT(wy), &z))
00524 return WINT2WV(z);
00525 }
00526 #endif
00527 x = w2v(wx);
00528 if (TYPE(x) == T_BIGNUM) return v2w(rb_big_mul(x, w2v(wy)));
00529 z = rb_funcall(x, '*', 1, w2v(wy));
00530 if (TYPE(z) == T_RATIONAL && RRATIONAL(z)->den == INT2FIX(1)) {
00531 z = RRATIONAL(z)->num;
00532 }
00533 return v2w(z);
00534 }
00535
00536 static wideval_t
00537 wquo(wideval_t wx, wideval_t wy)
00538 {
00539 VALUE x, y, ret;
00540 #if WIDEVALUE_IS_WIDER
00541 if (FIXWV_P(wx) && FIXWV_P(wy)) {
00542 wideint_t a, b, c;
00543 a = FIXWV2WINT(wx);
00544 b = FIXWV2WINT(wy);
00545 if (b == 0) rb_num_zerodiv();
00546 c = a / b;
00547 if (c * b == a) {
00548 return WINT2WV(c);
00549 }
00550 }
00551 #endif
00552 x = w2v(wx);
00553 y = w2v(wy);
00554 ret = rb_funcall(x, id_quo, 1, y);
00555 if (TYPE(ret) == T_RATIONAL &&
00556 RRATIONAL(ret)->den == INT2FIX(1)) {
00557 ret = RRATIONAL(ret)->num;
00558 }
00559 return v2w(ret);
00560 }
00561
00562 #define wmulquo(x,y,z) ((WIDEVAL_GET(y) == WIDEVAL_GET(z)) ? (x) : wquo(wmul((x),(y)),(z)))
00563 #define wmulquoll(x,y,z) (((y) == (z)) ? (x) : wquo(wmul((x),WINT2WV(y)),WINT2WV(z)))
00564
00565 static void
00566 wdivmod(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
00567 {
00568 VALUE tmp, ary;
00569 #if WIDEVALUE_IS_WIDER
00570 if (FIXWV_P(wn) && FIXWV_P(wd)) {
00571 wideint_t n, d, q, r;
00572 d = FIXWV2WINT(wd);
00573 if (d == 0) rb_num_zerodiv();
00574 if (d == 1) {
00575 *wq = wn;
00576 *wr = WINT2FIXWV(0);
00577 return;
00578 }
00579 if (d == -1) {
00580 wideint_t xneg = -FIXWV2WINT(wn);
00581 *wq = WINT2WV(xneg);
00582 *wr = WINT2FIXWV(0);
00583 return;
00584 }
00585 n = FIXWV2WINT(wn);
00586 if (n == 0) {
00587 *wq = WINT2FIXWV(0);
00588 *wr = WINT2FIXWV(0);
00589 return;
00590 }
00591 if (d < 0) {
00592 if (n < 0) {
00593 q = ((-n) / (-d));
00594 r = ((-n) % (-d));
00595 if (r != 0) {
00596 q -= 1;
00597 r += d;
00598 }
00599 }
00600 else {
00601 q = -(n / (-d));
00602 r = -(n % (-d));
00603 }
00604 }
00605 else {
00606 if (n < 0) {
00607 q = -((-n) / d);
00608 r = -((-n) % d);
00609 if (r != 0) {
00610 q -= 1;
00611 r += d;
00612 }
00613 }
00614 else {
00615 q = n / d;
00616 r = n % d;
00617 }
00618 }
00619 *wq = WINT2FIXWV(q);
00620 *wr = WINT2FIXWV(r);
00621 return;
00622 }
00623 #endif
00624 tmp = rb_funcall(w2v(wn), id_divmod, 1, w2v(wd));
00625 ary = rb_check_array_type(tmp);
00626 if (NIL_P(ary)) {
00627 rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
00628 rb_obj_classname(tmp));
00629 }
00630 *wq = v2w(rb_ary_entry(ary, 0));
00631 *wr = v2w(rb_ary_entry(ary, 1));
00632 }
00633
00634 static void
00635 wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr)
00636 {
00637 if (WIDEVAL_GET(wy) == WIDEVAL_GET(wz)) {
00638 *wq = wx;
00639 *wr = WINT2FIXWV(0);
00640 return;
00641 }
00642 wdivmod(wmul(wx,wy), wz, wq, wr);
00643 }
00644
00645 static wideval_t
00646 wdiv(wideval_t wx, wideval_t wy)
00647 {
00648 wideval_t q, r;
00649 wdivmod(wx, wy, &q, &r);
00650 return q;
00651 }
00652
00653 static wideval_t
00654 wmod(wideval_t wx, wideval_t wy)
00655 {
00656 wideval_t q, r;
00657 wdivmod(wx, wy, &q, &r);
00658 return r;
00659 }
00660
00661 static VALUE
00662 num_exact(VALUE v)
00663 {
00664 VALUE tmp;
00665 int t;
00666
00667 t = TYPE(v);
00668 switch (t) {
00669 case T_FIXNUM:
00670 case T_BIGNUM:
00671 return v;
00672
00673 case T_RATIONAL:
00674 break;
00675
00676 case T_STRING:
00677 case T_NIL:
00678 goto typeerror;
00679
00680 default:
00681 if ((tmp = rb_check_funcall(v, rb_intern("to_r"), 0, NULL)) != Qundef) {
00682 if (rb_respond_to(v, rb_intern("to_str"))) goto typeerror;
00683 v = tmp;
00684 break;
00685 }
00686 if (!NIL_P(tmp = rb_check_to_integer(v, "to_int"))) {
00687 v = tmp;
00688 break;
00689 }
00690 goto typeerror;
00691 }
00692
00693 t = TYPE(v);
00694 switch (t) {
00695 case T_FIXNUM:
00696 case T_BIGNUM:
00697 return v;
00698
00699 case T_RATIONAL:
00700 if (RRATIONAL(v)->den == INT2FIX(1))
00701 v = RRATIONAL(v)->num;
00702 break;
00703
00704 default:
00705 typeerror:
00706 rb_raise(rb_eTypeError, "can't convert %s into an exact number",
00707 NIL_P(v) ? "nil" : rb_obj_classname(v));
00708 }
00709 return v;
00710 }
00711
00712
00713
00714 #ifndef TYPEOF_TIMEVAL_TV_SEC
00715 # define TYPEOF_TIMEVAL_TV_SEC time_t
00716 #endif
00717 #ifndef TYPEOF_TIMEVAL_TV_USEC
00718 # if INT_MAX >= 1000000
00719 # define TYPEOF_TIMEVAL_TV_USEC int
00720 # else
00721 # define TYPEOF_TIMEVAL_TV_USEC long
00722 # endif
00723 #endif
00724
00725 #if SIZEOF_TIME_T == SIZEOF_LONG
00726 typedef unsigned long unsigned_time_t;
00727 #elif SIZEOF_TIME_T == SIZEOF_INT
00728 typedef unsigned int unsigned_time_t;
00729 #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
00730 typedef unsigned LONG_LONG unsigned_time_t;
00731 #else
00732 # error cannot find integer type which size is same as time_t.
00733 #endif
00734
00735 #define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
00736 #define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
00737
00738 static wideval_t
00739 rb_time_magnify(wideval_t w)
00740 {
00741 if (FIXWV_P(w)) {
00742 wideint_t z;
00743 if (wi_mul(FIXWV2WINT(w), TIME_SCALE, &z))
00744 return WINT2WV(z);
00745 }
00746 return wmul(w, WINT2FIXWV(TIME_SCALE));
00747 }
00748
00749 static wideval_t
00750 rb_time_unmagnify(wideval_t w)
00751 {
00752 #if WIDEVALUE_IS_WIDER
00753 if (FIXWV_P(w)) {
00754 wideint_t a, b, c;
00755 a = FIXWV2WINT(w);
00756 b = TIME_SCALE;
00757 c = a / b;
00758 if (c * b == a) {
00759 return WINT2FIXWV(c);
00760 }
00761 }
00762 #endif
00763 return wquo(w, WINT2FIXWV(TIME_SCALE));
00764 }
00765
00766 static VALUE
00767 rb_time_unmagnify_to_float(wideval_t w)
00768 {
00769 VALUE v;
00770 #if WIDEVALUE_IS_WIDER
00771 if (FIXWV_P(w)) {
00772 wideint_t a, b, c;
00773 a = FIXWV2WINT(w);
00774 b = TIME_SCALE;
00775 c = a / b;
00776 if (c * b == a) {
00777 return DBL2NUM((double)c);
00778 }
00779 v = DBL2NUM((double)FIXWV2WINT(w));
00780 return quo(v, DBL2NUM(TIME_SCALE));
00781 }
00782 #endif
00783 v = w2v(w);
00784 return quo(v, DBL2NUM(TIME_SCALE));
00785 }
00786
00787 static void
00788 split_second(wideval_t timew, wideval_t *timew_p, VALUE *subsecx_p)
00789 {
00790 wideval_t q, r;
00791 wdivmod(timew, WINT2FIXWV(TIME_SCALE), &q, &r);
00792 *timew_p = q;
00793 *subsecx_p = w2v(r);
00794 }
00795
00796 static wideval_t
00797 timet2wv(time_t t)
00798 {
00799 #if WIDEVALUE_IS_WIDER
00800 if (TIMET_MIN == 0) {
00801 uwideint_t wi = (uwideint_t)t;
00802 if (wi <= FIXWV_MAX) {
00803 return WINT2FIXWV(wi);
00804 }
00805 }
00806 else {
00807 wideint_t wi = (wideint_t)t;
00808 if (FIXWV_MIN <= wi && wi <= FIXWV_MAX) {
00809 return WINT2FIXWV(wi);
00810 }
00811 }
00812 #endif
00813 return v2w(TIMET2NUM(t));
00814 }
00815 #define TIMET2WV(t) timet2wv(t)
00816
00817 static time_t
00818 wv2timet(wideval_t w)
00819 {
00820 #if WIDEVALUE_IS_WIDER
00821 if (FIXWV_P(w)) {
00822 wideint_t wi = FIXWV2WINT(w);
00823 if (TIMET_MIN == 0) {
00824 if (wi < 0)
00825 rb_raise(rb_eRangeError, "negative value to convert into `time_t'");
00826 if (TIMET_MAX < (uwideint_t)wi)
00827 rb_raise(rb_eRangeError, "too big to convert into `time_t'");
00828 }
00829 else {
00830 if (wi < TIMET_MIN || TIMET_MAX < wi)
00831 rb_raise(rb_eRangeError, "too big to convert into `time_t'");
00832 }
00833 return (time_t)wi;
00834 }
00835 #endif
00836 return NUM2TIMET(w2v(w));
00837 }
00838 #define WV2TIMET(t) wv2timet(t)
00839
00840 VALUE rb_cTime;
00841 static VALUE time_utc_offset _((VALUE));
00842
00843 static int obj2int(VALUE obj);
00844 static VALUE obj2vint(VALUE obj);
00845 static int month_arg(VALUE arg);
00846 static void validate_utc_offset(VALUE utc_offset);
00847 static void validate_vtm(struct vtm *vtm);
00848
00849 static VALUE time_gmtime(VALUE);
00850 static VALUE time_localtime(VALUE);
00851 static VALUE time_fixoff(VALUE);
00852
00853 static time_t timegm_noleapsecond(struct tm *tm);
00854 static int tmcmp(struct tm *a, struct tm *b);
00855 static int vtmcmp(struct vtm *a, struct vtm *b);
00856 static const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
00857
00858 static struct vtm *localtimew(wideval_t timew, struct vtm *result);
00859
00860 static int leap_year_p(long y);
00861 #define leap_year_v_p(y) leap_year_p(NUM2LONG(mod((y), INT2FIX(400))))
00862
00863 #ifdef HAVE_GMTIME_R
00864 #define rb_gmtime_r(t, tm) gmtime_r((t), (tm))
00865 #define rb_localtime_r(t, tm) localtime_r((t), (tm))
00866 #else
00867 static inline struct tm *
00868 rb_gmtime_r(const time_t *tp, struct tm *result)
00869 {
00870 struct tm *t = gmtime(tp);
00871 if (t) *result = *t;
00872 return t;
00873 }
00874
00875 static inline struct tm *
00876 rb_localtime_r(const time_t *tp, struct tm *result)
00877 {
00878 struct tm *t = localtime(tp);
00879 if (t) *result = *t;
00880 return t;
00881 }
00882 #endif
00883
00884 static struct tm *
00885 rb_localtime_r2(const time_t *t, struct tm *result)
00886 {
00887 #if defined __APPLE__ && defined __LP64__
00888 if (*t != (time_t)(int)*t) return NULL;
00889 #endif
00890 result = rb_localtime_r(t, result);
00891 #if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
00892 if (result) {
00893 long gmtoff1 = 0;
00894 long gmtoff2 = 0;
00895 struct tm tmp = *result;
00896 time_t t2;
00897 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
00898 gmtoff1 = result->tm_gmtoff;
00899 # endif
00900 t2 = mktime(&tmp);
00901 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
00902 gmtoff2 = tmp.tm_gmtoff;
00903 # endif
00904 if (*t + gmtoff1 != t2 + gmtoff2)
00905 result = NULL;
00906 }
00907 #endif
00908 return result;
00909 }
00910 #define LOCALTIME(tm, result) (tzset(),rb_localtime_r2((tm), &(result)))
00911
00912 #if !defined(HAVE_STRUCT_TM_TM_GMTOFF)
00913 static struct tm *
00914 rb_gmtime_r2(const time_t *t, struct tm *result)
00915 {
00916 result = rb_gmtime_r(t, result);
00917 #if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
00918 if (result) {
00919 struct tm tmp = *result;
00920 time_t t2 = timegm(&tmp);
00921 if (*t != t2)
00922 result = NULL;
00923 }
00924 #endif
00925 return result;
00926 }
00927 # define GMTIME(tm, result) rb_gmtime_r2((tm), &(result))
00928 #endif
00929
00930 static const int common_year_yday_offset[] = {
00931 -1,
00932 -1 + 31,
00933 -1 + 31 + 28,
00934 -1 + 31 + 28 + 31,
00935 -1 + 31 + 28 + 31 + 30,
00936 -1 + 31 + 28 + 31 + 30 + 31,
00937 -1 + 31 + 28 + 31 + 30 + 31 + 30,
00938 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
00939 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
00940 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00941 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00942 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00943
00944 };
00945 static const int leap_year_yday_offset[] = {
00946 -1,
00947 -1 + 31,
00948 -1 + 31 + 29,
00949 -1 + 31 + 29 + 31,
00950 -1 + 31 + 29 + 31 + 30,
00951 -1 + 31 + 29 + 31 + 30 + 31,
00952 -1 + 31 + 29 + 31 + 30 + 31 + 30,
00953 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
00954 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
00955 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00956 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00957 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00958
00959 };
00960
00961 static const int common_year_days_in_month[] = {
00962 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
00963 };
00964 static const int leap_year_days_in_month[] = {
00965 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
00966 };
00967
00968 static int
00969 calc_tm_yday(long tm_year, int tm_mon, int tm_mday)
00970 {
00971 int tm_year_mod400 = (int)MOD(tm_year, 400);
00972 int tm_yday = tm_mday;
00973
00974 if (leap_year_p(tm_year_mod400 + 1900))
00975 tm_yday += leap_year_yday_offset[tm_mon];
00976 else
00977 tm_yday += common_year_yday_offset[tm_mon];
00978
00979 return tm_yday;
00980 }
00981
00982 static wideval_t
00983 timegmw_noleapsecond(struct vtm *vtm)
00984 {
00985 VALUE year1900;
00986 VALUE q400, r400;
00987 int year_mod400;
00988 int yday;
00989 long days_in400;
00990 VALUE vdays, ret;
00991 wideval_t wret;
00992
00993 year1900 = sub(vtm->year, INT2FIX(1900));
00994
00995 divmodv(year1900, INT2FIX(400), &q400, &r400);
00996 year_mod400 = NUM2INT(r400);
00997
00998 yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday);
00999
01000
01001
01002
01003
01004
01005
01006 ret = LONG2NUM(vtm->sec
01007 + vtm->min*60
01008 + vtm->hour*3600);
01009 days_in400 = yday
01010 - 70*365
01011 + DIV(year_mod400 - 69, 4)
01012 - DIV(year_mod400 - 1, 100)
01013 + (year_mod400 + 299) / 400;
01014 vdays = LONG2NUM(days_in400);
01015 vdays = add(vdays, mul(q400, INT2FIX(97)));
01016 vdays = add(vdays, mul(year1900, INT2FIX(365)));
01017 wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)), WINT2FIXWV(86400)));
01018 wret = wadd(wret, v2w(vtm->subsecx));
01019
01020 return wret;
01021 }
01022
01023 static st_table *zone_table;
01024
01025 static const char *
01026 zone_str(const char *s)
01027 {
01028 st_data_t k, v;
01029
01030 if (!zone_table)
01031 zone_table = st_init_strtable();
01032
01033 k = (st_data_t)s;
01034 if (st_lookup(zone_table, k, &v)) {
01035 return (const char *)v;
01036 }
01037 s = strdup(s);
01038 k = (st_data_t)s;
01039 st_add_direct(zone_table, k, k);
01040
01041 return s;
01042 }
01043
01044 static void
01045 gmtimew_noleapsecond(wideval_t timew, struct vtm *vtm)
01046 {
01047 VALUE v;
01048 int i, n, x, y;
01049 const int *yday_offset;
01050 int wday;
01051 VALUE timev;
01052 wideval_t timew2, w, w2;
01053
01054 vtm->isdst = 0;
01055
01056 split_second(timew, &timew2, &vtm->subsecx);
01057
01058 wdivmod(timew2, WINT2FIXWV(86400), &w2, &w);
01059 timev = w2v(w2);
01060 v = w2v(w);
01061
01062 wday = NUM2INT(mod(timev, INT2FIX(7)));
01063 vtm->wday = (wday + 4) % 7;
01064
01065 n = NUM2INT(v);
01066 vtm->sec = n % 60; n = n / 60;
01067 vtm->min = n % 60; n = n / 60;
01068 vtm->hour = n;
01069
01070
01071 divmodv(timev, INT2FIX(400*365 + 97), &timev, &v);
01072 vtm->year = mul(timev, INT2FIX(400));
01073
01074
01075
01076
01077 n = NUM2INT(v);
01078 y = 1970;
01079
01080
01081
01082
01083
01084 if (30*365+7+31+29-1 <= n) {
01085
01086 if (n < 31*365+8) {
01087
01088 y += 30;
01089 n -= 30*365+7;
01090 goto found;
01091 }
01092 else {
01093
01094 n -= 1;
01095 }
01096 }
01097
01098 x = n / (365*100 + 24);
01099 n = n % (365*100 + 24);
01100 y += x * 100;
01101 if (30*365+7+31+29-1 <= n) {
01102 if (n < 31*365+7) {
01103 y += 30;
01104 n -= 30*365+7;
01105 goto found;
01106 }
01107 else
01108 n += 1;
01109 }
01110
01111 x = n / (365*4 + 1);
01112 n = n % (365*4 + 1);
01113 y += x * 4;
01114 if (365*2+31+29-1 <= n) {
01115 if (n < 365*2+366) {
01116 y += 2;
01117 n -= 365*2;
01118 goto found;
01119 }
01120 else
01121 n -= 1;
01122 }
01123
01124 x = n / 365;
01125 n = n % 365;
01126 y += x;
01127
01128 found:
01129 vtm->yday = n+1;
01130 vtm->year = add(vtm->year, INT2NUM(y));
01131
01132 if (leap_year_p(y))
01133 yday_offset = leap_year_yday_offset;
01134 else
01135 yday_offset = common_year_yday_offset;
01136
01137 for (i = 0; i < 12; i++) {
01138 if (yday_offset[i] < n) {
01139 vtm->mon = i+1;
01140 vtm->mday = n - yday_offset[i];
01141 }
01142 else
01143 break;
01144 }
01145
01146 vtm->utc_offset = INT2FIX(0);
01147 vtm->zone = "UTC";
01148 }
01149
01150 static struct tm *
01151 gmtime_with_leapsecond(const time_t *timep, struct tm *result)
01152 {
01153 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
01154
01155 struct tm *t;
01156 int sign;
01157 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
01158 long gmtoff;
01159 t = LOCALTIME(timep, *result);
01160 if (t == NULL)
01161 return NULL;
01162
01163
01164 if (t->tm_gmtoff < 0) {
01165 sign = 1;
01166 gmtoff = -t->tm_gmtoff;
01167 }
01168 else {
01169 sign = -1;
01170 gmtoff = t->tm_gmtoff;
01171 }
01172 gmtoff_sec = (int)(gmtoff % 60);
01173 gmtoff = gmtoff / 60;
01174 gmtoff_min = (int)(gmtoff % 60);
01175 gmtoff = gmtoff / 60;
01176 gmtoff_hour = (int)gmtoff;
01177
01178 gmtoff_sec *= sign;
01179 gmtoff_min *= sign;
01180 gmtoff_hour *= sign;
01181
01182 gmtoff_day = 0;
01183
01184 if (gmtoff_sec) {
01185
01186
01187 result->tm_sec += gmtoff_sec;
01188 if (result->tm_sec < 0) {
01189 result->tm_sec += 60;
01190 gmtoff_min -= 1;
01191 }
01192 if (60 <= result->tm_sec) {
01193 result->tm_sec -= 60;
01194 gmtoff_min += 1;
01195 }
01196 }
01197 if (gmtoff_min) {
01198 result->tm_min += gmtoff_min;
01199 if (result->tm_min < 0) {
01200 result->tm_min += 60;
01201 gmtoff_hour -= 1;
01202 }
01203 if (60 <= result->tm_min) {
01204 result->tm_min -= 60;
01205 gmtoff_hour += 1;
01206 }
01207 }
01208 if (gmtoff_hour) {
01209 result->tm_hour += gmtoff_hour;
01210 if (result->tm_hour < 0) {
01211 result->tm_hour += 24;
01212 gmtoff_day = -1;
01213 }
01214 if (24 <= result->tm_hour) {
01215 result->tm_hour -= 24;
01216 gmtoff_day = 1;
01217 }
01218 }
01219
01220 if (gmtoff_day) {
01221 if (gmtoff_day < 0) {
01222 if (result->tm_yday == 0) {
01223 result->tm_mday = 31;
01224 result->tm_mon = 11;
01225 result->tm_year--;
01226 result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
01227 }
01228 else if (result->tm_mday == 1) {
01229 const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
01230 leap_year_days_in_month :
01231 common_year_days_in_month;
01232 result->tm_mon--;
01233 result->tm_mday = days_in_month[result->tm_mon];
01234 result->tm_yday--;
01235 }
01236 else {
01237 result->tm_mday--;
01238 result->tm_yday--;
01239 }
01240 result->tm_wday = (result->tm_wday + 6) % 7;
01241 }
01242 else {
01243 int leap = leap_year_p(result->tm_year + 1900);
01244 if (result->tm_yday == (leap ? 365 : 364)) {
01245 result->tm_year++;
01246 result->tm_mon = 0;
01247 result->tm_mday = 1;
01248 result->tm_yday = 0;
01249 }
01250 else if (result->tm_mday == (leap ? leap_year_days_in_month :
01251 common_year_days_in_month)[result->tm_mon]) {
01252 result->tm_mon++;
01253 result->tm_mday = 1;
01254 result->tm_yday++;
01255 }
01256 else {
01257 result->tm_mday++;
01258 result->tm_yday++;
01259 }
01260 result->tm_wday = (result->tm_wday + 1) % 7;
01261 }
01262 }
01263 result->tm_isdst = 0;
01264 result->tm_gmtoff = 0;
01265 #if defined(HAVE_TM_ZONE)
01266 result->tm_zone = (char *)"UTC";
01267 #endif
01268 return result;
01269 #else
01270 return GMTIME(timep, *result);
01271 #endif
01272 }
01273
01274 static long this_year = 0;
01275 static time_t known_leap_seconds_limit;
01276 static int number_of_leap_seconds_known;
01277
01278 static void
01279 init_leap_second_info()
01280 {
01281
01282
01283
01284
01285
01286 if (this_year == 0) {
01287 time_t now;
01288 struct tm *tm, result;
01289 struct vtm vtm;
01290 wideval_t timew;
01291 now = time(NULL);
01292 gmtime(&now);
01293 tm = gmtime_with_leapsecond(&now, &result);
01294 if (!tm) return;
01295 this_year = tm->tm_year;
01296
01297 if (TIMET_MAX - now < (time_t)(366*86400))
01298 known_leap_seconds_limit = TIMET_MAX;
01299 else
01300 known_leap_seconds_limit = now + (time_t)(366*86400);
01301
01302 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
01303 return;
01304
01305 vtm.year = LONG2NUM(result.tm_year + 1900);
01306 vtm.mon = result.tm_mon + 1;
01307 vtm.mday = result.tm_mday;
01308 vtm.hour = result.tm_hour;
01309 vtm.min = result.tm_min;
01310 vtm.sec = result.tm_sec;
01311 vtm.subsecx = INT2FIX(0);
01312 vtm.utc_offset = INT2FIX(0);
01313
01314 timew = timegmw_noleapsecond(&vtm);
01315
01316 number_of_leap_seconds_known = NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
01317 }
01318 }
01319
01320 static wideval_t
01321 timegmw(struct vtm *vtm)
01322 {
01323 wideval_t timew;
01324 struct tm tm;
01325 time_t t;
01326 const char *errmsg;
01327
01328
01329
01330 if (gt(INT2FIX(1972), vtm->year))
01331 return timegmw_noleapsecond(vtm);
01332
01333 init_leap_second_info();
01334
01335 timew = timegmw_noleapsecond(vtm);
01336
01337 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
01338 return wadd(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
01339 }
01340
01341 tm.tm_year = rb_long2int(NUM2LONG(vtm->year) - 1900);
01342 tm.tm_mon = vtm->mon - 1;
01343 tm.tm_mday = vtm->mday;
01344 tm.tm_hour = vtm->hour;
01345 tm.tm_min = vtm->min;
01346 tm.tm_sec = vtm->sec;
01347 tm.tm_isdst = 0;
01348
01349 errmsg = find_time_t(&tm, 1, &t);
01350 if (errmsg)
01351 rb_raise(rb_eArgError, "%s", errmsg);
01352 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
01353 }
01354
01355 static struct vtm *
01356 gmtimew(wideval_t timew, struct vtm *result)
01357 {
01358 time_t t;
01359 struct tm tm;
01360 VALUE subsecx;
01361 wideval_t timew2;
01362
01363 if (wlt(timew, WINT2FIXWV(0))) {
01364 gmtimew_noleapsecond(timew, result);
01365 return result;
01366 }
01367
01368 init_leap_second_info();
01369
01370 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
01371 timew = wsub(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
01372 gmtimew_noleapsecond(timew, result);
01373 return result;
01374 }
01375
01376 split_second(timew, &timew2, &subsecx);
01377
01378 t = WV2TIMET(timew2);
01379 if (!gmtime_with_leapsecond(&t, &tm))
01380 return NULL;
01381
01382 result->year = LONG2NUM((long)tm.tm_year + 1900);
01383 result->mon = tm.tm_mon + 1;
01384 result->mday = tm.tm_mday;
01385 result->hour = tm.tm_hour;
01386 result->min = tm.tm_min;
01387 result->sec = tm.tm_sec;
01388 result->subsecx = subsecx;
01389 result->utc_offset = INT2FIX(0);
01390 result->wday = tm.tm_wday;
01391 result->yday = tm.tm_yday+1;
01392 result->isdst = tm.tm_isdst;
01393 result->zone = "UTC";
01394
01395 return result;
01396 }
01397
01398 static struct tm *localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone);
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 static int compat_common_month_table[12][7] = {
01434
01435 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 },
01436 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 },
01437 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
01438 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
01439 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 },
01440 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 },
01441 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
01442 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 },
01443 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
01444 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 },
01445 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
01446 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
01447 };
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474 static int compat_leap_month_table[7] = {
01475
01476 2032, 2016, 2028, 2012, 2024, 2036, 2020,
01477 };
01478
01479 static int
01480 calc_wday(int year, int month, int day)
01481 {
01482 int a, y, m;
01483 int wday;
01484
01485 a = (14 - month) / 12;
01486 y = year + 4800 - a;
01487 m = month + 12 * a - 3;
01488 wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
01489 wday = wday % 7;
01490 return wday;
01491 }
01492
01493 static VALUE
01494 guess_local_offset(struct vtm *vtm_utc, int *isdst_ret, const char **zone_ret)
01495 {
01496 struct tm tm;
01497 long gmtoff;
01498 const char *zone;
01499 time_t t;
01500 struct vtm vtm2;
01501 VALUE timev;
01502 int y, wday;
01503
01504
01505
01506 if (lt(vtm_utc->year, INT2FIX(1916))) {
01507 VALUE off = INT2FIX(0);
01508 int isdst = 0;
01509 zone = "UTC";
01510
01511 # if defined(NEGATIVE_TIME_T)
01512 # if SIZEOF_TIME_T <= 4
01513
01514 # define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
01515 # else
01516
01517
01518 # define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
01519 # endif
01520 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
01521 off = LONG2FIX(gmtoff);
01522 isdst = tm.tm_isdst;
01523 }
01524 else
01525 # endif
01526
01527 if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
01528 off = LONG2FIX(gmtoff);
01529 isdst = tm.tm_isdst;
01530 }
01531
01532 if (isdst_ret)
01533 *isdst_ret = isdst;
01534 if (zone_ret)
01535 *zone_ret = zone;
01536 return off;
01537 }
01538
01539
01540
01541 vtm2 = *vtm_utc;
01542
01543
01544 y = NUM2INT(mod(vtm_utc->year, INT2FIX(400)));
01545 wday = calc_wday(y, vtm_utc->mon, 1);
01546 if (vtm_utc->mon == 2 && leap_year_p(y))
01547 vtm2.year = INT2FIX(compat_leap_month_table[wday]);
01548 else
01549 vtm2.year = INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
01550
01551 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
01552 t = NUM2TIMET(timev);
01553 zone = "UTC";
01554 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
01555 if (isdst_ret)
01556 *isdst_ret = tm.tm_isdst;
01557 if (zone_ret)
01558 *zone_ret = zone;
01559 return LONG2FIX(gmtoff);
01560 }
01561
01562 {
01563
01564 static time_t now = 0;
01565 static long now_gmtoff = 0;
01566 static const char *now_zone = "UTC";
01567 if (now == 0) {
01568 now = time(NULL);
01569 localtime_with_gmtoff_zone(&now, &tm, &now_gmtoff, &now_zone);
01570 }
01571 if (isdst_ret)
01572 *isdst_ret = tm.tm_isdst;
01573 if (zone_ret)
01574 *zone_ret = now_zone;
01575 return LONG2FIX(now_gmtoff);
01576 }
01577 }
01578
01579 static VALUE
01580 small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
01581 {
01582 int off;
01583
01584 off = vtm1->sec - vtm2->sec;
01585 off += (vtm1->min - vtm2->min) * 60;
01586 off += (vtm1->hour - vtm2->hour) * 3600;
01587 if (ne(vtm1->year, vtm2->year))
01588 off += lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
01589 else if (vtm1->mon != vtm2->mon)
01590 off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
01591 else if (vtm1->mday != vtm2->mday)
01592 off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
01593
01594 return INT2FIX(off);
01595 }
01596
01597 static wideval_t
01598 timelocalw(struct vtm *vtm)
01599 {
01600 time_t t;
01601 struct tm tm;
01602 VALUE v;
01603 wideval_t timew1, timew2;
01604 struct vtm vtm1, vtm2;
01605 int n;
01606
01607 if (FIXNUM_P(vtm->year)) {
01608 long l = FIX2LONG(vtm->year) - 1900;
01609 if (l < INT_MIN || INT_MAX < l)
01610 goto no_localtime;
01611 tm.tm_year = (int)l;
01612 }
01613 else {
01614 v = sub(vtm->year, INT2FIX(1900));
01615 if (lt(v, INT2NUM(INT_MIN)) || lt(INT2NUM(INT_MAX), v))
01616 goto no_localtime;
01617 tm.tm_year = NUM2INT(v);
01618 }
01619
01620 tm.tm_mon = vtm->mon-1;
01621 tm.tm_mday = vtm->mday;
01622 tm.tm_hour = vtm->hour;
01623 tm.tm_min = vtm->min;
01624 tm.tm_sec = vtm->sec;
01625 tm.tm_isdst = vtm->isdst;
01626
01627 if (find_time_t(&tm, 0, &t))
01628 goto no_localtime;
01629 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
01630
01631 no_localtime:
01632 timew1 = timegmw(vtm);
01633
01634 if (!localtimew(timew1, &vtm1))
01635 rb_raise(rb_eArgError, "localtimew error");
01636
01637 n = vtmcmp(vtm, &vtm1);
01638 if (n == 0) {
01639 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(12*3600)));
01640 if (!localtimew(timew1, &vtm1))
01641 rb_raise(rb_eArgError, "localtimew error");
01642 n = 1;
01643 }
01644
01645 if (n < 0) {
01646 timew2 = timew1;
01647 vtm2 = vtm1;
01648 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
01649 if (!localtimew(timew1, &vtm1))
01650 rb_raise(rb_eArgError, "localtimew error");
01651 }
01652 else {
01653 timew2 = wadd(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
01654 if (!localtimew(timew2, &vtm2))
01655 rb_raise(rb_eArgError, "localtimew error");
01656 }
01657 timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
01658 timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
01659
01660 if (weq(timew1, timew2))
01661 return timew1;
01662
01663 if (!localtimew(timew1, &vtm1))
01664 rb_raise(rb_eArgError, "localtimew error");
01665 if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
01666 return timew2;
01667
01668 if (!localtimew(timew2, &vtm2))
01669 rb_raise(rb_eArgError, "localtimew error");
01670 if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
01671 return timew1;
01672
01673 if (vtm->isdst)
01674 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
01675 else
01676 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
01677 }
01678
01679 static struct tm *
01680 localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone)
01681 {
01682 struct tm tm;
01683
01684 if (LOCALTIME(t, tm)) {
01685 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
01686 *gmtoff = tm.tm_gmtoff;
01687 #else
01688 struct tm *u, *l;
01689 long off;
01690 struct tm tmbuf;
01691 l = &tm;
01692 u = GMTIME(t, tmbuf);
01693 if (!u)
01694 return NULL;
01695 if (l->tm_year != u->tm_year)
01696 off = l->tm_year < u->tm_year ? -1 : 1;
01697 else if (l->tm_mon != u->tm_mon)
01698 off = l->tm_mon < u->tm_mon ? -1 : 1;
01699 else if (l->tm_mday != u->tm_mday)
01700 off = l->tm_mday < u->tm_mday ? -1 : 1;
01701 else
01702 off = 0;
01703 off = off * 24 + l->tm_hour - u->tm_hour;
01704 off = off * 60 + l->tm_min - u->tm_min;
01705 off = off * 60 + l->tm_sec - u->tm_sec;
01706 *gmtoff = off;
01707 #endif
01708
01709 if (zone) {
01710 #if defined(HAVE_TM_ZONE)
01711 *zone = zone_str(tm.tm_zone);
01712 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
01713
01714 *zone = zone_str(tzname[daylight && tm.tm_isdst]);
01715 #else
01716 {
01717 char buf[64];
01718 strftime(buf, sizeof(buf), "%Z", &tm);
01719 *zone = zone_str(buf);
01720 }
01721 #endif
01722 }
01723
01724 *result = tm;
01725 return result;
01726 }
01727 return NULL;
01728 }
01729
01730 static int
01731 timew_out_of_timet_range(wideval_t timew)
01732 {
01733 VALUE timexv;
01734 #if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T
01735 if (FIXWV_P(timew)) {
01736 wideint_t t = FIXWV2WINT(timew);
01737 if (t < TIME_SCALE * (wideint_t)TIMET_MIN ||
01738 TIME_SCALE * (1 + (wideint_t)TIMET_MAX) <= t)
01739 return 1;
01740 return 0;
01741 }
01742 #endif
01743 timexv = w2v(timew);
01744 if (lt(timexv, mul(INT2FIX(TIME_SCALE), TIMET2NUM(TIMET_MIN))) ||
01745 le(mul(INT2FIX(TIME_SCALE), add(TIMET2NUM(TIMET_MAX), INT2FIX(1))), timexv))
01746 return 1;
01747 return 0;
01748 }
01749
01750 static struct vtm *
01751 localtimew(wideval_t timew, struct vtm *result)
01752 {
01753 VALUE subsecx, offset;
01754 const char *zone;
01755 int isdst;
01756
01757 if (!timew_out_of_timet_range(timew)) {
01758 time_t t;
01759 struct tm tm;
01760 long gmtoff;
01761 wideval_t timew2;
01762
01763 split_second(timew, &timew2, &subsecx);
01764
01765 t = WV2TIMET(timew2);
01766
01767 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
01768 result->year = LONG2NUM((long)tm.tm_year + 1900);
01769 result->mon = tm.tm_mon + 1;
01770 result->mday = tm.tm_mday;
01771 result->hour = tm.tm_hour;
01772 result->min = tm.tm_min;
01773 result->sec = tm.tm_sec;
01774 result->subsecx = subsecx;
01775 result->wday = tm.tm_wday;
01776 result->yday = tm.tm_yday+1;
01777 result->isdst = tm.tm_isdst;
01778 result->utc_offset = LONG2NUM(gmtoff);
01779 result->zone = zone;
01780 return result;
01781 }
01782 }
01783
01784 if (!gmtimew(timew, result))
01785 return NULL;
01786
01787 offset = guess_local_offset(result, &isdst, &zone);
01788
01789 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
01790 return NULL;
01791
01792 result->utc_offset = offset;
01793 result->isdst = isdst;
01794 result->zone = zone;
01795
01796 return result;
01797 }
01798
01799 struct time_object {
01800 wideval_t timew;
01801 struct vtm vtm;
01802 int gmt;
01803 int tm_got;
01804 };
01805
01806 #define GetTimeval(obj, tobj) \
01807 TypedData_Get_Struct((obj), struct time_object, &time_data_type, (tobj))
01808
01809 #define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type)
01810
01811 #define TIME_UTC_P(tobj) ((tobj)->gmt == 1)
01812 #define TIME_SET_UTC(tobj) ((tobj)->gmt = 1)
01813
01814 #define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0)
01815 #define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0)
01816
01817 #define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2)
01818 #define TIME_SET_FIXOFF(tobj, off) \
01819 ((tobj)->gmt = 2, \
01820 (tobj)->vtm.utc_offset = (off), \
01821 (tobj)->vtm.zone = NULL)
01822
01823 #define TIME_COPY_GMT(tobj1, tobj2) \
01824 ((tobj1)->gmt = (tobj2)->gmt, \
01825 (tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \
01826 (tobj1)->vtm.zone = (tobj2)->vtm.zone)
01827
01828 static VALUE time_get_tm(VALUE, struct time_object *);
01829 #define MAKE_TM(time, tobj) \
01830 do { \
01831 if ((tobj)->tm_got == 0) { \
01832 time_get_tm((time), (tobj)); \
01833 } \
01834 } while (0)
01835
01836 static void
01837 time_mark(void *ptr)
01838 {
01839 struct time_object *tobj = ptr;
01840 if (!tobj) return;
01841 if (!FIXWV_P(tobj->timew))
01842 rb_gc_mark(w2v(tobj->timew));
01843 rb_gc_mark(tobj->vtm.year);
01844 rb_gc_mark(tobj->vtm.subsecx);
01845 rb_gc_mark(tobj->vtm.utc_offset);
01846 }
01847
01848 static void
01849 time_free(void *tobj)
01850 {
01851 if (tobj) xfree(tobj);
01852 }
01853
01854 static size_t
01855 time_memsize(const void *tobj)
01856 {
01857 return tobj ? sizeof(struct time_object) : 0;
01858 }
01859
01860 static const rb_data_type_t time_data_type = {
01861 "time",
01862 {time_mark, time_free, time_memsize,},
01863 };
01864
01865 static VALUE
01866 time_s_alloc(VALUE klass)
01867 {
01868 VALUE obj;
01869 struct time_object *tobj;
01870
01871 obj = TypedData_Make_Struct(klass, struct time_object, &time_data_type, tobj);
01872 tobj->tm_got=0;
01873 tobj->timew = WINT2FIXWV(0);
01874
01875 return obj;
01876 }
01877
01878 static void
01879 time_modify(VALUE time)
01880 {
01881 rb_check_frozen(time);
01882 if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
01883 rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
01884 }
01885
01886 static wideval_t
01887 timespec2timew(struct timespec *ts)
01888 {
01889 wideval_t timew;
01890
01891 timew = rb_time_magnify(TIMET2WV(ts->tv_sec));
01892 if (ts->tv_nsec)
01893 timew = wadd(timew, wmulquoll(WINT2WV(ts->tv_nsec), TIME_SCALE, 1000000000));
01894 return timew;
01895 }
01896
01897 static struct timespec
01898 timew2timespec(wideval_t timew)
01899 {
01900 VALUE subsecx;
01901 struct timespec ts;
01902 wideval_t timew2;
01903
01904 if (timew_out_of_timet_range(timew))
01905 rb_raise(rb_eArgError, "time out of system range");
01906 split_second(timew, &timew2, &subsecx);
01907 ts.tv_sec = WV2TIMET(timew2);
01908 ts.tv_nsec = NUM2LONG(mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE)));
01909 return ts;
01910 }
01911
01912 static struct timespec *
01913 timew2timespec_exact(wideval_t timew, struct timespec *ts)
01914 {
01915 VALUE subsecx;
01916 wideval_t timew2;
01917 VALUE nsecv;
01918
01919 if (timew_out_of_timet_range(timew))
01920 return NULL;
01921 split_second(timew, &timew2, &subsecx);
01922 ts->tv_sec = WV2TIMET(timew2);
01923 nsecv = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
01924 if (!FIXNUM_P(nsecv))
01925 return NULL;
01926 ts->tv_nsec = NUM2LONG(nsecv);
01927 return ts;
01928 }
01929
01930
01931
01932
01933
01934
01935
01936
01937 static VALUE
01938 time_init_0(VALUE time)
01939 {
01940 struct time_object *tobj;
01941 struct timespec ts;
01942
01943 time_modify(time);
01944 GetTimeval(time, tobj);
01945 tobj->tm_got=0;
01946 tobj->timew = WINT2FIXWV(0);
01947 #ifdef HAVE_CLOCK_GETTIME
01948 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
01949 rb_sys_fail("clock_gettime");
01950 }
01951 #else
01952 {
01953 struct timeval tv;
01954 if (gettimeofday(&tv, 0) < 0) {
01955 rb_sys_fail("gettimeofday");
01956 }
01957 ts.tv_sec = tv.tv_sec;
01958 ts.tv_nsec = tv.tv_usec * 1000;
01959 }
01960 #endif
01961 tobj->timew = timespec2timew(&ts);
01962
01963 return time;
01964 }
01965
01966 static VALUE
01967 time_set_utc_offset(VALUE time, VALUE off)
01968 {
01969 struct time_object *tobj;
01970 off = num_exact(off);
01971
01972 time_modify(time);
01973 GetTimeval(time, tobj);
01974
01975 tobj->tm_got = 0;
01976 TIME_SET_FIXOFF(tobj, off);
01977
01978 return time;
01979 }
01980
01981 static void
01982 vtm_add_offset(struct vtm *vtm, VALUE off)
01983 {
01984 int sign;
01985 VALUE subsec, v;
01986 int sec, min, hour;
01987 int day;
01988
01989 vtm->utc_offset = sub(vtm->utc_offset, off);
01990
01991 if (lt(off, INT2FIX(0))) {
01992 sign = -1;
01993 off = neg(off);
01994 }
01995 else {
01996 sign = 1;
01997 }
01998 divmodv(off, INT2FIX(1), &off, &subsec);
01999 divmodv(off, INT2FIX(60), &off, &v);
02000 sec = NUM2INT(v);
02001 divmodv(off, INT2FIX(60), &off, &v);
02002 min = NUM2INT(v);
02003 divmodv(off, INT2FIX(24), &off, &v);
02004 hour = NUM2INT(v);
02005
02006 if (sign < 0) {
02007 subsec = neg(subsec);
02008 sec = -sec;
02009 min = -min;
02010 hour = -hour;
02011 }
02012
02013 day = 0;
02014
02015 if (!rb_equal(subsec, INT2FIX(0))) {
02016 vtm->subsecx = add(vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
02017 if (lt(vtm->subsecx, INT2FIX(0))) {
02018 vtm->subsecx = add(vtm->subsecx, INT2FIX(TIME_SCALE));
02019 sec -= 1;
02020 }
02021 if (le(INT2FIX(TIME_SCALE), vtm->subsecx)) {
02022 vtm->subsecx = sub(vtm->subsecx, INT2FIX(TIME_SCALE));
02023 sec += 1;
02024 }
02025 goto not_zero_sec;
02026 }
02027 if (sec) {
02028 not_zero_sec:
02029
02030
02031 vtm->sec += sec;
02032 if (vtm->sec < 0) {
02033 vtm->sec += 60;
02034 min -= 1;
02035 }
02036 if (60 <= vtm->sec) {
02037 vtm->sec -= 60;
02038 min += 1;
02039 }
02040 }
02041 if (min) {
02042 vtm->min += min;
02043 if (vtm->min < 0) {
02044 vtm->min += 60;
02045 hour -= 1;
02046 }
02047 if (60 <= vtm->min) {
02048 vtm->min -= 60;
02049 hour += 1;
02050 }
02051 }
02052 if (hour) {
02053 vtm->hour += hour;
02054 if (vtm->hour < 0) {
02055 vtm->hour += 24;
02056 day = -1;
02057 }
02058 if (24 <= vtm->hour) {
02059 vtm->hour -= 24;
02060 day = 1;
02061 }
02062 }
02063
02064 if (day) {
02065 if (day < 0) {
02066 if (vtm->mon == 1 && vtm->mday == 1) {
02067 vtm->mday = 31;
02068 vtm->mon = 12;
02069 vtm->year = sub(vtm->year, INT2FIX(1));
02070 vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
02071 }
02072 else if (vtm->mday == 1) {
02073 const int *days_in_month = leap_year_v_p(vtm->year) ?
02074 leap_year_days_in_month :
02075 common_year_days_in_month;
02076 vtm->mon--;
02077 vtm->mday = days_in_month[vtm->mon-1];
02078 vtm->yday--;
02079 }
02080 else {
02081 vtm->mday--;
02082 vtm->yday--;
02083 }
02084 vtm->wday = (vtm->wday + 6) % 7;
02085 }
02086 else {
02087 int leap = leap_year_v_p(vtm->year);
02088 if (vtm->mon == 12 && vtm->mday == 31) {
02089 vtm->year = add(vtm->year, INT2FIX(1));
02090 vtm->mon = 1;
02091 vtm->mday = 1;
02092 vtm->yday = 1;
02093 }
02094 else if (vtm->mday == (leap ? leap_year_days_in_month :
02095 common_year_days_in_month)[vtm->mon-1]) {
02096 vtm->mon++;
02097 vtm->mday = 1;
02098 vtm->yday++;
02099 }
02100 else {
02101 vtm->mday++;
02102 vtm->yday++;
02103 }
02104 vtm->wday = (vtm->wday + 1) % 7;
02105 }
02106 }
02107 }
02108
02109 static VALUE
02110 utc_offset_arg(VALUE arg)
02111 {
02112 VALUE tmp;
02113 if (!NIL_P(tmp = rb_check_string_type(arg))) {
02114 int n;
02115 char *s = RSTRING_PTR(tmp);
02116 if (!rb_enc_str_asciicompat_p(tmp) ||
02117 RSTRING_LEN(tmp) != 6 ||
02118 (s[0] != '+' && s[0] != '-') ||
02119 !ISDIGIT(s[1]) ||
02120 !ISDIGIT(s[2]) ||
02121 s[3] != ':' ||
02122 !ISDIGIT(s[4]) ||
02123 !ISDIGIT(s[5]))
02124 rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
02125 n = (s[1] * 10 + s[2] - '0' * 11) * 3600;
02126 n += (s[4] * 10 + s[5] - '0' * 11) * 60;
02127 if (s[0] == '-')
02128 n = -n;
02129 return INT2FIX(n);
02130 }
02131 else {
02132 return num_exact(arg);
02133 }
02134 }
02135
02136 static VALUE
02137 time_init_1(int argc, VALUE *argv, VALUE time)
02138 {
02139 struct vtm vtm;
02140 VALUE v[7];
02141 struct time_object *tobj;
02142
02143 vtm.wday = -1;
02144 vtm.yday = 0;
02145 vtm.zone = "";
02146
02147
02148 rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
02149
02150 vtm.year = obj2vint(v[0]);
02151
02152 vtm.mon = NIL_P(v[1]) ? 1 : month_arg(v[1]);
02153
02154 vtm.mday = NIL_P(v[2]) ? 1 : obj2int(v[2]);
02155
02156 vtm.hour = NIL_P(v[3]) ? 0 : obj2int(v[3]);
02157
02158 vtm.min = NIL_P(v[4]) ? 0 : obj2int(v[4]);
02159
02160 vtm.sec = 0;
02161 vtm.subsecx = INT2FIX(0);
02162 if (!NIL_P(v[5])) {
02163 VALUE sec = num_exact(v[5]);
02164 VALUE subsec;
02165 divmodv(sec, INT2FIX(1), &sec, &subsec);
02166 vtm.sec = NUM2INT(sec);
02167 vtm.subsecx = w2v(rb_time_magnify(v2w(subsec)));
02168 }
02169
02170 vtm.isdst = -1;
02171 vtm.utc_offset = Qnil;
02172 if (!NIL_P(v[6])) {
02173 VALUE arg = v[6];
02174 if (arg == ID2SYM(rb_intern("dst")))
02175 vtm.isdst = 1;
02176 else if (arg == ID2SYM(rb_intern("std")))
02177 vtm.isdst = 0;
02178 else
02179 vtm.utc_offset = utc_offset_arg(arg);
02180 }
02181
02182 validate_vtm(&vtm);
02183
02184 time_modify(time);
02185 GetTimeval(time, tobj);
02186 tobj->tm_got=0;
02187 tobj->timew = WINT2FIXWV(0);
02188
02189 if (!NIL_P(vtm.utc_offset)) {
02190 VALUE off = vtm.utc_offset;
02191 vtm_add_offset(&vtm, neg(off));
02192 vtm.utc_offset = Qnil;
02193 tobj->timew = timegmw(&vtm);
02194 return time_set_utc_offset(time, off);
02195 }
02196 else {
02197 tobj->timew = timelocalw(&vtm);
02198 return time_localtime(time);
02199 }
02200 }
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246 static VALUE
02247 time_init(int argc, VALUE *argv, VALUE time)
02248 {
02249 if (argc == 0)
02250 return time_init_0(time);
02251 else
02252 return time_init_1(argc, argv, time);
02253 }
02254
02255 static void
02256 time_overflow_p(time_t *secp, long *nsecp)
02257 {
02258 time_t tmp, sec = *secp;
02259 long nsec = *nsecp;
02260
02261 if (nsec >= 1000000000) {
02262 tmp = sec + nsec / 1000000000;
02263 nsec %= 1000000000;
02264 if (sec > 0 && tmp < 0) {
02265 rb_raise(rb_eRangeError, "out of Time range");
02266 }
02267 sec = tmp;
02268 }
02269 if (nsec < 0) {
02270 tmp = sec + NDIV(nsec,1000000000);
02271 nsec = NMOD(nsec,1000000000);
02272 if (sec < 0 && tmp > 0) {
02273 rb_raise(rb_eRangeError, "out of Time range");
02274 }
02275 sec = tmp;
02276 }
02277 #ifndef NEGATIVE_TIME_T
02278 if (sec < 0)
02279 rb_raise(rb_eArgError, "time must be positive");
02280 #endif
02281 *secp = sec;
02282 *nsecp = nsec;
02283 }
02284
02285 static wideval_t
02286 nsec2timew(time_t sec, long nsec)
02287 {
02288 struct timespec ts;
02289 time_overflow_p(&sec, &nsec);
02290 ts.tv_sec = sec;
02291 ts.tv_nsec = nsec;
02292 return timespec2timew(&ts);
02293 }
02294
02295 static VALUE
02296 time_new_timew(VALUE klass, wideval_t timew)
02297 {
02298 VALUE time = time_s_alloc(klass);
02299 struct time_object *tobj;
02300
02301 GetTimeval(time, tobj);
02302 tobj->timew = timew;
02303
02304 return time;
02305 }
02306
02307 VALUE
02308 rb_time_new(time_t sec, long usec)
02309 {
02310 wideval_t timew;
02311
02312 if (usec >= 1000000) {
02313 long sec2 = usec / 1000000;
02314 if (sec > TIMET_MAX - sec2) {
02315 rb_raise(rb_eRangeError, "out of Time range");
02316 }
02317 usec -= sec2 * 1000000;
02318 sec += sec2;
02319 }
02320 else if (usec <= 1000000) {
02321 long sec2 = usec / 1000000;
02322 if (sec < -TIMET_MAX - sec2) {
02323 rb_raise(rb_eRangeError, "out of Time range");
02324 }
02325 usec -= sec2 * 1000000;
02326 sec += sec2;
02327 }
02328
02329 timew = nsec2timew(sec, usec * 1000);
02330 return time_new_timew(rb_cTime, timew);
02331 }
02332
02333 VALUE
02334 rb_time_nano_new(time_t sec, long nsec)
02335 {
02336 return time_new_timew(rb_cTime, nsec2timew(sec, nsec));
02337 }
02338
02339 VALUE
02340 rb_time_num_new(VALUE timev, VALUE off)
02341 {
02342 VALUE time = time_new_timew(rb_cTime, rb_time_magnify(v2w(timev)));
02343
02344 if (!NIL_P(off)) {
02345 off = utc_offset_arg(off);
02346 validate_utc_offset(off);
02347 time_set_utc_offset(time, off);
02348 return time;
02349 }
02350
02351 return time;
02352 }
02353
02354 static struct timespec
02355 time_timespec(VALUE num, int interval)
02356 {
02357 struct timespec t;
02358 const char *tstr = interval ? "time interval" : "time";
02359 VALUE i, f, ary;
02360
02361 #ifndef NEGATIVE_TIME_T
02362 interval = 1;
02363 #endif
02364
02365 switch (TYPE(num)) {
02366 case T_FIXNUM:
02367 t.tv_sec = NUM2TIMET(num);
02368 if (interval && t.tv_sec < 0)
02369 rb_raise(rb_eArgError, "%s must be positive", tstr);
02370 t.tv_nsec = 0;
02371 break;
02372
02373 case T_FLOAT:
02374 if (interval && RFLOAT_VALUE(num) < 0.0)
02375 rb_raise(rb_eArgError, "%s must be positive", tstr);
02376 else {
02377 double f, d;
02378
02379 d = modf(RFLOAT_VALUE(num), &f);
02380 if (d >= 0) {
02381 t.tv_nsec = (int)(d*1e9+0.5);
02382 }
02383 else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) {
02384 t.tv_nsec = 1000000000 - t.tv_nsec;
02385 f -= 1;
02386 }
02387 t.tv_sec = (time_t)f;
02388 if (f != t.tv_sec) {
02389 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(num));
02390 }
02391 }
02392 break;
02393
02394 case T_BIGNUM:
02395 t.tv_sec = NUM2TIMET(num);
02396 if (interval && t.tv_sec < 0)
02397 rb_raise(rb_eArgError, "%s must be positive", tstr);
02398 t.tv_nsec = 0;
02399 break;
02400
02401 default:
02402 i = INT2FIX(1);
02403 ary = rb_check_funcall(num, id_divmod, 1, &i);
02404 if (ary != Qundef && !NIL_P(ary = rb_check_array_type(ary))) {
02405 i = rb_ary_entry(ary, 0);
02406 f = rb_ary_entry(ary, 1);
02407 t.tv_sec = NUM2TIMET(i);
02408 if (interval && t.tv_sec < 0)
02409 rb_raise(rb_eArgError, "%s must be positive", tstr);
02410 f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
02411 t.tv_nsec = NUM2LONG(f);
02412 }
02413 else {
02414 rb_raise(rb_eTypeError, "can't convert %s into %s",
02415 rb_obj_classname(num), tstr);
02416 }
02417 break;
02418 }
02419 return t;
02420 }
02421
02422 static struct timeval
02423 time_timeval(VALUE num, int interval)
02424 {
02425 struct timespec ts;
02426 struct timeval tv;
02427
02428 ts = time_timespec(num, interval);
02429 tv.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
02430 tv.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
02431
02432 return tv;
02433 }
02434
02435 struct timeval
02436 rb_time_interval(VALUE num)
02437 {
02438 return time_timeval(num, TRUE);
02439 }
02440
02441 struct timeval
02442 rb_time_timeval(VALUE time)
02443 {
02444 struct time_object *tobj;
02445 struct timeval t;
02446 struct timespec ts;
02447
02448 if (IsTimeval(time)) {
02449 GetTimeval(time, tobj);
02450 ts = timew2timespec(tobj->timew);
02451 t.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
02452 t.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
02453 return t;
02454 }
02455 return time_timeval(time, FALSE);
02456 }
02457
02458 struct timespec
02459 rb_time_timespec(VALUE time)
02460 {
02461 struct time_object *tobj;
02462 struct timespec t;
02463
02464 if (IsTimeval(time)) {
02465 GetTimeval(time, tobj);
02466 t = timew2timespec(tobj->timew);
02467 return t;
02468 }
02469 return time_timespec(time, FALSE);
02470 }
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481 static VALUE
02482 time_s_now(VALUE klass)
02483 {
02484 return rb_class_new_instance(0, NULL, klass);
02485 }
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508 static VALUE
02509 time_s_at(int argc, VALUE *argv, VALUE klass)
02510 {
02511 VALUE time, t;
02512 wideval_t timew;
02513
02514 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
02515 time = num_exact(time);
02516 t = num_exact(t);
02517 timew = wadd(rb_time_magnify(v2w(time)), wmulquoll(v2w(t), TIME_SCALE, 1000000));
02518 t = time_new_timew(klass, timew);
02519 }
02520 else if (IsTimeval(time)) {
02521 struct time_object *tobj, *tobj2;
02522 GetTimeval(time, tobj);
02523 t = time_new_timew(klass, tobj->timew);
02524 GetTimeval(t, tobj2);
02525 TIME_COPY_GMT(tobj2, tobj);
02526 }
02527 else {
02528 timew = rb_time_magnify(v2w(num_exact(time)));
02529 t = time_new_timew(klass, timew);
02530 }
02531
02532 return t;
02533 }
02534
02535 static const char months[][4] = {
02536 "jan", "feb", "mar", "apr", "may", "jun",
02537 "jul", "aug", "sep", "oct", "nov", "dec",
02538 };
02539
02540 static int
02541 obj2int(VALUE obj)
02542 {
02543 if (TYPE(obj) == T_STRING) {
02544 obj = rb_str_to_inum(obj, 10, FALSE);
02545 }
02546
02547 return NUM2INT(obj);
02548 }
02549
02550 static VALUE
02551 obj2vint(VALUE obj)
02552 {
02553 if (TYPE(obj) == T_STRING) {
02554 obj = rb_str_to_inum(obj, 10, FALSE);
02555 }
02556 else {
02557 obj = rb_to_int(obj);
02558 }
02559
02560 return obj;
02561 }
02562
02563 static int
02564 obj2subsecx(VALUE obj, VALUE *subsecx)
02565 {
02566 VALUE subsec;
02567
02568 if (TYPE(obj) == T_STRING) {
02569 obj = rb_str_to_inum(obj, 10, FALSE);
02570 *subsecx = INT2FIX(0);
02571 return NUM2INT(obj);
02572 }
02573
02574 divmodv(num_exact(obj), INT2FIX(1), &obj, &subsec);
02575 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
02576 return NUM2INT(obj);
02577 }
02578
02579 static long
02580 usec2subsecx(VALUE obj)
02581 {
02582 if (TYPE(obj) == T_STRING) {
02583 obj = rb_str_to_inum(obj, 10, FALSE);
02584 }
02585
02586 return mulquo(num_exact(obj), INT2FIX(TIME_SCALE), INT2FIX(1000000));
02587 }
02588
02589 static int
02590 month_arg(VALUE arg)
02591 {
02592 int i, mon;
02593
02594 VALUE s = rb_check_string_type(arg);
02595 if (!NIL_P(s)) {
02596 mon = 0;
02597 for (i=0; i<12; i++) {
02598 if (RSTRING_LEN(s) == 3 &&
02599 STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
02600 mon = i+1;
02601 break;
02602 }
02603 }
02604 if (mon == 0) {
02605 char c = RSTRING_PTR(s)[0];
02606
02607 if ('0' <= c && c <= '9') {
02608 mon = obj2int(s);
02609 }
02610 }
02611 }
02612 else {
02613 mon = obj2int(arg);
02614 }
02615 return mon;
02616 }
02617
02618 static void
02619 validate_utc_offset(VALUE utc_offset)
02620 {
02621 if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400)))
02622 rb_raise(rb_eArgError, "utc_offset out of range");
02623 }
02624
02625 static void
02626 validate_vtm(struct vtm *vtm)
02627 {
02628 if ( vtm->mon < 1 || vtm->mon > 12
02629 || vtm->mday < 1 || vtm->mday > 31
02630 || vtm->hour < 0 || vtm->hour > 24
02631 || (vtm->hour == 24 && (vtm->min > 0 || vtm->sec > 0))
02632 || vtm->min < 0 || vtm->min > 59
02633 || vtm->sec < 0 || vtm->sec > 60
02634 || lt(vtm->subsecx, INT2FIX(0)) || ge(vtm->subsecx, INT2FIX(TIME_SCALE))
02635 || (!NIL_P(vtm->utc_offset) && (validate_utc_offset(vtm->utc_offset), 0)))
02636 rb_raise(rb_eArgError, "argument out of range");
02637 }
02638
02639 static void
02640 time_arg(int argc, VALUE *argv, struct vtm *vtm)
02641 {
02642 VALUE v[8];
02643
02644 vtm->year = INT2FIX(0);
02645 vtm->mon = 0;
02646 vtm->mday = 0;
02647 vtm->hour = 0;
02648 vtm->min = 0;
02649 vtm->sec = 0;
02650 vtm->subsecx = INT2FIX(0);
02651 vtm->utc_offset = Qnil;
02652 vtm->wday = 0;
02653 vtm->yday = 0;
02654 vtm->isdst = 0;
02655 vtm->zone = "";
02656
02657 if (argc == 10) {
02658 v[0] = argv[5];
02659 v[1] = argv[4];
02660 v[2] = argv[3];
02661 v[3] = argv[2];
02662 v[4] = argv[1];
02663 v[5] = argv[0];
02664 v[6] = Qnil;
02665 vtm->isdst = RTEST(argv[8]) ? 1 : 0;
02666 }
02667 else {
02668 rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
02669
02670
02671 vtm->wday = -1;
02672 vtm->isdst = -1;
02673 }
02674
02675 vtm->year = obj2vint(v[0]);
02676
02677 if (NIL_P(v[1])) {
02678 vtm->mon = 1;
02679 }
02680 else {
02681 vtm->mon = month_arg(v[1]);
02682 }
02683
02684 if (NIL_P(v[2])) {
02685 vtm->mday = 1;
02686 }
02687 else {
02688 vtm->mday = obj2int(v[2]);
02689 }
02690
02691 vtm->hour = NIL_P(v[3])?0:obj2int(v[3]);
02692
02693 vtm->min = NIL_P(v[4])?0:obj2int(v[4]);
02694
02695 if (!NIL_P(v[6]) && argc == 7) {
02696 vtm->sec = NIL_P(v[5])?0:obj2int(v[5]);
02697 vtm->subsecx = usec2subsecx(v[6]);
02698 }
02699 else {
02700
02701 vtm->sec = NIL_P(v[5])?0:obj2subsecx(v[5], &vtm->subsecx);
02702 }
02703
02704 validate_vtm(vtm);
02705 }
02706
02707 static int
02708 leap_year_p(long y)
02709 {
02710 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
02711 }
02712
02713 static time_t
02714 timegm_noleapsecond(struct tm *tm)
02715 {
02716 long tm_year = tm->tm_year;
02717 int tm_yday = tm->tm_mday;
02718 if (leap_year_p(tm_year + 1900))
02719 tm_yday += leap_year_yday_offset[tm->tm_mon];
02720 else
02721 tm_yday += common_year_yday_offset[tm->tm_mon];
02722
02723
02724
02725
02726
02727
02728
02729 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
02730 (time_t)(tm_yday +
02731 (tm_year-70)*365 +
02732 DIV(tm_year-69,4) -
02733 DIV(tm_year-1,100) +
02734 DIV(tm_year+299,400))*86400;
02735 }
02736
02737 #if 0
02738 #define DEBUG_FIND_TIME_NUMGUESS
02739 #define DEBUG_GUESSRANGE
02740 #endif
02741
02742 #ifdef DEBUG_GUESSRANGE
02743 #define DEBUG_REPORT_GUESSRANGE fprintf(stderr, "find time guess range: %ld - %ld : %lu\n", guess_lo, guess_hi, (unsigned_time_t)(guess_hi-guess_lo))
02744 #else
02745 #define DEBUG_REPORT_GUESSRANGE
02746 #endif
02747
02748 #ifdef DEBUG_FIND_TIME_NUMGUESS
02749 #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
02750 static unsigned long long find_time_numguess;
02751
02752 static VALUE find_time_numguess_getter(void)
02753 {
02754 return ULL2NUM(find_time_numguess);
02755 }
02756 #else
02757 #define DEBUG_FIND_TIME_NUMGUESS_INC
02758 #endif
02759
02760 static const char *
02761 find_time_t(struct tm *tptr, int utc_p, time_t *tp)
02762 {
02763 time_t guess, guess0, guess_lo, guess_hi;
02764 struct tm *tm, tm0, tm_lo, tm_hi;
02765 int d;
02766 int find_dst;
02767 struct tm result;
02768 int status;
02769 int tptr_tm_yday;
02770
02771 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
02772
02773 guess_lo = TIMET_MIN;
02774 guess_hi = TIMET_MAX;
02775
02776 find_dst = 0 < tptr->tm_isdst;
02777
02778 #if defined(HAVE_MKTIME)
02779 tm0 = *tptr;
02780 if (!utc_p && (guess = mktime(&tm0)) != -1) {
02781 tm = GUESS(&guess);
02782 if (tm && tmcmp(tptr, tm) == 0) {
02783 goto found;
02784 }
02785 }
02786 #endif
02787
02788 tm0 = *tptr;
02789 if (tm0.tm_mon < 0) {
02790 tm0.tm_mon = 0;
02791 tm0.tm_mday = 1;
02792 tm0.tm_hour = 0;
02793 tm0.tm_min = 0;
02794 tm0.tm_sec = 0;
02795 }
02796 else if (11 < tm0.tm_mon) {
02797 tm0.tm_mon = 11;
02798 tm0.tm_mday = 31;
02799 tm0.tm_hour = 23;
02800 tm0.tm_min = 59;
02801 tm0.tm_sec = 60;
02802 }
02803 else if (tm0.tm_mday < 1) {
02804 tm0.tm_mday = 1;
02805 tm0.tm_hour = 0;
02806 tm0.tm_min = 0;
02807 tm0.tm_sec = 0;
02808 }
02809 else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
02810 leap_year_days_in_month :
02811 common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
02812 tm0.tm_mday = d;
02813 tm0.tm_hour = 23;
02814 tm0.tm_min = 59;
02815 tm0.tm_sec = 60;
02816 }
02817 else if (tm0.tm_hour < 0) {
02818 tm0.tm_hour = 0;
02819 tm0.tm_min = 0;
02820 tm0.tm_sec = 0;
02821 }
02822 else if (23 < tm0.tm_hour) {
02823 tm0.tm_hour = 23;
02824 tm0.tm_min = 59;
02825 tm0.tm_sec = 60;
02826 }
02827 else if (tm0.tm_min < 0) {
02828 tm0.tm_min = 0;
02829 tm0.tm_sec = 0;
02830 }
02831 else if (59 < tm0.tm_min) {
02832 tm0.tm_min = 59;
02833 tm0.tm_sec = 60;
02834 }
02835 else if (tm0.tm_sec < 0) {
02836 tm0.tm_sec = 0;
02837 }
02838 else if (60 < tm0.tm_sec) {
02839 tm0.tm_sec = 60;
02840 }
02841
02842 DEBUG_REPORT_GUESSRANGE;
02843 guess0 = guess = timegm_noleapsecond(&tm0);
02844 tm = GUESS(&guess);
02845 if (tm) {
02846 d = tmcmp(tptr, tm);
02847 if (d == 0) { goto found; }
02848 if (d < 0) {
02849 guess_hi = guess;
02850 guess -= 24 * 60 * 60;
02851 }
02852 else {
02853 guess_lo = guess;
02854 guess += 24 * 60 * 60;
02855 }
02856 DEBUG_REPORT_GUESSRANGE;
02857 if (guess_lo < guess && guess < guess_hi && (tm = GUESS(&guess)) != NULL) {
02858 d = tmcmp(tptr, tm);
02859 if (d == 0) { goto found; }
02860 if (d < 0)
02861 guess_hi = guess;
02862 else
02863 guess_lo = guess;
02864 DEBUG_REPORT_GUESSRANGE;
02865 }
02866 }
02867
02868 tm = GUESS(&guess_lo);
02869 if (!tm) goto error;
02870 d = tmcmp(tptr, tm);
02871 if (d < 0) goto out_of_range;
02872 if (d == 0) { guess = guess_lo; goto found; }
02873 tm_lo = *tm;
02874
02875 tm = GUESS(&guess_hi);
02876 if (!tm) goto error;
02877 d = tmcmp(tptr, tm);
02878 if (d > 0) goto out_of_range;
02879 if (d == 0) { guess = guess_hi; goto found; }
02880 tm_hi = *tm;
02881
02882 DEBUG_REPORT_GUESSRANGE;
02883
02884 status = 1;
02885
02886 while (guess_lo + 1 < guess_hi) {
02887 if (status == 0) {
02888 binsearch:
02889 guess = guess_lo / 2 + guess_hi / 2;
02890 if (guess <= guess_lo)
02891 guess = guess_lo + 1;
02892 else if (guess >= guess_hi)
02893 guess = guess_hi - 1;
02894 status = 1;
02895 }
02896 else {
02897 if (status == 1) {
02898 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
02899 guess = guess_hi - (guess0_hi - guess0);
02900 if (guess == guess_hi)
02901 guess--;
02902 status = 2;
02903 }
02904 else if (status == 2) {
02905 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
02906 guess = guess_lo + (guess0 - guess0_lo);
02907 if (guess == guess_lo)
02908 guess++;
02909 status = 0;
02910 }
02911 if (guess <= guess_lo || guess_hi <= guess) {
02912
02913 #ifdef DEBUG_GUESSRANGE
02914 if (guess <= guess_lo) fprintf(stderr, "too small guess: %ld <= %ld\n", guess, guess_lo);
02915 if (guess_hi <= guess) fprintf(stderr, "too big guess: %ld <= %ld\n", guess_hi, guess);
02916 #endif
02917 goto binsearch;
02918 }
02919 }
02920
02921 tm = GUESS(&guess);
02922 if (!tm) goto error;
02923
02924 d = tmcmp(tptr, tm);
02925
02926 if (d < 0) {
02927 guess_hi = guess;
02928 tm_hi = *tm;
02929 DEBUG_REPORT_GUESSRANGE;
02930 }
02931 else if (d > 0) {
02932 guess_lo = guess;
02933 tm_lo = *tm;
02934 DEBUG_REPORT_GUESSRANGE;
02935 }
02936 else {
02937 found:
02938 if (!utc_p) {
02939
02940 time_t guess2;
02941 if (find_dst) {
02942 guess2 = guess - 2 * 60 * 60;
02943 tm = LOCALTIME(&guess2, result);
02944 if (tm) {
02945 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
02946 tptr->tm_min != tm->tm_min ||
02947 tptr->tm_sec != tm->tm_sec) {
02948 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
02949 (tm->tm_min - tptr->tm_min) * 60 +
02950 (tm->tm_sec - tptr->tm_sec);
02951 if (tptr->tm_mday != tm->tm_mday)
02952 guess2 += 24 * 60 * 60;
02953 if (guess != guess2) {
02954 tm = LOCALTIME(&guess2, result);
02955 if (tm && tmcmp(tptr, tm) == 0) {
02956 if (guess < guess2)
02957 *tp = guess;
02958 else
02959 *tp = guess2;
02960 return NULL;
02961 }
02962 }
02963 }
02964 }
02965 }
02966 else {
02967 guess2 = guess + 2 * 60 * 60;
02968 tm = LOCALTIME(&guess2, result);
02969 if (tm) {
02970 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
02971 tptr->tm_min != tm->tm_min ||
02972 tptr->tm_sec != tm->tm_sec) {
02973 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
02974 (tm->tm_min - tptr->tm_min) * 60 +
02975 (tm->tm_sec - tptr->tm_sec);
02976 if (tptr->tm_mday != tm->tm_mday)
02977 guess2 -= 24 * 60 * 60;
02978 if (guess != guess2) {
02979 tm = LOCALTIME(&guess2, result);
02980 if (tm && tmcmp(tptr, tm) == 0) {
02981 if (guess < guess2)
02982 *tp = guess2;
02983 else
02984 *tp = guess;
02985 return NULL;
02986 }
02987 }
02988 }
02989 }
02990 }
02991 }
02992 *tp = guess;
02993 return NULL;
02994 }
02995 }
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
03006
03007 *tp = guess_lo +
03008 ((tptr->tm_year - tm_lo.tm_year) * 365 +
03009 ((tptr->tm_year-69)/4) -
03010 ((tptr->tm_year-1)/100) +
03011 ((tptr->tm_year+299)/400) -
03012 ((tm_lo.tm_year-69)/4) +
03013 ((tm_lo.tm_year-1)/100) -
03014 ((tm_lo.tm_year+299)/400) +
03015 tptr_tm_yday -
03016 tm_lo.tm_yday) * 86400 +
03017 (tptr->tm_hour - tm_lo.tm_hour) * 3600 +
03018 (tptr->tm_min - tm_lo.tm_min) * 60 +
03019 (tptr->tm_sec - (tm_lo.tm_sec == 60 ? 59 : tm_lo.tm_sec));
03020
03021 return NULL;
03022
03023 out_of_range:
03024 return "time out of range";
03025
03026 error:
03027 return "gmtime/localtime error";
03028 }
03029
03030 static int
03031 vtmcmp(struct vtm *a, struct vtm *b)
03032 {
03033 if (ne(a->year, b->year))
03034 return lt(a->year, b->year) ? -1 : 1;
03035 else if (a->mon != b->mon)
03036 return a->mon < b->mon ? -1 : 1;
03037 else if (a->mday != b->mday)
03038 return a->mday < b->mday ? -1 : 1;
03039 else if (a->hour != b->hour)
03040 return a->hour < b->hour ? -1 : 1;
03041 else if (a->min != b->min)
03042 return a->min < b->min ? -1 : 1;
03043 else if (a->sec != b->sec)
03044 return a->sec < b->sec ? -1 : 1;
03045 else if (ne(a->subsecx, b->subsecx))
03046 return lt(a->subsecx, b->subsecx) ? -1 : 1;
03047 else
03048 return 0;
03049 }
03050
03051 static int
03052 tmcmp(struct tm *a, struct tm *b)
03053 {
03054 if (a->tm_year != b->tm_year)
03055 return a->tm_year < b->tm_year ? -1 : 1;
03056 else if (a->tm_mon != b->tm_mon)
03057 return a->tm_mon < b->tm_mon ? -1 : 1;
03058 else if (a->tm_mday != b->tm_mday)
03059 return a->tm_mday < b->tm_mday ? -1 : 1;
03060 else if (a->tm_hour != b->tm_hour)
03061 return a->tm_hour < b->tm_hour ? -1 : 1;
03062 else if (a->tm_min != b->tm_min)
03063 return a->tm_min < b->tm_min ? -1 : 1;
03064 else if (a->tm_sec != b->tm_sec)
03065 return a->tm_sec < b->tm_sec ? -1 : 1;
03066 else
03067 return 0;
03068 }
03069
03070 static VALUE
03071 time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
03072 {
03073 struct vtm vtm;
03074 VALUE time;
03075
03076 time_arg(argc, argv, &vtm);
03077 if (utc_p)
03078 time = time_new_timew(klass, timegmw(&vtm));
03079 else
03080 time = time_new_timew(klass, timelocalw(&vtm));
03081 if (utc_p) return time_gmtime(time);
03082 return time_localtime(time);
03083 }
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100
03101
03102
03103
03104
03105
03106
03107
03108
03109
03110
03111
03112
03113
03114
03115
03116
03117 static VALUE
03118 time_s_mkutc(int argc, VALUE *argv, VALUE klass)
03119 {
03120 return time_utc_or_local(argc, argv, TRUE, klass);
03121 }
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148 static VALUE
03149 time_s_mktime(int argc, VALUE *argv, VALUE klass)
03150 {
03151 return time_utc_or_local(argc, argv, FALSE, klass);
03152 }
03153
03154
03155
03156
03157
03158
03159
03160
03161
03162
03163
03164
03165
03166
03167 static VALUE
03168 time_to_i(VALUE time)
03169 {
03170 struct time_object *tobj;
03171
03172 GetTimeval(time, tobj);
03173 return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE)));
03174 }
03175
03176
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191 static VALUE
03192 time_to_f(VALUE time)
03193 {
03194 struct time_object *tobj;
03195
03196 GetTimeval(time, tobj);
03197 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
03198 }
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215 static VALUE
03216 time_to_r(VALUE time)
03217 {
03218 struct time_object *tobj;
03219 VALUE v;
03220
03221 GetTimeval(time, tobj);
03222 v = w2v(rb_time_unmagnify(tobj->timew));
03223 if (TYPE(v) != T_RATIONAL) {
03224 v = rb_Rational1(v);
03225 }
03226 return v;
03227 }
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241 static VALUE
03242 time_usec(VALUE time)
03243 {
03244 struct time_object *tobj;
03245 wideval_t w, q, r;
03246
03247 GetTimeval(time, tobj);
03248
03249 w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
03250 wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
03251 return rb_to_int(w2v(q));
03252 }
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271 static VALUE
03272 time_nsec(VALUE time)
03273 {
03274 struct time_object *tobj;
03275
03276 GetTimeval(time, tobj);
03277 return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
03278 }
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298 static VALUE
03299 time_subsec(VALUE time)
03300 {
03301 struct time_object *tobj;
03302
03303 GetTimeval(time, tobj);
03304 return quo(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))), INT2FIX(TIME_SCALE));
03305 }
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327 static VALUE
03328 time_cmp(VALUE time1, VALUE time2)
03329 {
03330 struct time_object *tobj1, *tobj2;
03331 int n;
03332
03333 GetTimeval(time1, tobj1);
03334 if (IsTimeval(time2)) {
03335 GetTimeval(time2, tobj2);
03336 n = wcmp(tobj1->timew, tobj2->timew);
03337 }
03338 else {
03339 VALUE tmp;
03340
03341 tmp = rb_funcall(time2, rb_intern("<=>"), 1, time1);
03342 if (NIL_P(tmp)) return Qnil;
03343
03344 n = -rb_cmpint(tmp, time1, time2);
03345 }
03346 if (n == 0) return INT2FIX(0);
03347 if (n > 0) return INT2FIX(1);
03348 return INT2FIX(-1);
03349 }
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360 static VALUE
03361 time_eql(VALUE time1, VALUE time2)
03362 {
03363 struct time_object *tobj1, *tobj2;
03364
03365 GetTimeval(time1, tobj1);
03366 if (IsTimeval(time2)) {
03367 GetTimeval(time2, tobj2);
03368 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
03369 }
03370 return Qfalse;
03371 }
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392 static VALUE
03393 time_utc_p(VALUE time)
03394 {
03395 struct time_object *tobj;
03396
03397 GetTimeval(time, tobj);
03398 if (TIME_UTC_P(tobj)) return Qtrue;
03399 return Qfalse;
03400 }
03401
03402
03403
03404
03405
03406
03407
03408
03409 static VALUE
03410 time_hash(VALUE time)
03411 {
03412 struct time_object *tobj;
03413
03414 GetTimeval(time, tobj);
03415 return rb_hash(w2v(tobj->timew));
03416 }
03417
03418
03419 static VALUE
03420 time_init_copy(VALUE copy, VALUE time)
03421 {
03422 struct time_object *tobj, *tcopy;
03423
03424 if (copy == time) return copy;
03425 time_modify(copy);
03426 GetTimeval(time, tobj);
03427 GetTimeval(copy, tcopy);
03428 MEMCPY(tcopy, tobj, struct time_object, 1);
03429
03430 return copy;
03431 }
03432
03433 static VALUE
03434 time_dup(VALUE time)
03435 {
03436 VALUE dup = time_s_alloc(rb_obj_class(time));
03437 time_init_copy(dup, time);
03438 return dup;
03439 }
03440
03441 static VALUE
03442 time_localtime(VALUE time)
03443 {
03444 struct time_object *tobj;
03445 struct vtm vtm;
03446
03447 GetTimeval(time, tobj);
03448 if (TIME_LOCALTIME_P(tobj)) {
03449 if (tobj->tm_got)
03450 return time;
03451 }
03452 else {
03453 time_modify(time);
03454 }
03455
03456 if (!localtimew(tobj->timew, &vtm))
03457 rb_raise(rb_eArgError, "localtime error");
03458 tobj->vtm = vtm;
03459
03460 tobj->tm_got = 1;
03461 TIME_SET_LOCALTIME(tobj);
03462 return time;
03463 }
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485 static VALUE
03486 time_localtime_m(int argc, VALUE *argv, VALUE time)
03487 {
03488 VALUE off;
03489 rb_scan_args(argc, argv, "01", &off);
03490
03491 if (!NIL_P(off)) {
03492 off = utc_offset_arg(off);
03493 validate_utc_offset(off);
03494
03495 time_set_utc_offset(time, off);
03496 return time_fixoff(time);
03497 }
03498
03499 return time_localtime(time);
03500 }
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513
03514
03515
03516
03517
03518
03519
03520 static VALUE
03521 time_gmtime(VALUE time)
03522 {
03523 struct time_object *tobj;
03524 struct vtm vtm;
03525
03526 GetTimeval(time, tobj);
03527 if (TIME_UTC_P(tobj)) {
03528 if (tobj->tm_got)
03529 return time;
03530 }
03531 else {
03532 time_modify(time);
03533 }
03534
03535 if (!gmtimew(tobj->timew, &vtm))
03536 rb_raise(rb_eArgError, "gmtime error");
03537 tobj->vtm = vtm;
03538
03539 tobj->tm_got = 1;
03540 TIME_SET_UTC(tobj);
03541 return time;
03542 }
03543
03544 static VALUE
03545 time_fixoff(VALUE time)
03546 {
03547 struct time_object *tobj;
03548 struct vtm vtm;
03549 VALUE off;
03550
03551 GetTimeval(time, tobj);
03552 if (TIME_FIXOFF_P(tobj)) {
03553 if (tobj->tm_got)
03554 return time;
03555 }
03556 else {
03557 time_modify(time);
03558 }
03559
03560 if (TIME_FIXOFF_P(tobj))
03561 off = tobj->vtm.utc_offset;
03562 else
03563 off = INT2FIX(0);
03564
03565 if (!gmtimew(tobj->timew, &vtm))
03566 rb_raise(rb_eArgError, "gmtime error");
03567
03568 tobj->vtm = vtm;
03569 vtm_add_offset(&tobj->vtm, off);
03570
03571 tobj->tm_got = 1;
03572 TIME_SET_FIXOFF(tobj, off);
03573 return time;
03574 }
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597
03598 static VALUE
03599 time_getlocaltime(int argc, VALUE *argv, VALUE time)
03600 {
03601 VALUE off;
03602 rb_scan_args(argc, argv, "01", &off);
03603
03604 if (!NIL_P(off)) {
03605 off = utc_offset_arg(off);
03606 validate_utc_offset(off);
03607
03608 time = time_dup(time);
03609 time_set_utc_offset(time, off);
03610 return time_fixoff(time);
03611 }
03612
03613 return time_localtime(time_dup(time));
03614 }
03615
03616
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631 static VALUE
03632 time_getgmtime(VALUE time)
03633 {
03634 return time_gmtime(time_dup(time));
03635 }
03636
03637 static VALUE
03638 time_get_tm(VALUE time, struct time_object *tobj)
03639 {
03640 if (TIME_UTC_P(tobj)) return time_gmtime(time);
03641 if (TIME_FIXOFF_P(tobj)) return time_fixoff(time);
03642 return time_localtime(time);
03643 }
03644
03645 static VALUE strftimev(const char *fmt, VALUE time);
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657 static VALUE
03658 time_asctime(VALUE time)
03659 {
03660 return strftimev("%a %b %e %T %Y", time);
03661 }
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679 static VALUE
03680 time_to_s(VALUE time)
03681 {
03682 struct time_object *tobj;
03683
03684 GetTimeval(time, tobj);
03685 if (TIME_UTC_P(tobj))
03686 return strftimev("%Y-%m-%d %H:%M:%S UTC", time);
03687 else
03688 return strftimev("%Y-%m-%d %H:%M:%S %z", time);
03689 }
03690
03691 static VALUE
03692 time_add(struct time_object *tobj, VALUE offset, int sign)
03693 {
03694 VALUE result;
03695 offset = num_exact(offset);
03696 if (sign < 0)
03697 result = time_new_timew(rb_cTime, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
03698 else
03699 result = time_new_timew(rb_cTime, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
03700 if (TIME_UTC_P(tobj)) {
03701 GetTimeval(result, tobj);
03702 TIME_SET_UTC(tobj);
03703 }
03704 else if (TIME_FIXOFF_P(tobj)) {
03705 VALUE off = tobj->vtm.utc_offset;
03706 GetTimeval(result, tobj);
03707 TIME_SET_FIXOFF(tobj, off);
03708 }
03709 return result;
03710 }
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723 static VALUE
03724 time_plus(VALUE time1, VALUE time2)
03725 {
03726 struct time_object *tobj;
03727 GetTimeval(time1, tobj);
03728
03729 if (IsTimeval(time2)) {
03730 rb_raise(rb_eTypeError, "time + time?");
03731 }
03732 return time_add(tobj, time2, 1);
03733 }
03734
03735
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747
03748
03749
03750 static VALUE
03751 time_minus(VALUE time1, VALUE time2)
03752 {
03753 struct time_object *tobj;
03754
03755 GetTimeval(time1, tobj);
03756 if (IsTimeval(time2)) {
03757 struct time_object *tobj2;
03758
03759 GetTimeval(time2, tobj2);
03760 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
03761 }
03762 return time_add(tobj, time2, -1);
03763 }
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776 VALUE
03777 rb_time_succ(VALUE time)
03778 {
03779 struct time_object *tobj;
03780 struct time_object *tobj2;
03781
03782 rb_warn("Time#succ is obsolete; use time + 1");
03783 GetTimeval(time, tobj);
03784 time = time_new_timew(rb_cTime, wadd(tobj->timew, WINT2FIXWV(TIME_SCALE)));
03785 GetTimeval(time, tobj2);
03786 TIME_COPY_GMT(tobj2, tobj);
03787 return time;
03788 }
03789
03790 #define time_succ rb_time_succ
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827
03828
03829 static VALUE
03830 time_round(int argc, VALUE *argv, VALUE time)
03831 {
03832 VALUE ndigits, v, a, b, den;
03833 long nd;
03834 struct time_object *tobj;
03835
03836 rb_scan_args(argc, argv, "01", &ndigits);
03837
03838 if (NIL_P(ndigits))
03839 ndigits = INT2FIX(0);
03840 else
03841 ndigits = rb_to_int(ndigits);
03842
03843 nd = NUM2LONG(ndigits);
03844 if (nd < 0)
03845 rb_raise(rb_eArgError, "negative ndigits given");
03846
03847 GetTimeval(time, tobj);
03848 v = w2v(rb_time_unmagnify(tobj->timew));
03849
03850 a = INT2FIX(1);
03851 b = INT2FIX(10);
03852 while (0 < nd) {
03853 if (nd & 1)
03854 a = mul(a, b);
03855 b = mul(b, b);
03856 nd = nd >> 1;
03857 }
03858 den = quo(INT2FIX(1), a);
03859 v = mod(v, den);
03860 if (lt(v, quo(den, INT2FIX(2))))
03861 return time_add(tobj, v, -1);
03862 else
03863 return time_add(tobj, sub(den, v), 1);
03864 }
03865
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879 static VALUE
03880 time_sec(VALUE time)
03881 {
03882 struct time_object *tobj;
03883
03884 GetTimeval(time, tobj);
03885 MAKE_TM(time, tobj);
03886 return INT2FIX(tobj->vtm.sec);
03887 }
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899 static VALUE
03900 time_min(VALUE time)
03901 {
03902 struct time_object *tobj;
03903
03904 GetTimeval(time, tobj);
03905 MAKE_TM(time, tobj);
03906 return INT2FIX(tobj->vtm.min);
03907 }
03908
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919 static VALUE
03920 time_hour(VALUE time)
03921 {
03922 struct time_object *tobj;
03923
03924 GetTimeval(time, tobj);
03925 MAKE_TM(time, tobj);
03926 return INT2FIX(tobj->vtm.hour);
03927 }
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941 static VALUE
03942 time_mday(VALUE time)
03943 {
03944 struct time_object *tobj;
03945
03946 GetTimeval(time, tobj);
03947 MAKE_TM(time, tobj);
03948 return INT2FIX(tobj->vtm.mday);
03949 }
03950
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962
03963 static VALUE
03964 time_mon(VALUE time)
03965 {
03966 struct time_object *tobj;
03967
03968 GetTimeval(time, tobj);
03969 MAKE_TM(time, tobj);
03970 return INT2FIX(tobj->vtm.mon);
03971 }
03972
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983 static VALUE
03984 time_year(VALUE time)
03985 {
03986 struct time_object *tobj;
03987
03988 GetTimeval(time, tobj);
03989 MAKE_TM(time, tobj);
03990 return tobj->vtm.year;
03991 }
03992
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011 static VALUE
04012 time_wday(VALUE time)
04013 {
04014 struct time_object *tobj;
04015
04016 GetTimeval(time, tobj);
04017 MAKE_TM(time, tobj);
04018 return INT2FIX(tobj->vtm.wday);
04019 }
04020
04021 #define wday_p(n) {\
04022 struct time_object *tobj;\
04023 GetTimeval(time, tobj);\
04024 MAKE_TM(time, tobj);\
04025 return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\
04026 }
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038 static VALUE
04039 time_sunday(VALUE time)
04040 {
04041 wday_p(0);
04042 }
04043
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054 static VALUE
04055 time_monday(VALUE time)
04056 {
04057 wday_p(1);
04058 }
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070 static VALUE
04071 time_tuesday(VALUE time)
04072 {
04073 wday_p(2);
04074 }
04075
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085
04086 static VALUE
04087 time_wednesday(VALUE time)
04088 {
04089 wday_p(3);
04090 }
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101
04102 static VALUE
04103 time_thursday(VALUE time)
04104 {
04105 wday_p(4);
04106 }
04107
04108
04109
04110
04111
04112
04113
04114
04115
04116
04117
04118 static VALUE
04119 time_friday(VALUE time)
04120 {
04121 wday_p(5);
04122 }
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134 static VALUE
04135 time_saturday(VALUE time)
04136 {
04137 wday_p(6);
04138 }
04139
04140
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150 static VALUE
04151 time_yday(VALUE time)
04152 {
04153 struct time_object *tobj;
04154
04155 GetTimeval(time, tobj);
04156 MAKE_TM(time, tobj);
04157 return INT2FIX(tobj->vtm.yday);
04158 }
04159
04160
04161
04162
04163
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179
04180
04181
04182
04183
04184
04185 static VALUE
04186 time_isdst(VALUE time)
04187 {
04188 struct time_object *tobj;
04189
04190 GetTimeval(time, tobj);
04191 MAKE_TM(time, tobj);
04192 return tobj->vtm.isdst ? Qtrue : Qfalse;
04193 }
04194
04195
04196
04197
04198
04199
04200
04201
04202
04203
04204
04205
04206
04207
04208 static VALUE
04209 time_zone(VALUE time)
04210 {
04211 struct time_object *tobj;
04212
04213 GetTimeval(time, tobj);
04214 MAKE_TM(time, tobj);
04215
04216 if (TIME_UTC_P(tobj)) {
04217 return rb_obj_untaint(rb_locale_str_new_cstr("UTC"));
04218 }
04219 if (tobj->vtm.zone == NULL)
04220 return Qnil;
04221 return rb_obj_untaint(rb_locale_str_new_cstr(tobj->vtm.zone));
04222 }
04223
04224
04225
04226
04227
04228
04229
04230
04231
04232
04233
04234
04235
04236
04237
04238
04239 static VALUE
04240 time_utc_offset(VALUE time)
04241 {
04242 struct time_object *tobj;
04243
04244 GetTimeval(time, tobj);
04245 MAKE_TM(time, tobj);
04246
04247 if (TIME_UTC_P(tobj)) {
04248 return INT2FIX(0);
04249 }
04250 else {
04251 return tobj->vtm.utc_offset;
04252 }
04253 }
04254
04255
04256
04257
04258
04259
04260
04261
04262
04263
04264
04265
04266
04267
04268
04269
04270 static VALUE
04271 time_to_a(VALUE time)
04272 {
04273 struct time_object *tobj;
04274
04275 GetTimeval(time, tobj);
04276 MAKE_TM(time, tobj);
04277 return rb_ary_new3(10,
04278 INT2FIX(tobj->vtm.sec),
04279 INT2FIX(tobj->vtm.min),
04280 INT2FIX(tobj->vtm.hour),
04281 INT2FIX(tobj->vtm.mday),
04282 INT2FIX(tobj->vtm.mon),
04283 tobj->vtm.year,
04284 INT2FIX(tobj->vtm.wday),
04285 INT2FIX(tobj->vtm.yday),
04286 tobj->vtm.isdst?Qtrue:Qfalse,
04287 time_zone(time));
04288 }
04289
04290 size_t
04291 rb_strftime(char *s, size_t maxsize, const char *format,
04292 const struct vtm *vtm, VALUE timev,
04293 int gmt);
04294
04295 #define SMALLBUF 100
04296 static size_t
04297 rb_strftime_alloc(char **buf, const char *format,
04298 struct vtm *vtm, wideval_t timew, int gmt)
04299 {
04300 size_t size, len, flen;
04301 VALUE timev = Qnil;
04302 struct timespec ts;
04303
04304 if (!timew2timespec_exact(timew, &ts))
04305 timev = w2v(rb_time_unmagnify(timew));
04306
04307 (*buf)[0] = '\0';
04308 flen = strlen(format);
04309 if (flen == 0) {
04310 return 0;
04311 }
04312 errno = 0;
04313 if (timev == Qnil)
04314 len = rb_strftime_timespec(*buf, SMALLBUF, format, vtm, &ts, gmt);
04315 else
04316 len = rb_strftime(*buf, SMALLBUF, format, vtm, timev, gmt);
04317 if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
04318 for (size=1024; ; size*=2) {
04319 *buf = xmalloc(size);
04320 (*buf)[0] = '\0';
04321 if (timev == Qnil)
04322 len = rb_strftime_timespec(*buf, size, format, vtm, &ts, gmt);
04323 else
04324 len = rb_strftime(*buf, size, format, vtm, timev, gmt);
04325
04326
04327
04328
04329
04330
04331
04332 if (len > 0) break;
04333 xfree(*buf);
04334 if (size >= 1024 * flen) {
04335 rb_sys_fail(format);
04336 break;
04337 }
04338 }
04339 return len;
04340 }
04341
04342 static VALUE
04343 strftimev(const char *fmt, VALUE time)
04344 {
04345 struct time_object *tobj;
04346 char buffer[SMALLBUF], *buf = buffer;
04347 long len;
04348 VALUE str;
04349
04350 GetTimeval(time, tobj);
04351 MAKE_TM(time, tobj);
04352 len = rb_strftime_alloc(&buf, fmt, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04353 str = rb_str_new(buf, len);
04354 if (buf != buffer) xfree(buf);
04355 return str;
04356 }
04357
04358
04359
04360
04361
04362
04363
04364
04365
04366
04367
04368
04369
04370
04371
04372
04373
04374
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413
04414
04415
04416
04417
04418
04419
04420
04421
04422
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433
04434
04435
04436
04437
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530 static VALUE
04531 time_strftime(VALUE time, VALUE format)
04532 {
04533 struct time_object *tobj;
04534 char buffer[SMALLBUF], *buf = buffer;
04535 const char *fmt;
04536 long len;
04537 VALUE str;
04538
04539 GetTimeval(time, tobj);
04540 MAKE_TM(time, tobj);
04541 StringValue(format);
04542 if (!rb_enc_str_asciicompat_p(format)) {
04543 rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
04544 }
04545 format = rb_str_new4(format);
04546 fmt = RSTRING_PTR(format);
04547 len = RSTRING_LEN(format);
04548 if (len == 0) {
04549 rb_warning("strftime called with empty format string");
04550 }
04551 else if (memchr(fmt, '\0', len)) {
04552
04553 const char *p = fmt, *pe = fmt + len;
04554
04555 str = rb_str_new(0, 0);
04556 while (p < pe) {
04557 len = rb_strftime_alloc(&buf, p, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04558 rb_str_cat(str, buf, len);
04559 p += strlen(p);
04560 if (buf != buffer) {
04561 xfree(buf);
04562 buf = buffer;
04563 }
04564 for (fmt = p; p < pe && !*p; ++p);
04565 if (p > fmt) rb_str_cat(str, fmt, p - fmt);
04566 }
04567 return str;
04568 }
04569 else {
04570 len = rb_strftime_alloc(&buf, RSTRING_PTR(format),
04571 &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04572 }
04573 str = rb_str_new(buf, len);
04574 if (buf != buffer) xfree(buf);
04575 rb_enc_copy(str, format);
04576 return str;
04577 }
04578
04579
04580
04581
04582
04583 static VALUE
04584 time_mdump(VALUE time)
04585 {
04586 struct time_object *tobj;
04587 unsigned long p, s;
04588 char buf[8];
04589 int i;
04590 VALUE str;
04591
04592 struct vtm vtm;
04593 long year;
04594 long usec, nsec;
04595 VALUE subsecx, nano, subnano, v;
04596
04597 GetTimeval(time, tobj);
04598
04599 gmtimew(tobj->timew, &vtm);
04600
04601 if (FIXNUM_P(vtm.year)) {
04602 year = FIX2LONG(vtm.year);
04603 if (year < 1900 || 1900+0xffff < year)
04604 rb_raise(rb_eArgError, "year too big to marshal: %ld UTC", year);
04605 }
04606 else {
04607 rb_raise(rb_eArgError, "year too big to marshal");
04608 }
04609
04610 subsecx = vtm.subsecx;
04611
04612 nano = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
04613 divmodv(nano, INT2FIX(1), &v, &subnano);
04614 nsec = FIX2LONG(v);
04615 usec = nsec / 1000;
04616 nsec = nsec % 1000;
04617
04618 nano = add(LONG2FIX(nsec), subnano);
04619
04620 p = 0x1UL << 31 |
04621 TIME_UTC_P(tobj) << 30 |
04622 (year-1900) << 14 |
04623 (vtm.mon-1) << 10 |
04624 vtm.mday << 5 |
04625 vtm.hour;
04626 s = vtm.min << 26 |
04627 vtm.sec << 20 |
04628 usec;
04629
04630 for (i=0; i<4; i++) {
04631 buf[i] = (unsigned char)p;
04632 p = RSHIFT(p, 8);
04633 }
04634 for (i=4; i<8; i++) {
04635 buf[i] = (unsigned char)s;
04636 s = RSHIFT(s, 8);
04637 }
04638
04639 str = rb_str_new(buf, 8);
04640 rb_copy_generic_ivar(str, time);
04641 if (!rb_equal(nano, INT2FIX(0))) {
04642 if (TYPE(nano) == T_RATIONAL) {
04643 rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
04644 rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
04645 }
04646 else {
04647 rb_ivar_set(str, id_nano_num, nano);
04648 rb_ivar_set(str, id_nano_den, INT2FIX(1));
04649 }
04650 }
04651 if (nsec) {
04652
04653
04654
04655
04656
04657
04658
04659 char buf[2];
04660 int len = (int)sizeof(buf);
04661 buf[1] = (char)((nsec % 10) << 4);
04662 nsec /= 10;
04663 buf[0] = (char)(nsec % 10);
04664 nsec /= 10;
04665 buf[0] |= (char)((nsec % 10) << 4);
04666 if (buf[1] == 0)
04667 len = 1;
04668 rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
04669 }
04670 if (!TIME_UTC_P(tobj)) {
04671 VALUE off = time_utc_offset(time), div, mod;
04672 divmodv(off, INT2FIX(1), &div, &mod);
04673 if (rb_equal(mod, INT2FIX(0)))
04674 off = rb_Integer(div);
04675 rb_ivar_set(str, id_offset, off);
04676 }
04677 return str;
04678 }
04679
04680
04681
04682
04683
04684
04685
04686
04687 static VALUE
04688 time_dump(int argc, VALUE *argv, VALUE time)
04689 {
04690 VALUE str;
04691
04692 rb_scan_args(argc, argv, "01", 0);
04693 str = time_mdump(time);
04694
04695 return str;
04696 }
04697
04698
04699
04700
04701
04702 static VALUE
04703 time_mload(VALUE time, VALUE str)
04704 {
04705 struct time_object *tobj;
04706 unsigned long p, s;
04707 time_t sec;
04708 long usec;
04709 unsigned char *buf;
04710 struct vtm vtm;
04711 int i, gmt;
04712 long nsec;
04713 VALUE submicro, nano_num, nano_den, offset;
04714 wideval_t timew;
04715 st_data_t data;
04716
04717 time_modify(time);
04718
04719 #define get_attr(attr, iffound) \
04720 attr = rb_attr_get(str, id_##attr); \
04721 if (!NIL_P(attr)) { \
04722 data = id_##attr; \
04723 iffound; \
04724 st_delete(rb_generic_ivar_table(str), &data, 0); \
04725 }
04726
04727 get_attr(nano_num, {});
04728 get_attr(nano_den, {});
04729 get_attr(submicro, {});
04730 get_attr(offset, validate_utc_offset(offset));
04731 #undef get_attr
04732
04733 rb_copy_generic_ivar(time, str);
04734
04735 StringValue(str);
04736 buf = (unsigned char *)RSTRING_PTR(str);
04737 if (RSTRING_LEN(str) != 8) {
04738 rb_raise(rb_eTypeError, "marshaled time format differ");
04739 }
04740
04741 p = s = 0;
04742 for (i=0; i<4; i++) {
04743 p |= buf[i]<<(8*i);
04744 }
04745 for (i=4; i<8; i++) {
04746 s |= buf[i]<<(8*(i-4));
04747 }
04748
04749 if ((p & (1UL<<31)) == 0) {
04750 gmt = 0;
04751 offset = Qnil;
04752 sec = p;
04753 usec = s;
04754 nsec = usec * 1000;
04755 timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
04756 }
04757 else {
04758 p &= ~(1UL<<31);
04759 gmt = (int)((p >> 30) & 0x1);
04760
04761 vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
04762 vtm.mon = ((int)(p >> 10) & 0xf) + 1;
04763 vtm.mday = (int)(p >> 5) & 0x1f;
04764 vtm.hour = (int) p & 0x1f;
04765 vtm.min = (int)(s >> 26) & 0x3f;
04766 vtm.sec = (int)(s >> 20) & 0x3f;
04767 vtm.utc_offset = INT2FIX(0);
04768 vtm.yday = vtm.wday = 0;
04769 vtm.isdst = 0;
04770 vtm.zone = "";
04771
04772 usec = (long)(s & 0xfffff);
04773 nsec = usec * 1000;
04774
04775
04776 vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
04777 if (nano_num != Qnil) {
04778 VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
04779 vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
04780 }
04781 else if (submicro != Qnil) {
04782 unsigned char *ptr;
04783 long len;
04784 int digit;
04785 ptr = (unsigned char*)StringValuePtr(submicro);
04786 len = RSTRING_LEN(submicro);
04787 nsec = 0;
04788 if (0 < len) {
04789 if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
04790 nsec += digit * 100;
04791 if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
04792 nsec += digit * 10;
04793 }
04794 if (1 < len) {
04795 if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
04796 nsec += digit;
04797 }
04798 vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
04799 end_submicro: ;
04800 }
04801 timew = timegmw(&vtm);
04802 }
04803
04804 GetTimeval(time, tobj);
04805 tobj->tm_got = 0;
04806 tobj->timew = timew;
04807 if (gmt) {
04808 TIME_SET_UTC(tobj);
04809 }
04810 else if (!NIL_P(offset)) {
04811 time_set_utc_offset(time, offset);
04812 time_fixoff(time);
04813 }
04814
04815 return time;
04816 }
04817
04818
04819
04820
04821
04822
04823
04824
04825 static VALUE
04826 time_load(VALUE klass, VALUE str)
04827 {
04828 VALUE time = time_s_alloc(klass);
04829
04830 time_mload(time, str);
04831 return time;
04832 }
04833
04834
04835
04836
04837
04838
04839
04840
04841
04842
04843
04844
04845
04846
04847
04848
04849
04850
04851 void
04852 Init_Time(void)
04853 {
04854 #undef rb_intern
04855 #define rb_intern(str) rb_intern_const(str)
04856
04857 id_eq = rb_intern("==");
04858 id_ne = rb_intern("!=");
04859 id_quo = rb_intern("quo");
04860 id_div = rb_intern("div");
04861 id_cmp = rb_intern("<=>");
04862 id_lshift = rb_intern("<<");
04863 id_divmod = rb_intern("divmod");
04864 id_mul = rb_intern("*");
04865 id_submicro = rb_intern("submicro");
04866 id_nano_num = rb_intern("nano_num");
04867 id_nano_den = rb_intern("nano_den");
04868 id_offset = rb_intern("offset");
04869
04870 rb_cTime = rb_define_class("Time", rb_cObject);
04871 rb_include_module(rb_cTime, rb_mComparable);
04872
04873 rb_define_alloc_func(rb_cTime, time_s_alloc);
04874 rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
04875 rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
04876 rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
04877 rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
04878 rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
04879 rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
04880
04881 rb_define_method(rb_cTime, "to_i", time_to_i, 0);
04882 rb_define_method(rb_cTime, "to_f", time_to_f, 0);
04883 rb_define_method(rb_cTime, "to_r", time_to_r, 0);
04884 rb_define_method(rb_cTime, "<=>", time_cmp, 1);
04885 rb_define_method(rb_cTime, "eql?", time_eql, 1);
04886 rb_define_method(rb_cTime, "hash", time_hash, 0);
04887 rb_define_method(rb_cTime, "initialize", time_init, -1);
04888 rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1);
04889
04890 rb_define_method(rb_cTime, "localtime", time_localtime_m, -1);
04891 rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
04892 rb_define_method(rb_cTime, "utc", time_gmtime, 0);
04893 rb_define_method(rb_cTime, "getlocal", time_getlocaltime, -1);
04894 rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
04895 rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
04896
04897 rb_define_method(rb_cTime, "ctime", time_asctime, 0);
04898 rb_define_method(rb_cTime, "asctime", time_asctime, 0);
04899 rb_define_method(rb_cTime, "to_s", time_to_s, 0);
04900 rb_define_method(rb_cTime, "inspect", time_to_s, 0);
04901 rb_define_method(rb_cTime, "to_a", time_to_a, 0);
04902
04903 rb_define_method(rb_cTime, "+", time_plus, 1);
04904 rb_define_method(rb_cTime, "-", time_minus, 1);
04905
04906 rb_define_method(rb_cTime, "succ", time_succ, 0);
04907 rb_define_method(rb_cTime, "round", time_round, -1);
04908
04909 rb_define_method(rb_cTime, "sec", time_sec, 0);
04910 rb_define_method(rb_cTime, "min", time_min, 0);
04911 rb_define_method(rb_cTime, "hour", time_hour, 0);
04912 rb_define_method(rb_cTime, "mday", time_mday, 0);
04913 rb_define_method(rb_cTime, "day", time_mday, 0);
04914 rb_define_method(rb_cTime, "mon", time_mon, 0);
04915 rb_define_method(rb_cTime, "month", time_mon, 0);
04916 rb_define_method(rb_cTime, "year", time_year, 0);
04917 rb_define_method(rb_cTime, "wday", time_wday, 0);
04918 rb_define_method(rb_cTime, "yday", time_yday, 0);
04919 rb_define_method(rb_cTime, "isdst", time_isdst, 0);
04920 rb_define_method(rb_cTime, "dst?", time_isdst, 0);
04921 rb_define_method(rb_cTime, "zone", time_zone, 0);
04922 rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
04923 rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
04924 rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
04925
04926 rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
04927 rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
04928
04929 rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
04930 rb_define_method(rb_cTime, "monday?", time_monday, 0);
04931 rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
04932 rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
04933 rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
04934 rb_define_method(rb_cTime, "friday?", time_friday, 0);
04935 rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
04936
04937 rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
04938 rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
04939 rb_define_method(rb_cTime, "usec", time_usec, 0);
04940 rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
04941 rb_define_method(rb_cTime, "nsec", time_nsec, 0);
04942 rb_define_method(rb_cTime, "subsec", time_subsec, 0);
04943
04944 rb_define_method(rb_cTime, "strftime", time_strftime, 1);
04945
04946
04947 rb_define_method(rb_cTime, "_dump", time_dump, -1);
04948 rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
04949 #if 0
04950
04951 rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0);
04952 rb_define_method(rb_cTime, "marshal_load", time_mload, 1);
04953 #endif
04954
04955 #ifdef DEBUG_FIND_TIME_NUMGUESS
04956 rb_define_virtual_variable("$find_time_numguess", find_time_numguess_getter, NULL);
04957 #endif
04958 }
04959