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