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, id_zone;
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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(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 (RB_TYPE_P(x, T_BIGNUM)) return v2w(rb_big_mul(x, w2v(wy)));
00533 z = rb_funcall(x, '*', 1, w2v(wy));
00534 if (RB_TYPE_P(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 (RB_TYPE_P(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 VALUE validate_utc_offset(VALUE utc_offset);
00853 static VALUE validate_zone_name(VALUE zone_name);
00854 static void validate_vtm(struct vtm *vtm);
00855 static int obj2subsecx(VALUE obj, VALUE *subsecx);
00856
00857 static VALUE time_gmtime(VALUE);
00858 static VALUE time_localtime(VALUE);
00859 static VALUE time_fixoff(VALUE);
00860
00861 static time_t timegm_noleapsecond(struct tm *tm);
00862 static int tmcmp(struct tm *a, struct tm *b);
00863 static int vtmcmp(struct vtm *a, struct vtm *b);
00864 static const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
00865
00866 static struct vtm *localtimew(wideval_t timew, struct vtm *result);
00867
00868 static int leap_year_p(long y);
00869 #define leap_year_v_p(y) leap_year_p(NUM2LONG(mod((y), INT2FIX(400))))
00870
00871 #ifdef HAVE_GMTIME_R
00872 #define rb_gmtime_r(t, tm) gmtime_r((t), (tm))
00873 #define rb_localtime_r(t, tm) localtime_r((t), (tm))
00874 #else
00875 static inline struct tm *
00876 rb_gmtime_r(const time_t *tp, struct tm *result)
00877 {
00878 struct tm *t = gmtime(tp);
00879 if (t) *result = *t;
00880 return t;
00881 }
00882
00883 static inline struct tm *
00884 rb_localtime_r(const time_t *tp, struct tm *result)
00885 {
00886 struct tm *t = localtime(tp);
00887 if (t) *result = *t;
00888 return t;
00889 }
00890 #endif
00891
00892 static struct tm *
00893 rb_localtime_r2(const time_t *t, struct tm *result)
00894 {
00895 #if defined __APPLE__ && defined __LP64__
00896 if (*t != (time_t)(int)*t) return NULL;
00897 #endif
00898 result = rb_localtime_r(t, result);
00899 #if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
00900 if (result) {
00901 long gmtoff1 = 0;
00902 long gmtoff2 = 0;
00903 struct tm tmp = *result;
00904 time_t t2;
00905 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
00906 gmtoff1 = result->tm_gmtoff;
00907 # endif
00908 t2 = mktime(&tmp);
00909 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
00910 gmtoff2 = tmp.tm_gmtoff;
00911 # endif
00912 if (*t + gmtoff1 != t2 + gmtoff2)
00913 result = NULL;
00914 }
00915 #endif
00916 return result;
00917 }
00918 #define LOCALTIME(tm, result) (tzset(),rb_localtime_r2((tm), &(result)))
00919
00920 #if !defined(HAVE_STRUCT_TM_TM_GMTOFF)
00921 static struct tm *
00922 rb_gmtime_r2(const time_t *t, struct tm *result)
00923 {
00924 result = rb_gmtime_r(t, result);
00925 #if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
00926 if (result) {
00927 struct tm tmp = *result;
00928 time_t t2 = timegm(&tmp);
00929 if (*t != t2)
00930 result = NULL;
00931 }
00932 #endif
00933 return result;
00934 }
00935 # define GMTIME(tm, result) rb_gmtime_r2((tm), &(result))
00936 #endif
00937
00938 static const int common_year_yday_offset[] = {
00939 -1,
00940 -1 + 31,
00941 -1 + 31 + 28,
00942 -1 + 31 + 28 + 31,
00943 -1 + 31 + 28 + 31 + 30,
00944 -1 + 31 + 28 + 31 + 30 + 31,
00945 -1 + 31 + 28 + 31 + 30 + 31 + 30,
00946 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
00947 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
00948 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00949 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00950 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00951
00952 };
00953 static const int leap_year_yday_offset[] = {
00954 -1,
00955 -1 + 31,
00956 -1 + 31 + 29,
00957 -1 + 31 + 29 + 31,
00958 -1 + 31 + 29 + 31 + 30,
00959 -1 + 31 + 29 + 31 + 30 + 31,
00960 -1 + 31 + 29 + 31 + 30 + 31 + 30,
00961 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
00962 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
00963 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00964 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00965 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00966
00967 };
00968
00969 static const int common_year_days_in_month[] = {
00970 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
00971 };
00972 static const int leap_year_days_in_month[] = {
00973 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
00974 };
00975
00976 static int
00977 calc_tm_yday(long tm_year, int tm_mon, int tm_mday)
00978 {
00979 int tm_year_mod400 = (int)MOD(tm_year, 400);
00980 int tm_yday = tm_mday;
00981
00982 if (leap_year_p(tm_year_mod400 + 1900))
00983 tm_yday += leap_year_yday_offset[tm_mon];
00984 else
00985 tm_yday += common_year_yday_offset[tm_mon];
00986
00987 return tm_yday;
00988 }
00989
00990 static wideval_t
00991 timegmw_noleapsecond(struct vtm *vtm)
00992 {
00993 VALUE year1900;
00994 VALUE q400, r400;
00995 int year_mod400;
00996 int yday;
00997 long days_in400;
00998 VALUE vdays, ret;
00999 wideval_t wret;
01000
01001 year1900 = sub(vtm->year, INT2FIX(1900));
01002
01003 divmodv(year1900, INT2FIX(400), &q400, &r400);
01004 year_mod400 = NUM2INT(r400);
01005
01006 yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday);
01007
01008
01009
01010
01011
01012
01013
01014 ret = LONG2NUM(vtm->sec
01015 + vtm->min*60
01016 + vtm->hour*3600);
01017 days_in400 = yday
01018 - 70*365
01019 + DIV(year_mod400 - 69, 4)
01020 - DIV(year_mod400 - 1, 100)
01021 + (year_mod400 + 299) / 400;
01022 vdays = LONG2NUM(days_in400);
01023 vdays = add(vdays, mul(q400, INT2FIX(97)));
01024 vdays = add(vdays, mul(year1900, INT2FIX(365)));
01025 wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)), WINT2FIXWV(86400)));
01026 wret = wadd(wret, v2w(vtm->subsecx));
01027
01028 return wret;
01029 }
01030
01031 static st_table *zone_table;
01032
01033 static int
01034 zone_str_update(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
01035 {
01036 const char *s = (const char *)*key;
01037 const char **ret = (const char **)arg;
01038
01039 if (existing) {
01040 *ret = (const char *)*value;
01041 return ST_STOP;
01042 }
01043 *ret = s = strdup(s);
01044 *key = *value = (st_data_t)s;
01045 return ST_CONTINUE;
01046 }
01047
01048 static const char *
01049 zone_str(const char *s)
01050 {
01051 if (!zone_table)
01052 zone_table = st_init_strtable();
01053
01054 st_update(zone_table, (st_data_t)s, zone_str_update, (st_data_t)&s);
01055 return s;
01056 }
01057
01058 static void
01059 gmtimew_noleapsecond(wideval_t timew, struct vtm *vtm)
01060 {
01061 VALUE v;
01062 int i, n, x, y;
01063 const int *yday_offset;
01064 int wday;
01065 VALUE timev;
01066 wideval_t timew2, w, w2;
01067
01068 vtm->isdst = 0;
01069
01070 split_second(timew, &timew2, &vtm->subsecx);
01071
01072 wdivmod(timew2, WINT2FIXWV(86400), &w2, &w);
01073 timev = w2v(w2);
01074 v = w2v(w);
01075
01076 wday = NUM2INT(mod(timev, INT2FIX(7)));
01077 vtm->wday = (wday + 4) % 7;
01078
01079 n = NUM2INT(v);
01080 vtm->sec = n % 60; n = n / 60;
01081 vtm->min = n % 60; n = n / 60;
01082 vtm->hour = n;
01083
01084
01085 divmodv(timev, INT2FIX(400*365 + 97), &timev, &v);
01086 vtm->year = mul(timev, INT2FIX(400));
01087
01088
01089
01090
01091 n = NUM2INT(v);
01092 y = 1970;
01093
01094
01095
01096
01097
01098 if (30*365+7+31+29-1 <= n) {
01099
01100 if (n < 31*365+8) {
01101
01102 y += 30;
01103 n -= 30*365+7;
01104 goto found;
01105 }
01106 else {
01107
01108 n -= 1;
01109 }
01110 }
01111
01112 x = n / (365*100 + 24);
01113 n = n % (365*100 + 24);
01114 y += x * 100;
01115 if (30*365+7+31+29-1 <= n) {
01116 if (n < 31*365+7) {
01117 y += 30;
01118 n -= 30*365+7;
01119 goto found;
01120 }
01121 else
01122 n += 1;
01123 }
01124
01125 x = n / (365*4 + 1);
01126 n = n % (365*4 + 1);
01127 y += x * 4;
01128 if (365*2+31+29-1 <= n) {
01129 if (n < 365*2+366) {
01130 y += 2;
01131 n -= 365*2;
01132 goto found;
01133 }
01134 else
01135 n -= 1;
01136 }
01137
01138 x = n / 365;
01139 n = n % 365;
01140 y += x;
01141
01142 found:
01143 vtm->yday = n+1;
01144 vtm->year = add(vtm->year, INT2NUM(y));
01145
01146 if (leap_year_p(y))
01147 yday_offset = leap_year_yday_offset;
01148 else
01149 yday_offset = common_year_yday_offset;
01150
01151 for (i = 0; i < 12; i++) {
01152 if (yday_offset[i] < n) {
01153 vtm->mon = i+1;
01154 vtm->mday = n - yday_offset[i];
01155 }
01156 else
01157 break;
01158 }
01159
01160 vtm->utc_offset = INT2FIX(0);
01161 vtm->zone = "UTC";
01162 }
01163
01164 static struct tm *
01165 gmtime_with_leapsecond(const time_t *timep, struct tm *result)
01166 {
01167 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
01168
01169 struct tm *t;
01170 int sign;
01171 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
01172 long gmtoff;
01173 t = LOCALTIME(timep, *result);
01174 if (t == NULL)
01175 return NULL;
01176
01177
01178 if (t->tm_gmtoff < 0) {
01179 sign = 1;
01180 gmtoff = -t->tm_gmtoff;
01181 }
01182 else {
01183 sign = -1;
01184 gmtoff = t->tm_gmtoff;
01185 }
01186 gmtoff_sec = (int)(gmtoff % 60);
01187 gmtoff = gmtoff / 60;
01188 gmtoff_min = (int)(gmtoff % 60);
01189 gmtoff = gmtoff / 60;
01190 gmtoff_hour = (int)gmtoff;
01191
01192 gmtoff_sec *= sign;
01193 gmtoff_min *= sign;
01194 gmtoff_hour *= sign;
01195
01196 gmtoff_day = 0;
01197
01198 if (gmtoff_sec) {
01199
01200
01201 result->tm_sec += gmtoff_sec;
01202 if (result->tm_sec < 0) {
01203 result->tm_sec += 60;
01204 gmtoff_min -= 1;
01205 }
01206 if (60 <= result->tm_sec) {
01207 result->tm_sec -= 60;
01208 gmtoff_min += 1;
01209 }
01210 }
01211 if (gmtoff_min) {
01212 result->tm_min += gmtoff_min;
01213 if (result->tm_min < 0) {
01214 result->tm_min += 60;
01215 gmtoff_hour -= 1;
01216 }
01217 if (60 <= result->tm_min) {
01218 result->tm_min -= 60;
01219 gmtoff_hour += 1;
01220 }
01221 }
01222 if (gmtoff_hour) {
01223 result->tm_hour += gmtoff_hour;
01224 if (result->tm_hour < 0) {
01225 result->tm_hour += 24;
01226 gmtoff_day = -1;
01227 }
01228 if (24 <= result->tm_hour) {
01229 result->tm_hour -= 24;
01230 gmtoff_day = 1;
01231 }
01232 }
01233
01234 if (gmtoff_day) {
01235 if (gmtoff_day < 0) {
01236 if (result->tm_yday == 0) {
01237 result->tm_mday = 31;
01238 result->tm_mon = 11;
01239 result->tm_year--;
01240 result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
01241 }
01242 else if (result->tm_mday == 1) {
01243 const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
01244 leap_year_days_in_month :
01245 common_year_days_in_month;
01246 result->tm_mon--;
01247 result->tm_mday = days_in_month[result->tm_mon];
01248 result->tm_yday--;
01249 }
01250 else {
01251 result->tm_mday--;
01252 result->tm_yday--;
01253 }
01254 result->tm_wday = (result->tm_wday + 6) % 7;
01255 }
01256 else {
01257 int leap = leap_year_p(result->tm_year + 1900);
01258 if (result->tm_yday == (leap ? 365 : 364)) {
01259 result->tm_year++;
01260 result->tm_mon = 0;
01261 result->tm_mday = 1;
01262 result->tm_yday = 0;
01263 }
01264 else if (result->tm_mday == (leap ? leap_year_days_in_month :
01265 common_year_days_in_month)[result->tm_mon]) {
01266 result->tm_mon++;
01267 result->tm_mday = 1;
01268 result->tm_yday++;
01269 }
01270 else {
01271 result->tm_mday++;
01272 result->tm_yday++;
01273 }
01274 result->tm_wday = (result->tm_wday + 1) % 7;
01275 }
01276 }
01277 result->tm_isdst = 0;
01278 result->tm_gmtoff = 0;
01279 #if defined(HAVE_TM_ZONE)
01280 result->tm_zone = (char *)"UTC";
01281 #endif
01282 return result;
01283 #else
01284 return GMTIME(timep, *result);
01285 #endif
01286 }
01287
01288 static long this_year = 0;
01289 static time_t known_leap_seconds_limit;
01290 static int number_of_leap_seconds_known;
01291
01292 static void
01293 init_leap_second_info(void)
01294 {
01295
01296
01297
01298
01299
01300 if (this_year == 0) {
01301 time_t now;
01302 struct tm *tm, result;
01303 struct vtm vtm;
01304 wideval_t timew;
01305 now = time(NULL);
01306 gmtime(&now);
01307 tm = gmtime_with_leapsecond(&now, &result);
01308 if (!tm) return;
01309 this_year = tm->tm_year;
01310
01311 if (TIMET_MAX - now < (time_t)(366*86400))
01312 known_leap_seconds_limit = TIMET_MAX;
01313 else
01314 known_leap_seconds_limit = now + (time_t)(366*86400);
01315
01316 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
01317 return;
01318
01319 vtm.year = LONG2NUM(result.tm_year + 1900);
01320 vtm.mon = result.tm_mon + 1;
01321 vtm.mday = result.tm_mday;
01322 vtm.hour = result.tm_hour;
01323 vtm.min = result.tm_min;
01324 vtm.sec = result.tm_sec;
01325 vtm.subsecx = INT2FIX(0);
01326 vtm.utc_offset = INT2FIX(0);
01327
01328 timew = timegmw_noleapsecond(&vtm);
01329
01330 number_of_leap_seconds_known = NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
01331 }
01332 }
01333
01334 static wideval_t
01335 timegmw(struct vtm *vtm)
01336 {
01337 wideval_t timew;
01338 struct tm tm;
01339 time_t t;
01340 const char *errmsg;
01341
01342
01343
01344 if (gt(INT2FIX(1972), vtm->year))
01345 return timegmw_noleapsecond(vtm);
01346
01347 init_leap_second_info();
01348
01349 timew = timegmw_noleapsecond(vtm);
01350
01351 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
01352 return wadd(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
01353 }
01354
01355 tm.tm_year = rb_long2int(NUM2LONG(vtm->year) - 1900);
01356 tm.tm_mon = vtm->mon - 1;
01357 tm.tm_mday = vtm->mday;
01358 tm.tm_hour = vtm->hour;
01359 tm.tm_min = vtm->min;
01360 tm.tm_sec = vtm->sec;
01361 tm.tm_isdst = 0;
01362
01363 errmsg = find_time_t(&tm, 1, &t);
01364 if (errmsg)
01365 rb_raise(rb_eArgError, "%s", errmsg);
01366 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
01367 }
01368
01369 static struct vtm *
01370 gmtimew(wideval_t timew, struct vtm *result)
01371 {
01372 time_t t;
01373 struct tm tm;
01374 VALUE subsecx;
01375 wideval_t timew2;
01376
01377 if (wlt(timew, WINT2FIXWV(0))) {
01378 gmtimew_noleapsecond(timew, result);
01379 return result;
01380 }
01381
01382 init_leap_second_info();
01383
01384 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
01385 timew = wsub(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
01386 gmtimew_noleapsecond(timew, result);
01387 return result;
01388 }
01389
01390 split_second(timew, &timew2, &subsecx);
01391
01392 t = WV2TIMET(timew2);
01393 if (!gmtime_with_leapsecond(&t, &tm))
01394 return NULL;
01395
01396 result->year = LONG2NUM((long)tm.tm_year + 1900);
01397 result->mon = tm.tm_mon + 1;
01398 result->mday = tm.tm_mday;
01399 result->hour = tm.tm_hour;
01400 result->min = tm.tm_min;
01401 result->sec = tm.tm_sec;
01402 result->subsecx = subsecx;
01403 result->utc_offset = INT2FIX(0);
01404 result->wday = tm.tm_wday;
01405 result->yday = tm.tm_yday+1;
01406 result->isdst = tm.tm_isdst;
01407 result->zone = "UTC";
01408
01409 return result;
01410 }
01411
01412 static struct tm *localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone);
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
01440
01441
01442
01443
01444
01445
01446
01447 static int compat_common_month_table[12][7] = {
01448
01449 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 },
01450 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 },
01451 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
01452 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
01453 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 },
01454 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 },
01455 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
01456 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 },
01457 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
01458 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 },
01459 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
01460 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
01461 };
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488 static int compat_leap_month_table[7] = {
01489
01490 2032, 2016, 2028, 2012, 2024, 2036, 2020,
01491 };
01492
01493 static int
01494 calc_wday(int year, int month, int day)
01495 {
01496 int a, y, m;
01497 int wday;
01498
01499 a = (14 - month) / 12;
01500 y = year + 4800 - a;
01501 m = month + 12 * a - 3;
01502 wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
01503 wday = wday % 7;
01504 return wday;
01505 }
01506
01507 static VALUE
01508 guess_local_offset(struct vtm *vtm_utc, int *isdst_ret, const char **zone_ret)
01509 {
01510 struct tm tm;
01511 long gmtoff;
01512 const char *zone;
01513 time_t t;
01514 struct vtm vtm2;
01515 VALUE timev;
01516 int y, wday;
01517
01518
01519
01520 if (lt(vtm_utc->year, INT2FIX(1916))) {
01521 VALUE off = INT2FIX(0);
01522 int isdst = 0;
01523 zone = "UTC";
01524
01525 # if defined(NEGATIVE_TIME_T)
01526 # if SIZEOF_TIME_T <= 4
01527
01528 # define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
01529 # else
01530
01531
01532 # define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
01533 # endif
01534 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
01535 off = LONG2FIX(gmtoff);
01536 isdst = tm.tm_isdst;
01537 }
01538 else
01539 # endif
01540
01541 if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
01542 off = LONG2FIX(gmtoff);
01543 isdst = tm.tm_isdst;
01544 }
01545
01546 if (isdst_ret)
01547 *isdst_ret = isdst;
01548 if (zone_ret)
01549 *zone_ret = zone;
01550 return off;
01551 }
01552
01553
01554
01555 vtm2 = *vtm_utc;
01556
01557
01558 y = NUM2INT(mod(vtm_utc->year, INT2FIX(400)));
01559 wday = calc_wday(y, vtm_utc->mon, 1);
01560 if (vtm_utc->mon == 2 && leap_year_p(y))
01561 vtm2.year = INT2FIX(compat_leap_month_table[wday]);
01562 else
01563 vtm2.year = INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
01564
01565 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
01566 t = NUM2TIMET(timev);
01567 zone = "UTC";
01568 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
01569 if (isdst_ret)
01570 *isdst_ret = tm.tm_isdst;
01571 if (zone_ret)
01572 *zone_ret = zone;
01573 return LONG2FIX(gmtoff);
01574 }
01575
01576 {
01577
01578 static time_t now = 0;
01579 static long now_gmtoff = 0;
01580 static const char *now_zone = "UTC";
01581 if (now == 0) {
01582 now = time(NULL);
01583 localtime_with_gmtoff_zone(&now, &tm, &now_gmtoff, &now_zone);
01584 }
01585 if (isdst_ret)
01586 *isdst_ret = tm.tm_isdst;
01587 if (zone_ret)
01588 *zone_ret = now_zone;
01589 return LONG2FIX(now_gmtoff);
01590 }
01591 }
01592
01593 static VALUE
01594 small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
01595 {
01596 int off;
01597
01598 off = vtm1->sec - vtm2->sec;
01599 off += (vtm1->min - vtm2->min) * 60;
01600 off += (vtm1->hour - vtm2->hour) * 3600;
01601 if (ne(vtm1->year, vtm2->year))
01602 off += lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
01603 else if (vtm1->mon != vtm2->mon)
01604 off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
01605 else if (vtm1->mday != vtm2->mday)
01606 off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
01607
01608 return INT2FIX(off);
01609 }
01610
01611 static wideval_t
01612 timelocalw(struct vtm *vtm)
01613 {
01614 time_t t;
01615 struct tm tm;
01616 VALUE v;
01617 wideval_t timew1, timew2;
01618 struct vtm vtm1, vtm2;
01619 int n;
01620
01621 if (FIXNUM_P(vtm->year)) {
01622 long l = FIX2LONG(vtm->year) - 1900;
01623 if (l < INT_MIN || INT_MAX < l)
01624 goto no_localtime;
01625 tm.tm_year = (int)l;
01626 }
01627 else {
01628 v = sub(vtm->year, INT2FIX(1900));
01629 if (lt(v, INT2NUM(INT_MIN)) || lt(INT2NUM(INT_MAX), v))
01630 goto no_localtime;
01631 tm.tm_year = NUM2INT(v);
01632 }
01633
01634 tm.tm_mon = vtm->mon-1;
01635 tm.tm_mday = vtm->mday;
01636 tm.tm_hour = vtm->hour;
01637 tm.tm_min = vtm->min;
01638 tm.tm_sec = vtm->sec;
01639 tm.tm_isdst = vtm->isdst;
01640
01641 if (find_time_t(&tm, 0, &t))
01642 goto no_localtime;
01643 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
01644
01645 no_localtime:
01646 timew1 = timegmw(vtm);
01647
01648 if (!localtimew(timew1, &vtm1))
01649 rb_raise(rb_eArgError, "localtimew error");
01650
01651 n = vtmcmp(vtm, &vtm1);
01652 if (n == 0) {
01653 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(12*3600)));
01654 if (!localtimew(timew1, &vtm1))
01655 rb_raise(rb_eArgError, "localtimew error");
01656 n = 1;
01657 }
01658
01659 if (n < 0) {
01660 timew2 = timew1;
01661 vtm2 = vtm1;
01662 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
01663 if (!localtimew(timew1, &vtm1))
01664 rb_raise(rb_eArgError, "localtimew error");
01665 }
01666 else {
01667 timew2 = wadd(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
01668 if (!localtimew(timew2, &vtm2))
01669 rb_raise(rb_eArgError, "localtimew error");
01670 }
01671 timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
01672 timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
01673
01674 if (weq(timew1, timew2))
01675 return timew1;
01676
01677 if (!localtimew(timew1, &vtm1))
01678 rb_raise(rb_eArgError, "localtimew error");
01679 if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
01680 return timew2;
01681
01682 if (!localtimew(timew2, &vtm2))
01683 rb_raise(rb_eArgError, "localtimew error");
01684 if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
01685 return timew1;
01686
01687 if (vtm->isdst)
01688 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
01689 else
01690 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
01691 }
01692
01693 static struct tm *
01694 localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone)
01695 {
01696 struct tm tm;
01697
01698 if (LOCALTIME(t, tm)) {
01699 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
01700 *gmtoff = tm.tm_gmtoff;
01701 #else
01702 struct tm *u, *l;
01703 long off;
01704 struct tm tmbuf;
01705 l = &tm;
01706 u = GMTIME(t, tmbuf);
01707 if (!u)
01708 return NULL;
01709 if (l->tm_year != u->tm_year)
01710 off = l->tm_year < u->tm_year ? -1 : 1;
01711 else if (l->tm_mon != u->tm_mon)
01712 off = l->tm_mon < u->tm_mon ? -1 : 1;
01713 else if (l->tm_mday != u->tm_mday)
01714 off = l->tm_mday < u->tm_mday ? -1 : 1;
01715 else
01716 off = 0;
01717 off = off * 24 + l->tm_hour - u->tm_hour;
01718 off = off * 60 + l->tm_min - u->tm_min;
01719 off = off * 60 + l->tm_sec - u->tm_sec;
01720 *gmtoff = off;
01721 #endif
01722
01723 if (zone) {
01724 #if defined(HAVE_TM_ZONE)
01725 *zone = zone_str(tm.tm_zone);
01726 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
01727
01728 *zone = zone_str(tzname[daylight && tm.tm_isdst]);
01729 #else
01730 {
01731 char buf[64];
01732 strftime(buf, sizeof(buf), "%Z", &tm);
01733 *zone = zone_str(buf);
01734 }
01735 #endif
01736 }
01737
01738 *result = tm;
01739 return result;
01740 }
01741 return NULL;
01742 }
01743
01744 static int
01745 timew_out_of_timet_range(wideval_t timew)
01746 {
01747 VALUE timexv;
01748 #if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T
01749 if (FIXWV_P(timew)) {
01750 wideint_t t = FIXWV2WINT(timew);
01751 if (t < TIME_SCALE * (wideint_t)TIMET_MIN ||
01752 TIME_SCALE * (1 + (wideint_t)TIMET_MAX) <= t)
01753 return 1;
01754 return 0;
01755 }
01756 #endif
01757 #if SIZEOF_TIME_T == SIZEOF_INT64_T
01758 if (FIXWV_P(timew)) {
01759 wideint_t t = FIXWV2WINT(timew);
01760 if (~(time_t)0 <= 0) {
01761 return 0;
01762 }
01763 else {
01764 if (t < 0)
01765 return 1;
01766 return 0;
01767 }
01768 }
01769 #endif
01770 timexv = w2v(timew);
01771 if (lt(timexv, mul(INT2FIX(TIME_SCALE), TIMET2NUM(TIMET_MIN))) ||
01772 le(mul(INT2FIX(TIME_SCALE), add(TIMET2NUM(TIMET_MAX), INT2FIX(1))), timexv))
01773 return 1;
01774 return 0;
01775 }
01776
01777 static struct vtm *
01778 localtimew(wideval_t timew, struct vtm *result)
01779 {
01780 VALUE subsecx, offset;
01781 const char *zone;
01782 int isdst;
01783
01784 if (!timew_out_of_timet_range(timew)) {
01785 time_t t;
01786 struct tm tm;
01787 long gmtoff;
01788 wideval_t timew2;
01789
01790 split_second(timew, &timew2, &subsecx);
01791
01792 t = WV2TIMET(timew2);
01793
01794 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
01795 result->year = LONG2NUM((long)tm.tm_year + 1900);
01796 result->mon = tm.tm_mon + 1;
01797 result->mday = tm.tm_mday;
01798 result->hour = tm.tm_hour;
01799 result->min = tm.tm_min;
01800 result->sec = tm.tm_sec;
01801 result->subsecx = subsecx;
01802 result->wday = tm.tm_wday;
01803 result->yday = tm.tm_yday+1;
01804 result->isdst = tm.tm_isdst;
01805 result->utc_offset = LONG2NUM(gmtoff);
01806 result->zone = zone;
01807 return result;
01808 }
01809 }
01810
01811 if (!gmtimew(timew, result))
01812 return NULL;
01813
01814 offset = guess_local_offset(result, &isdst, &zone);
01815
01816 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
01817 return NULL;
01818
01819 result->utc_offset = offset;
01820 result->isdst = isdst;
01821 result->zone = zone;
01822
01823 return result;
01824 }
01825
01826 struct time_object {
01827 wideval_t timew;
01828 struct vtm vtm;
01829 int gmt;
01830 int tm_got;
01831 };
01832
01833 #define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj))
01834 #define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj))
01835
01836 #define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type)
01837 #define TIME_INIT_P(tobj) ((tobj)->gmt != -1)
01838
01839 #define TIME_UTC_P(tobj) ((tobj)->gmt == 1)
01840 #define TIME_SET_UTC(tobj) ((tobj)->gmt = 1)
01841
01842 #define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0)
01843 #define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0)
01844
01845 #define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2)
01846 #define TIME_SET_FIXOFF(tobj, off) \
01847 ((tobj)->gmt = 2, \
01848 (tobj)->vtm.utc_offset = (off), \
01849 (tobj)->vtm.zone = NULL)
01850
01851 #define TIME_COPY_GMT(tobj1, tobj2) \
01852 ((tobj1)->gmt = (tobj2)->gmt, \
01853 (tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \
01854 (tobj1)->vtm.zone = (tobj2)->vtm.zone)
01855
01856 static VALUE time_get_tm(VALUE, struct time_object *);
01857 #define MAKE_TM(time, tobj) \
01858 do { \
01859 if ((tobj)->tm_got == 0) { \
01860 time_get_tm((time), (tobj)); \
01861 } \
01862 } while (0)
01863
01864 static void
01865 time_mark(void *ptr)
01866 {
01867 struct time_object *tobj = ptr;
01868 if (!tobj) return;
01869 if (!FIXWV_P(tobj->timew))
01870 rb_gc_mark(w2v(tobj->timew));
01871 rb_gc_mark(tobj->vtm.year);
01872 rb_gc_mark(tobj->vtm.subsecx);
01873 rb_gc_mark(tobj->vtm.utc_offset);
01874 }
01875
01876 static void
01877 time_free(void *tobj)
01878 {
01879 if (tobj) xfree(tobj);
01880 }
01881
01882 static size_t
01883 time_memsize(const void *tobj)
01884 {
01885 return tobj ? sizeof(struct time_object) : 0;
01886 }
01887
01888 static const rb_data_type_t time_data_type = {
01889 "time",
01890 {time_mark, time_free, time_memsize,},
01891 };
01892
01893 static VALUE
01894 time_s_alloc(VALUE klass)
01895 {
01896 VALUE obj;
01897 struct time_object *tobj;
01898
01899 obj = TypedData_Make_Struct(klass, struct time_object, &time_data_type, tobj);
01900 tobj->gmt = -1;
01901 tobj->tm_got=0;
01902 tobj->timew = WINT2FIXWV(0);
01903
01904 return obj;
01905 }
01906
01907 static struct time_object *
01908 get_timeval(VALUE obj)
01909 {
01910 struct time_object *tobj;
01911 TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
01912 if (!TIME_INIT_P(tobj)) {
01913 rb_raise(rb_eTypeError, "uninitialized %"PRIsVALUE, rb_obj_class(obj));
01914 }
01915 return tobj;
01916 }
01917
01918 static struct time_object *
01919 get_new_timeval(VALUE obj)
01920 {
01921 struct time_object *tobj;
01922 TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
01923 if (TIME_INIT_P(tobj)) {
01924 rb_raise(rb_eTypeError, "already initialized %"PRIsVALUE, rb_obj_class(obj));
01925 }
01926 return tobj;
01927 }
01928
01929 static void
01930 time_modify(VALUE time)
01931 {
01932 rb_check_frozen(time);
01933 rb_check_trusted(time);
01934 }
01935
01936 static wideval_t
01937 timespec2timew(struct timespec *ts)
01938 {
01939 wideval_t timew;
01940
01941 timew = rb_time_magnify(TIMET2WV(ts->tv_sec));
01942 if (ts->tv_nsec)
01943 timew = wadd(timew, wmulquoll(WINT2WV(ts->tv_nsec), TIME_SCALE, 1000000000));
01944 return timew;
01945 }
01946
01947 static struct timespec
01948 timew2timespec(wideval_t timew)
01949 {
01950 VALUE subsecx;
01951 struct timespec ts;
01952 wideval_t timew2;
01953
01954 if (timew_out_of_timet_range(timew))
01955 rb_raise(rb_eArgError, "time out of system range");
01956 split_second(timew, &timew2, &subsecx);
01957 ts.tv_sec = WV2TIMET(timew2);
01958 ts.tv_nsec = NUM2LONG(mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE)));
01959 return ts;
01960 }
01961
01962 static struct timespec *
01963 timew2timespec_exact(wideval_t timew, struct timespec *ts)
01964 {
01965 VALUE subsecx;
01966 wideval_t timew2;
01967 VALUE nsecv;
01968
01969 if (timew_out_of_timet_range(timew))
01970 return NULL;
01971 split_second(timew, &timew2, &subsecx);
01972 ts->tv_sec = WV2TIMET(timew2);
01973 nsecv = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
01974 if (!FIXNUM_P(nsecv))
01975 return NULL;
01976 ts->tv_nsec = NUM2LONG(nsecv);
01977 return ts;
01978 }
01979
01980
01981
01982
01983
01984
01985
01986
01987 static VALUE
01988 time_init_0(VALUE time)
01989 {
01990 struct time_object *tobj;
01991 struct timespec ts;
01992
01993 time_modify(time);
01994 GetNewTimeval(time, tobj);
01995 tobj->gmt = 0;
01996 tobj->tm_got=0;
01997 tobj->timew = WINT2FIXWV(0);
01998 #ifdef HAVE_CLOCK_GETTIME
01999 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
02000 rb_sys_fail("clock_gettime");
02001 }
02002 #else
02003 {
02004 struct timeval tv;
02005 if (gettimeofday(&tv, 0) < 0) {
02006 rb_sys_fail("gettimeofday");
02007 }
02008 ts.tv_sec = tv.tv_sec;
02009 ts.tv_nsec = tv.tv_usec * 1000;
02010 }
02011 #endif
02012 tobj->timew = timespec2timew(&ts);
02013
02014 return time;
02015 }
02016
02017 static VALUE
02018 time_set_utc_offset(VALUE time, VALUE off)
02019 {
02020 struct time_object *tobj;
02021 off = num_exact(off);
02022
02023 time_modify(time);
02024 GetTimeval(time, tobj);
02025
02026 tobj->tm_got = 0;
02027 TIME_SET_FIXOFF(tobj, off);
02028
02029 return time;
02030 }
02031
02032 static void
02033 vtm_add_offset(struct vtm *vtm, VALUE off)
02034 {
02035 int sign;
02036 VALUE subsec, v;
02037 int sec, min, hour;
02038 int day;
02039
02040 vtm->utc_offset = sub(vtm->utc_offset, off);
02041
02042 if (lt(off, INT2FIX(0))) {
02043 sign = -1;
02044 off = neg(off);
02045 }
02046 else {
02047 sign = 1;
02048 }
02049 divmodv(off, INT2FIX(1), &off, &subsec);
02050 divmodv(off, INT2FIX(60), &off, &v);
02051 sec = NUM2INT(v);
02052 divmodv(off, INT2FIX(60), &off, &v);
02053 min = NUM2INT(v);
02054 divmodv(off, INT2FIX(24), &off, &v);
02055 hour = NUM2INT(v);
02056
02057 if (sign < 0) {
02058 subsec = neg(subsec);
02059 sec = -sec;
02060 min = -min;
02061 hour = -hour;
02062 }
02063
02064 day = 0;
02065
02066 if (!rb_equal(subsec, INT2FIX(0))) {
02067 vtm->subsecx = add(vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
02068 if (lt(vtm->subsecx, INT2FIX(0))) {
02069 vtm->subsecx = add(vtm->subsecx, INT2FIX(TIME_SCALE));
02070 sec -= 1;
02071 }
02072 if (le(INT2FIX(TIME_SCALE), vtm->subsecx)) {
02073 vtm->subsecx = sub(vtm->subsecx, INT2FIX(TIME_SCALE));
02074 sec += 1;
02075 }
02076 goto not_zero_sec;
02077 }
02078 if (sec) {
02079 not_zero_sec:
02080
02081
02082 vtm->sec += sec;
02083 if (vtm->sec < 0) {
02084 vtm->sec += 60;
02085 min -= 1;
02086 }
02087 if (60 <= vtm->sec) {
02088 vtm->sec -= 60;
02089 min += 1;
02090 }
02091 }
02092 if (min) {
02093 vtm->min += min;
02094 if (vtm->min < 0) {
02095 vtm->min += 60;
02096 hour -= 1;
02097 }
02098 if (60 <= vtm->min) {
02099 vtm->min -= 60;
02100 hour += 1;
02101 }
02102 }
02103 if (hour) {
02104 vtm->hour += hour;
02105 if (vtm->hour < 0) {
02106 vtm->hour += 24;
02107 day = -1;
02108 }
02109 if (24 <= vtm->hour) {
02110 vtm->hour -= 24;
02111 day = 1;
02112 }
02113 }
02114
02115 if (day) {
02116 if (day < 0) {
02117 if (vtm->mon == 1 && vtm->mday == 1) {
02118 vtm->mday = 31;
02119 vtm->mon = 12;
02120 vtm->year = sub(vtm->year, INT2FIX(1));
02121 vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
02122 }
02123 else if (vtm->mday == 1) {
02124 const int *days_in_month = leap_year_v_p(vtm->year) ?
02125 leap_year_days_in_month :
02126 common_year_days_in_month;
02127 vtm->mon--;
02128 vtm->mday = days_in_month[vtm->mon-1];
02129 vtm->yday--;
02130 }
02131 else {
02132 vtm->mday--;
02133 vtm->yday--;
02134 }
02135 vtm->wday = (vtm->wday + 6) % 7;
02136 }
02137 else {
02138 int leap = leap_year_v_p(vtm->year);
02139 if (vtm->mon == 12 && vtm->mday == 31) {
02140 vtm->year = add(vtm->year, INT2FIX(1));
02141 vtm->mon = 1;
02142 vtm->mday = 1;
02143 vtm->yday = 1;
02144 }
02145 else if (vtm->mday == (leap ? leap_year_days_in_month :
02146 common_year_days_in_month)[vtm->mon-1]) {
02147 vtm->mon++;
02148 vtm->mday = 1;
02149 vtm->yday++;
02150 }
02151 else {
02152 vtm->mday++;
02153 vtm->yday++;
02154 }
02155 vtm->wday = (vtm->wday + 1) % 7;
02156 }
02157 }
02158 }
02159
02160 static VALUE
02161 utc_offset_arg(VALUE arg)
02162 {
02163 VALUE tmp;
02164 if (!NIL_P(tmp = rb_check_string_type(arg))) {
02165 int n = 0;
02166 char *s = RSTRING_PTR(tmp);
02167 if (!rb_enc_str_asciicompat_p(tmp)) {
02168 invalid_utc_offset:
02169 rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
02170 }
02171 switch (RSTRING_LEN(tmp)) {
02172 case 9:
02173 if (s[6] != ':') goto invalid_utc_offset;
02174 if (!ISDIGIT(s[7]) || !ISDIGIT(s[8])) goto invalid_utc_offset;
02175 n += (s[7] * 10 + s[8] - '0' * 11);
02176 case 6:
02177 if (s[0] != '+' && s[0] != '-') goto invalid_utc_offset;
02178 if (!ISDIGIT(s[1]) || !ISDIGIT(s[2])) goto invalid_utc_offset;
02179 if (s[3] != ':') goto invalid_utc_offset;
02180 if (!ISDIGIT(s[4]) || !ISDIGIT(s[5])) goto invalid_utc_offset;
02181 break;
02182 default:
02183 goto invalid_utc_offset;
02184 }
02185 n += (s[1] * 10 + s[2] - '0' * 11) * 3600;
02186 n += (s[4] * 10 + s[5] - '0' * 11) * 60;
02187 if (s[0] == '-')
02188 n = -n;
02189 return INT2FIX(n);
02190 }
02191 else {
02192 return num_exact(arg);
02193 }
02194 }
02195
02196 static VALUE
02197 time_init_1(int argc, VALUE *argv, VALUE time)
02198 {
02199 struct vtm vtm;
02200 VALUE v[7];
02201 struct time_object *tobj;
02202
02203 vtm.wday = -1;
02204 vtm.yday = 0;
02205 vtm.zone = "";
02206
02207
02208 rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
02209
02210 vtm.year = obj2vint(v[0]);
02211
02212 vtm.mon = NIL_P(v[1]) ? 1 : month_arg(v[1]);
02213
02214 vtm.mday = NIL_P(v[2]) ? 1 : obj2int(v[2]);
02215
02216 vtm.hour = NIL_P(v[3]) ? 0 : obj2int(v[3]);
02217
02218 vtm.min = NIL_P(v[4]) ? 0 : obj2int(v[4]);
02219
02220 vtm.subsecx = INT2FIX(0);
02221 vtm.sec = NIL_P(v[5]) ? 0 : obj2subsecx(v[5], &vtm.subsecx);
02222
02223 vtm.isdst = -1;
02224 vtm.utc_offset = Qnil;
02225 if (!NIL_P(v[6])) {
02226 VALUE arg = v[6];
02227 if (arg == ID2SYM(rb_intern("dst")))
02228 vtm.isdst = 1;
02229 else if (arg == ID2SYM(rb_intern("std")))
02230 vtm.isdst = 0;
02231 else
02232 vtm.utc_offset = utc_offset_arg(arg);
02233 }
02234
02235 validate_vtm(&vtm);
02236
02237 time_modify(time);
02238 GetNewTimeval(time, tobj);
02239 tobj->gmt = 0;
02240 tobj->tm_got=0;
02241 tobj->timew = WINT2FIXWV(0);
02242
02243 if (!NIL_P(vtm.utc_offset)) {
02244 VALUE off = vtm.utc_offset;
02245 vtm_add_offset(&vtm, neg(off));
02246 vtm.utc_offset = Qnil;
02247 tobj->timew = timegmw(&vtm);
02248 return time_set_utc_offset(time, off);
02249 }
02250 else {
02251 tobj->timew = timelocalw(&vtm);
02252 return time_localtime(time);
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
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301 static VALUE
02302 time_init(int argc, VALUE *argv, VALUE time)
02303 {
02304 if (argc == 0)
02305 return time_init_0(time);
02306 else
02307 return time_init_1(argc, argv, time);
02308 }
02309
02310 static void
02311 time_overflow_p(time_t *secp, long *nsecp)
02312 {
02313 time_t tmp, sec = *secp;
02314 long nsec = *nsecp;
02315
02316 if (nsec >= 1000000000) {
02317 tmp = sec + nsec / 1000000000;
02318 nsec %= 1000000000;
02319 if (sec > 0 && tmp < 0) {
02320 rb_raise(rb_eRangeError, "out of Time range");
02321 }
02322 sec = tmp;
02323 }
02324 if (nsec < 0) {
02325 tmp = sec + NDIV(nsec,1000000000);
02326 nsec = NMOD(nsec,1000000000);
02327 if (sec < 0 && tmp > 0) {
02328 rb_raise(rb_eRangeError, "out of Time range");
02329 }
02330 sec = tmp;
02331 }
02332 #ifndef NEGATIVE_TIME_T
02333 if (sec < 0)
02334 rb_raise(rb_eArgError, "time must be positive");
02335 #endif
02336 *secp = sec;
02337 *nsecp = nsec;
02338 }
02339
02340 static wideval_t
02341 nsec2timew(time_t sec, long nsec)
02342 {
02343 struct timespec ts;
02344 time_overflow_p(&sec, &nsec);
02345 ts.tv_sec = sec;
02346 ts.tv_nsec = nsec;
02347 return timespec2timew(&ts);
02348 }
02349
02350 static VALUE
02351 time_new_timew(VALUE klass, wideval_t timew)
02352 {
02353 VALUE time = time_s_alloc(klass);
02354 struct time_object *tobj;
02355
02356 tobj = DATA_PTR(time);
02357 tobj->gmt = 0;
02358 tobj->timew = timew;
02359
02360 return time;
02361 }
02362
02363 VALUE
02364 rb_time_new(time_t sec, long usec)
02365 {
02366 wideval_t timew;
02367
02368 if (usec >= 1000000) {
02369 long sec2 = usec / 1000000;
02370 if (sec > TIMET_MAX - sec2) {
02371 rb_raise(rb_eRangeError, "out of Time range");
02372 }
02373 usec -= sec2 * 1000000;
02374 sec += sec2;
02375 }
02376 else if (usec <= 1000000) {
02377 long sec2 = usec / 1000000;
02378 if (sec < -TIMET_MAX - sec2) {
02379 rb_raise(rb_eRangeError, "out of Time range");
02380 }
02381 usec -= sec2 * 1000000;
02382 sec += sec2;
02383 }
02384
02385 timew = nsec2timew(sec, usec * 1000);
02386 return time_new_timew(rb_cTime, timew);
02387 }
02388
02389 VALUE
02390 rb_time_nano_new(time_t sec, long nsec)
02391 {
02392 return time_new_timew(rb_cTime, nsec2timew(sec, nsec));
02393 }
02394
02395 VALUE
02396 rb_time_num_new(VALUE timev, VALUE off)
02397 {
02398 VALUE time = time_new_timew(rb_cTime, rb_time_magnify(v2w(timev)));
02399
02400 if (!NIL_P(off)) {
02401 off = utc_offset_arg(off);
02402 validate_utc_offset(off);
02403 time_set_utc_offset(time, off);
02404 return time;
02405 }
02406
02407 return time;
02408 }
02409
02410 static struct timespec
02411 time_timespec(VALUE num, int interval)
02412 {
02413 struct timespec t;
02414 const char *tstr = interval ? "time interval" : "time";
02415 VALUE i, f, ary;
02416
02417 #ifndef NEGATIVE_TIME_T
02418 interval = 1;
02419 #endif
02420
02421 switch (TYPE(num)) {
02422 case T_FIXNUM:
02423 t.tv_sec = NUM2TIMET(num);
02424 if (interval && t.tv_sec < 0)
02425 rb_raise(rb_eArgError, "%s must be positive", tstr);
02426 t.tv_nsec = 0;
02427 break;
02428
02429 case T_FLOAT:
02430 if (interval && RFLOAT_VALUE(num) < 0.0)
02431 rb_raise(rb_eArgError, "%s must be positive", tstr);
02432 else {
02433 double f, d;
02434
02435 d = modf(RFLOAT_VALUE(num), &f);
02436 if (d >= 0) {
02437 t.tv_nsec = (int)(d*1e9+0.5);
02438 if (t.tv_nsec >= 1000000000) {
02439 t.tv_nsec -= 1000000000;
02440 f += 1;
02441 }
02442 }
02443 else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) {
02444 t.tv_nsec = 1000000000 - t.tv_nsec;
02445 f -= 1;
02446 }
02447 t.tv_sec = (time_t)f;
02448 if (f != t.tv_sec) {
02449 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(num));
02450 }
02451 }
02452 break;
02453
02454 case T_BIGNUM:
02455 t.tv_sec = NUM2TIMET(num);
02456 if (interval && t.tv_sec < 0)
02457 rb_raise(rb_eArgError, "%s must be positive", tstr);
02458 t.tv_nsec = 0;
02459 break;
02460
02461 default:
02462 i = INT2FIX(1);
02463 ary = rb_check_funcall(num, id_divmod, 1, &i);
02464 if (ary != Qundef && !NIL_P(ary = rb_check_array_type(ary))) {
02465 i = rb_ary_entry(ary, 0);
02466 f = rb_ary_entry(ary, 1);
02467 t.tv_sec = NUM2TIMET(i);
02468 if (interval && t.tv_sec < 0)
02469 rb_raise(rb_eArgError, "%s must be positive", tstr);
02470 f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
02471 t.tv_nsec = NUM2LONG(f);
02472 }
02473 else {
02474 rb_raise(rb_eTypeError, "can't convert %s into %s",
02475 rb_obj_classname(num), tstr);
02476 }
02477 break;
02478 }
02479 return t;
02480 }
02481
02482 static struct timeval
02483 time_timeval(VALUE num, int interval)
02484 {
02485 struct timespec ts;
02486 struct timeval tv;
02487
02488 ts = time_timespec(num, interval);
02489 tv.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
02490 tv.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
02491
02492 return tv;
02493 }
02494
02495 struct timeval
02496 rb_time_interval(VALUE num)
02497 {
02498 return time_timeval(num, TRUE);
02499 }
02500
02501 struct timeval
02502 rb_time_timeval(VALUE time)
02503 {
02504 struct time_object *tobj;
02505 struct timeval t;
02506 struct timespec ts;
02507
02508 if (IsTimeval(time)) {
02509 GetTimeval(time, tobj);
02510 ts = timew2timespec(tobj->timew);
02511 t.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
02512 t.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
02513 return t;
02514 }
02515 return time_timeval(time, FALSE);
02516 }
02517
02518 struct timespec
02519 rb_time_timespec(VALUE time)
02520 {
02521 struct time_object *tobj;
02522 struct timespec t;
02523
02524 if (IsTimeval(time)) {
02525 GetTimeval(time, tobj);
02526 t = timew2timespec(tobj->timew);
02527 return t;
02528 }
02529 return time_timespec(time, FALSE);
02530 }
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541 static VALUE
02542 time_s_now(VALUE klass)
02543 {
02544 return rb_class_new_instance(0, NULL, klass);
02545 }
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570 static VALUE
02571 time_s_at(int argc, VALUE *argv, VALUE klass)
02572 {
02573 VALUE time, t;
02574 wideval_t timew;
02575
02576 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
02577 time = num_exact(time);
02578 t = num_exact(t);
02579 timew = wadd(rb_time_magnify(v2w(time)), wmulquoll(v2w(t), TIME_SCALE, 1000000));
02580 t = time_new_timew(klass, timew);
02581 }
02582 else if (IsTimeval(time)) {
02583 struct time_object *tobj, *tobj2;
02584 GetTimeval(time, tobj);
02585 t = time_new_timew(klass, tobj->timew);
02586 GetTimeval(t, tobj2);
02587 TIME_COPY_GMT(tobj2, tobj);
02588 }
02589 else {
02590 timew = rb_time_magnify(v2w(num_exact(time)));
02591 t = time_new_timew(klass, timew);
02592 }
02593
02594 return t;
02595 }
02596
02597 static const char months[][4] = {
02598 "jan", "feb", "mar", "apr", "may", "jun",
02599 "jul", "aug", "sep", "oct", "nov", "dec",
02600 };
02601
02602 static int
02603 obj2int(VALUE obj)
02604 {
02605 if (RB_TYPE_P(obj, T_STRING)) {
02606 obj = rb_str_to_inum(obj, 10, FALSE);
02607 }
02608
02609 return NUM2INT(obj);
02610 }
02611
02612 static VALUE
02613 obj2vint(VALUE obj)
02614 {
02615 if (RB_TYPE_P(obj, T_STRING)) {
02616 obj = rb_str_to_inum(obj, 10, FALSE);
02617 }
02618 else {
02619 obj = rb_to_int(obj);
02620 }
02621
02622 return obj;
02623 }
02624
02625 static int
02626 obj2subsecx(VALUE obj, VALUE *subsecx)
02627 {
02628 VALUE subsec;
02629
02630 if (RB_TYPE_P(obj, T_STRING)) {
02631 obj = rb_str_to_inum(obj, 10, FALSE);
02632 *subsecx = INT2FIX(0);
02633 return NUM2INT(obj);
02634 }
02635
02636 divmodv(num_exact(obj), INT2FIX(1), &obj, &subsec);
02637 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
02638 return NUM2INT(obj);
02639 }
02640
02641 static long
02642 usec2subsecx(VALUE obj)
02643 {
02644 if (RB_TYPE_P(obj, T_STRING)) {
02645 obj = rb_str_to_inum(obj, 10, FALSE);
02646 }
02647
02648 return mulquo(num_exact(obj), INT2FIX(TIME_SCALE), INT2FIX(1000000));
02649 }
02650
02651 static int
02652 month_arg(VALUE arg)
02653 {
02654 int i, mon;
02655
02656 VALUE s = rb_check_string_type(arg);
02657 if (!NIL_P(s)) {
02658 mon = 0;
02659 for (i=0; i<12; i++) {
02660 if (RSTRING_LEN(s) == 3 &&
02661 STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
02662 mon = i+1;
02663 break;
02664 }
02665 }
02666 if (mon == 0) {
02667 char c = RSTRING_PTR(s)[0];
02668
02669 if ('0' <= c && c <= '9') {
02670 mon = obj2int(s);
02671 }
02672 }
02673 }
02674 else {
02675 mon = obj2int(arg);
02676 }
02677 return mon;
02678 }
02679
02680 static VALUE
02681 validate_utc_offset(VALUE utc_offset)
02682 {
02683 if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400)))
02684 rb_raise(rb_eArgError, "utc_offset out of range");
02685 return utc_offset;
02686 }
02687
02688 static VALUE
02689 validate_zone_name(VALUE zone_name)
02690 {
02691 StringValueCStr(zone_name);
02692 return zone_name;
02693 }
02694
02695 static void
02696 validate_vtm(struct vtm *vtm)
02697 {
02698 if ( vtm->mon < 1 || vtm->mon > 12
02699 || vtm->mday < 1 || vtm->mday > 31
02700 || vtm->hour < 0 || vtm->hour > 24
02701 || (vtm->hour == 24 && (vtm->min > 0 || vtm->sec > 0))
02702 || vtm->min < 0 || vtm->min > 59
02703 || vtm->sec < 0 || vtm->sec > 60
02704 || lt(vtm->subsecx, INT2FIX(0)) || ge(vtm->subsecx, INT2FIX(TIME_SCALE))
02705 || (!NIL_P(vtm->utc_offset) && (validate_utc_offset(vtm->utc_offset), 0)))
02706 rb_raise(rb_eArgError, "argument out of range");
02707 }
02708
02709 static void
02710 time_arg(int argc, VALUE *argv, struct vtm *vtm)
02711 {
02712 VALUE v[8];
02713
02714 vtm->year = INT2FIX(0);
02715 vtm->mon = 0;
02716 vtm->mday = 0;
02717 vtm->hour = 0;
02718 vtm->min = 0;
02719 vtm->sec = 0;
02720 vtm->subsecx = INT2FIX(0);
02721 vtm->utc_offset = Qnil;
02722 vtm->wday = 0;
02723 vtm->yday = 0;
02724 vtm->isdst = 0;
02725 vtm->zone = "";
02726
02727 if (argc == 10) {
02728 v[0] = argv[5];
02729 v[1] = argv[4];
02730 v[2] = argv[3];
02731 v[3] = argv[2];
02732 v[4] = argv[1];
02733 v[5] = argv[0];
02734 v[6] = Qnil;
02735 vtm->isdst = RTEST(argv[8]) ? 1 : 0;
02736 }
02737 else {
02738 rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
02739
02740
02741 vtm->wday = -1;
02742 vtm->isdst = -1;
02743 }
02744
02745 vtm->year = obj2vint(v[0]);
02746
02747 if (NIL_P(v[1])) {
02748 vtm->mon = 1;
02749 }
02750 else {
02751 vtm->mon = month_arg(v[1]);
02752 }
02753
02754 if (NIL_P(v[2])) {
02755 vtm->mday = 1;
02756 }
02757 else {
02758 vtm->mday = obj2int(v[2]);
02759 }
02760
02761 vtm->hour = NIL_P(v[3])?0:obj2int(v[3]);
02762
02763 vtm->min = NIL_P(v[4])?0:obj2int(v[4]);
02764
02765 if (!NIL_P(v[6]) && argc == 7) {
02766 vtm->sec = NIL_P(v[5])?0:obj2int(v[5]);
02767 vtm->subsecx = usec2subsecx(v[6]);
02768 }
02769 else {
02770
02771 vtm->sec = NIL_P(v[5])?0:obj2subsecx(v[5], &vtm->subsecx);
02772 }
02773
02774 validate_vtm(vtm);
02775 }
02776
02777 static int
02778 leap_year_p(long y)
02779 {
02780 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
02781 }
02782
02783 static time_t
02784 timegm_noleapsecond(struct tm *tm)
02785 {
02786 long tm_year = tm->tm_year;
02787 int tm_yday = tm->tm_mday;
02788 if (leap_year_p(tm_year + 1900))
02789 tm_yday += leap_year_yday_offset[tm->tm_mon];
02790 else
02791 tm_yday += common_year_yday_offset[tm->tm_mon];
02792
02793
02794
02795
02796
02797
02798
02799 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
02800 (time_t)(tm_yday +
02801 (tm_year-70)*365 +
02802 DIV(tm_year-69,4) -
02803 DIV(tm_year-1,100) +
02804 DIV(tm_year+299,400))*86400;
02805 }
02806
02807 #if 0
02808 #define DEBUG_FIND_TIME_NUMGUESS
02809 #define DEBUG_GUESSRANGE
02810 #endif
02811
02812 #ifdef DEBUG_GUESSRANGE
02813 #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))
02814 #else
02815 #define DEBUG_REPORT_GUESSRANGE
02816 #endif
02817
02818 #ifdef DEBUG_FIND_TIME_NUMGUESS
02819 #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
02820 static unsigned long long find_time_numguess;
02821
02822 static VALUE find_time_numguess_getter(void)
02823 {
02824 return ULL2NUM(find_time_numguess);
02825 }
02826 #else
02827 #define DEBUG_FIND_TIME_NUMGUESS_INC
02828 #endif
02829
02830 static const char *
02831 find_time_t(struct tm *tptr, int utc_p, time_t *tp)
02832 {
02833 time_t guess, guess0, guess_lo, guess_hi;
02834 struct tm *tm, tm0, tm_lo, tm_hi;
02835 int d;
02836 int find_dst;
02837 struct tm result;
02838 int status;
02839 int tptr_tm_yday;
02840
02841 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
02842
02843 guess_lo = TIMET_MIN;
02844 guess_hi = TIMET_MAX;
02845
02846 find_dst = 0 < tptr->tm_isdst;
02847
02848 #if defined(HAVE_MKTIME)
02849 tm0 = *tptr;
02850 if (!utc_p && (guess = mktime(&tm0)) != -1) {
02851 tm = GUESS(&guess);
02852 if (tm && tmcmp(tptr, tm) == 0) {
02853 goto found;
02854 }
02855 }
02856 #endif
02857
02858 tm0 = *tptr;
02859 if (tm0.tm_mon < 0) {
02860 tm0.tm_mon = 0;
02861 tm0.tm_mday = 1;
02862 tm0.tm_hour = 0;
02863 tm0.tm_min = 0;
02864 tm0.tm_sec = 0;
02865 }
02866 else if (11 < tm0.tm_mon) {
02867 tm0.tm_mon = 11;
02868 tm0.tm_mday = 31;
02869 tm0.tm_hour = 23;
02870 tm0.tm_min = 59;
02871 tm0.tm_sec = 60;
02872 }
02873 else if (tm0.tm_mday < 1) {
02874 tm0.tm_mday = 1;
02875 tm0.tm_hour = 0;
02876 tm0.tm_min = 0;
02877 tm0.tm_sec = 0;
02878 }
02879 else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
02880 leap_year_days_in_month :
02881 common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
02882 tm0.tm_mday = d;
02883 tm0.tm_hour = 23;
02884 tm0.tm_min = 59;
02885 tm0.tm_sec = 60;
02886 }
02887 else if (tm0.tm_hour < 0) {
02888 tm0.tm_hour = 0;
02889 tm0.tm_min = 0;
02890 tm0.tm_sec = 0;
02891 }
02892 else if (23 < tm0.tm_hour) {
02893 tm0.tm_hour = 23;
02894 tm0.tm_min = 59;
02895 tm0.tm_sec = 60;
02896 }
02897 else if (tm0.tm_min < 0) {
02898 tm0.tm_min = 0;
02899 tm0.tm_sec = 0;
02900 }
02901 else if (59 < tm0.tm_min) {
02902 tm0.tm_min = 59;
02903 tm0.tm_sec = 60;
02904 }
02905 else if (tm0.tm_sec < 0) {
02906 tm0.tm_sec = 0;
02907 }
02908 else if (60 < tm0.tm_sec) {
02909 tm0.tm_sec = 60;
02910 }
02911
02912 DEBUG_REPORT_GUESSRANGE;
02913 guess0 = guess = timegm_noleapsecond(&tm0);
02914 tm = GUESS(&guess);
02915 if (tm) {
02916 d = tmcmp(tptr, tm);
02917 if (d == 0) { goto found; }
02918 if (d < 0) {
02919 guess_hi = guess;
02920 guess -= 24 * 60 * 60;
02921 }
02922 else {
02923 guess_lo = guess;
02924 guess += 24 * 60 * 60;
02925 }
02926 DEBUG_REPORT_GUESSRANGE;
02927 if (guess_lo < guess && guess < guess_hi && (tm = GUESS(&guess)) != NULL) {
02928 d = tmcmp(tptr, tm);
02929 if (d == 0) { goto found; }
02930 if (d < 0)
02931 guess_hi = guess;
02932 else
02933 guess_lo = guess;
02934 DEBUG_REPORT_GUESSRANGE;
02935 }
02936 }
02937
02938 tm = GUESS(&guess_lo);
02939 if (!tm) goto error;
02940 d = tmcmp(tptr, tm);
02941 if (d < 0) goto out_of_range;
02942 if (d == 0) { guess = guess_lo; goto found; }
02943 tm_lo = *tm;
02944
02945 tm = GUESS(&guess_hi);
02946 if (!tm) goto error;
02947 d = tmcmp(tptr, tm);
02948 if (d > 0) goto out_of_range;
02949 if (d == 0) { guess = guess_hi; goto found; }
02950 tm_hi = *tm;
02951
02952 DEBUG_REPORT_GUESSRANGE;
02953
02954 status = 1;
02955
02956 while (guess_lo + 1 < guess_hi) {
02957 if (status == 0) {
02958 binsearch:
02959 guess = guess_lo / 2 + guess_hi / 2;
02960 if (guess <= guess_lo)
02961 guess = guess_lo + 1;
02962 else if (guess >= guess_hi)
02963 guess = guess_hi - 1;
02964 status = 1;
02965 }
02966 else {
02967 if (status == 1) {
02968 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
02969 guess = guess_hi - (guess0_hi - guess0);
02970 if (guess == guess_hi)
02971 guess--;
02972 status = 2;
02973 }
02974 else if (status == 2) {
02975 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
02976 guess = guess_lo + (guess0 - guess0_lo);
02977 if (guess == guess_lo)
02978 guess++;
02979 status = 0;
02980 }
02981 if (guess <= guess_lo || guess_hi <= guess) {
02982
02983 #ifdef DEBUG_GUESSRANGE
02984 if (guess <= guess_lo) fprintf(stderr, "too small guess: %ld <= %ld\n", guess, guess_lo);
02985 if (guess_hi <= guess) fprintf(stderr, "too big guess: %ld <= %ld\n", guess_hi, guess);
02986 #endif
02987 goto binsearch;
02988 }
02989 }
02990
02991 tm = GUESS(&guess);
02992 if (!tm) goto error;
02993
02994 d = tmcmp(tptr, tm);
02995
02996 if (d < 0) {
02997 guess_hi = guess;
02998 tm_hi = *tm;
02999 DEBUG_REPORT_GUESSRANGE;
03000 }
03001 else if (d > 0) {
03002 guess_lo = guess;
03003 tm_lo = *tm;
03004 DEBUG_REPORT_GUESSRANGE;
03005 }
03006 else {
03007 found:
03008 if (!utc_p) {
03009
03010 time_t guess2;
03011 if (find_dst) {
03012 guess2 = guess - 2 * 60 * 60;
03013 tm = LOCALTIME(&guess2, result);
03014 if (tm) {
03015 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
03016 tptr->tm_min != tm->tm_min ||
03017 tptr->tm_sec != tm->tm_sec) {
03018 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
03019 (tm->tm_min - tptr->tm_min) * 60 +
03020 (tm->tm_sec - tptr->tm_sec);
03021 if (tptr->tm_mday != tm->tm_mday)
03022 guess2 += 24 * 60 * 60;
03023 if (guess != guess2) {
03024 tm = LOCALTIME(&guess2, result);
03025 if (tm && tmcmp(tptr, tm) == 0) {
03026 if (guess < guess2)
03027 *tp = guess;
03028 else
03029 *tp = guess2;
03030 return NULL;
03031 }
03032 }
03033 }
03034 }
03035 }
03036 else {
03037 guess2 = guess + 2 * 60 * 60;
03038 tm = LOCALTIME(&guess2, result);
03039 if (tm) {
03040 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
03041 tptr->tm_min != tm->tm_min ||
03042 tptr->tm_sec != tm->tm_sec) {
03043 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
03044 (tm->tm_min - tptr->tm_min) * 60 +
03045 (tm->tm_sec - tptr->tm_sec);
03046 if (tptr->tm_mday != tm->tm_mday)
03047 guess2 -= 24 * 60 * 60;
03048 if (guess != guess2) {
03049 tm = LOCALTIME(&guess2, result);
03050 if (tm && tmcmp(tptr, tm) == 0) {
03051 if (guess < guess2)
03052 *tp = guess2;
03053 else
03054 *tp = guess;
03055 return NULL;
03056 }
03057 }
03058 }
03059 }
03060 }
03061 }
03062 *tp = guess;
03063 return NULL;
03064 }
03065 }
03066
03067
03068
03069
03070
03071
03072
03073
03074
03075 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
03076
03077 *tp = guess_lo +
03078 ((tptr->tm_year - tm_lo.tm_year) * 365 +
03079 ((tptr->tm_year-69)/4) -
03080 ((tptr->tm_year-1)/100) +
03081 ((tptr->tm_year+299)/400) -
03082 ((tm_lo.tm_year-69)/4) +
03083 ((tm_lo.tm_year-1)/100) -
03084 ((tm_lo.tm_year+299)/400) +
03085 tptr_tm_yday -
03086 tm_lo.tm_yday) * 86400 +
03087 (tptr->tm_hour - tm_lo.tm_hour) * 3600 +
03088 (tptr->tm_min - tm_lo.tm_min) * 60 +
03089 (tptr->tm_sec - (tm_lo.tm_sec == 60 ? 59 : tm_lo.tm_sec));
03090
03091 return NULL;
03092
03093 out_of_range:
03094 return "time out of range";
03095
03096 error:
03097 return "gmtime/localtime error";
03098 }
03099
03100 static int
03101 vtmcmp(struct vtm *a, struct vtm *b)
03102 {
03103 if (ne(a->year, b->year))
03104 return lt(a->year, b->year) ? -1 : 1;
03105 else if (a->mon != b->mon)
03106 return a->mon < b->mon ? -1 : 1;
03107 else if (a->mday != b->mday)
03108 return a->mday < b->mday ? -1 : 1;
03109 else if (a->hour != b->hour)
03110 return a->hour < b->hour ? -1 : 1;
03111 else if (a->min != b->min)
03112 return a->min < b->min ? -1 : 1;
03113 else if (a->sec != b->sec)
03114 return a->sec < b->sec ? -1 : 1;
03115 else if (ne(a->subsecx, b->subsecx))
03116 return lt(a->subsecx, b->subsecx) ? -1 : 1;
03117 else
03118 return 0;
03119 }
03120
03121 static int
03122 tmcmp(struct tm *a, struct tm *b)
03123 {
03124 if (a->tm_year != b->tm_year)
03125 return a->tm_year < b->tm_year ? -1 : 1;
03126 else if (a->tm_mon != b->tm_mon)
03127 return a->tm_mon < b->tm_mon ? -1 : 1;
03128 else if (a->tm_mday != b->tm_mday)
03129 return a->tm_mday < b->tm_mday ? -1 : 1;
03130 else if (a->tm_hour != b->tm_hour)
03131 return a->tm_hour < b->tm_hour ? -1 : 1;
03132 else if (a->tm_min != b->tm_min)
03133 return a->tm_min < b->tm_min ? -1 : 1;
03134 else if (a->tm_sec != b->tm_sec)
03135 return a->tm_sec < b->tm_sec ? -1 : 1;
03136 else
03137 return 0;
03138 }
03139
03140 static VALUE
03141 time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
03142 {
03143 struct vtm vtm;
03144 VALUE time;
03145
03146 time_arg(argc, argv, &vtm);
03147 if (utc_p)
03148 time = time_new_timew(klass, timegmw(&vtm));
03149 else
03150 time = time_new_timew(klass, timelocalw(&vtm));
03151 if (utc_p) return time_gmtime(time);
03152 return time_localtime(time);
03153 }
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
03182
03183
03184
03185
03186
03187 static VALUE
03188 time_s_mkutc(int argc, VALUE *argv, VALUE klass)
03189 {
03190 return time_utc_or_local(argc, argv, TRUE, klass);
03191 }
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218 static VALUE
03219 time_s_mktime(int argc, VALUE *argv, VALUE klass)
03220 {
03221 return time_utc_or_local(argc, argv, FALSE, klass);
03222 }
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237 static VALUE
03238 time_to_i(VALUE time)
03239 {
03240 struct time_object *tobj;
03241
03242 GetTimeval(time, tobj);
03243 return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE)));
03244 }
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261 static VALUE
03262 time_to_f(VALUE time)
03263 {
03264 struct time_object *tobj;
03265
03266 GetTimeval(time, tobj);
03267 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
03268 }
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285 static VALUE
03286 time_to_r(VALUE time)
03287 {
03288 struct time_object *tobj;
03289 VALUE v;
03290
03291 GetTimeval(time, tobj);
03292 v = w2v(rb_time_unmagnify(tobj->timew));
03293 if (!RB_TYPE_P(v, T_RATIONAL)) {
03294 v = rb_Rational1(v);
03295 }
03296 return v;
03297 }
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311 static VALUE
03312 time_usec(VALUE time)
03313 {
03314 struct time_object *tobj;
03315 wideval_t w, q, r;
03316
03317 GetTimeval(time, tobj);
03318
03319 w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
03320 wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
03321 return rb_to_int(w2v(q));
03322 }
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342 static VALUE
03343 time_nsec(VALUE time)
03344 {
03345 struct time_object *tobj;
03346
03347 GetTimeval(time, tobj);
03348 return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
03349 }
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370 static VALUE
03371 time_subsec(VALUE time)
03372 {
03373 struct time_object *tobj;
03374
03375 GetTimeval(time, tobj);
03376 return quo(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))), INT2FIX(TIME_SCALE));
03377 }
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404 static VALUE
03405 time_cmp(VALUE time1, VALUE time2)
03406 {
03407 struct time_object *tobj1, *tobj2;
03408 int n;
03409
03410 GetTimeval(time1, tobj1);
03411 if (IsTimeval(time2)) {
03412 GetTimeval(time2, tobj2);
03413 n = wcmp(tobj1->timew, tobj2->timew);
03414 }
03415 else {
03416 return rb_invcmp(time1, time2);
03417 }
03418 if (n == 0) return INT2FIX(0);
03419 if (n > 0) return INT2FIX(1);
03420 return INT2FIX(-1);
03421 }
03422
03423
03424
03425
03426
03427
03428
03429
03430
03431 static VALUE
03432 time_eql(VALUE time1, VALUE time2)
03433 {
03434 struct time_object *tobj1, *tobj2;
03435
03436 GetTimeval(time1, tobj1);
03437 if (IsTimeval(time2)) {
03438 GetTimeval(time2, tobj2);
03439 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
03440 }
03441 return Qfalse;
03442 }
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462 static VALUE
03463 time_utc_p(VALUE time)
03464 {
03465 struct time_object *tobj;
03466
03467 GetTimeval(time, tobj);
03468 if (TIME_UTC_P(tobj)) return Qtrue;
03469 return Qfalse;
03470 }
03471
03472
03473
03474
03475
03476
03477
03478
03479 static VALUE
03480 time_hash(VALUE time)
03481 {
03482 struct time_object *tobj;
03483
03484 GetTimeval(time, tobj);
03485 return rb_hash(w2v(tobj->timew));
03486 }
03487
03488
03489 static VALUE
03490 time_init_copy(VALUE copy, VALUE time)
03491 {
03492 struct time_object *tobj, *tcopy;
03493
03494 if (!OBJ_INIT_COPY(copy, time)) return copy;
03495 GetTimeval(time, tobj);
03496 GetNewTimeval(copy, tcopy);
03497 MEMCPY(tcopy, tobj, struct time_object, 1);
03498
03499 return copy;
03500 }
03501
03502 static VALUE
03503 time_dup(VALUE time)
03504 {
03505 VALUE dup = time_s_alloc(rb_obj_class(time));
03506 time_init_copy(dup, time);
03507 return dup;
03508 }
03509
03510 static VALUE
03511 time_localtime(VALUE time)
03512 {
03513 struct time_object *tobj;
03514 struct vtm vtm;
03515
03516 GetTimeval(time, tobj);
03517 if (TIME_LOCALTIME_P(tobj)) {
03518 if (tobj->tm_got)
03519 return time;
03520 }
03521 else {
03522 time_modify(time);
03523 }
03524
03525 if (!localtimew(tobj->timew, &vtm))
03526 rb_raise(rb_eArgError, "localtime error");
03527 tobj->vtm = vtm;
03528
03529 tobj->tm_got = 1;
03530 TIME_SET_LOCALTIME(tobj);
03531 return time;
03532 }
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554 static VALUE
03555 time_localtime_m(int argc, VALUE *argv, VALUE time)
03556 {
03557 VALUE off;
03558 rb_scan_args(argc, argv, "01", &off);
03559
03560 if (!NIL_P(off)) {
03561 off = utc_offset_arg(off);
03562 validate_utc_offset(off);
03563
03564 time_set_utc_offset(time, off);
03565 return time_fixoff(time);
03566 }
03567
03568 return time_localtime(time);
03569 }
03570
03571
03572
03573
03574
03575
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588
03589 static VALUE
03590 time_gmtime(VALUE time)
03591 {
03592 struct time_object *tobj;
03593 struct vtm vtm;
03594
03595 GetTimeval(time, tobj);
03596 if (TIME_UTC_P(tobj)) {
03597 if (tobj->tm_got)
03598 return time;
03599 }
03600 else {
03601 time_modify(time);
03602 }
03603
03604 if (!gmtimew(tobj->timew, &vtm))
03605 rb_raise(rb_eArgError, "gmtime error");
03606 tobj->vtm = vtm;
03607
03608 tobj->tm_got = 1;
03609 TIME_SET_UTC(tobj);
03610 return time;
03611 }
03612
03613 static VALUE
03614 time_fixoff(VALUE time)
03615 {
03616 struct time_object *tobj;
03617 struct vtm vtm;
03618 VALUE off;
03619
03620 GetTimeval(time, tobj);
03621 if (TIME_FIXOFF_P(tobj)) {
03622 if (tobj->tm_got)
03623 return time;
03624 }
03625 else {
03626 time_modify(time);
03627 }
03628
03629 if (TIME_FIXOFF_P(tobj))
03630 off = tobj->vtm.utc_offset;
03631 else
03632 off = INT2FIX(0);
03633
03634 if (!gmtimew(tobj->timew, &vtm))
03635 rb_raise(rb_eArgError, "gmtime error");
03636
03637 tobj->vtm = vtm;
03638 vtm_add_offset(&tobj->vtm, off);
03639
03640 tobj->tm_got = 1;
03641 TIME_SET_FIXOFF(tobj, off);
03642 return time;
03643 }
03644
03645
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667 static VALUE
03668 time_getlocaltime(int argc, VALUE *argv, VALUE time)
03669 {
03670 VALUE off;
03671 rb_scan_args(argc, argv, "01", &off);
03672
03673 if (!NIL_P(off)) {
03674 off = utc_offset_arg(off);
03675 validate_utc_offset(off);
03676
03677 time = time_dup(time);
03678 time_set_utc_offset(time, off);
03679 return time_fixoff(time);
03680 }
03681
03682 return time_localtime(time_dup(time));
03683 }
03684
03685
03686
03687
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697
03698
03699 static VALUE
03700 time_getgmtime(VALUE time)
03701 {
03702 return time_gmtime(time_dup(time));
03703 }
03704
03705 static VALUE
03706 time_get_tm(VALUE time, struct time_object *tobj)
03707 {
03708 if (TIME_UTC_P(tobj)) return time_gmtime(time);
03709 if (TIME_FIXOFF_P(tobj)) return time_fixoff(time);
03710 return time_localtime(time);
03711 }
03712
03713 static VALUE strftimev(const char *fmt, VALUE time, rb_encoding *enc);
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725 static VALUE
03726 time_asctime(VALUE time)
03727 {
03728 return strftimev("%a %b %e %T %Y", time, rb_usascii_encoding());
03729 }
03730
03731
03732
03733
03734
03735
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747 static VALUE
03748 time_to_s(VALUE time)
03749 {
03750 struct time_object *tobj;
03751
03752 GetTimeval(time, tobj);
03753 if (TIME_UTC_P(tobj))
03754 return strftimev("%Y-%m-%d %H:%M:%S UTC", time, rb_usascii_encoding());
03755 else
03756 return strftimev("%Y-%m-%d %H:%M:%S %z", time, rb_usascii_encoding());
03757 }
03758
03759 static VALUE
03760 time_add(struct time_object *tobj, VALUE offset, int sign)
03761 {
03762 VALUE result;
03763 offset = num_exact(offset);
03764 if (sign < 0)
03765 result = time_new_timew(rb_cTime, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
03766 else
03767 result = time_new_timew(rb_cTime, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
03768 if (TIME_UTC_P(tobj)) {
03769 GetTimeval(result, tobj);
03770 TIME_SET_UTC(tobj);
03771 }
03772 else if (TIME_FIXOFF_P(tobj)) {
03773 VALUE off = tobj->vtm.utc_offset;
03774 GetTimeval(result, tobj);
03775 TIME_SET_FIXOFF(tobj, off);
03776 }
03777 return result;
03778 }
03779
03780
03781
03782
03783
03784
03785
03786
03787
03788
03789
03790
03791 static VALUE
03792 time_plus(VALUE time1, VALUE time2)
03793 {
03794 struct time_object *tobj;
03795 GetTimeval(time1, tobj);
03796
03797 if (IsTimeval(time2)) {
03798 rb_raise(rb_eTypeError, "time + time?");
03799 }
03800 return time_add(tobj, time2, 1);
03801 }
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818 static VALUE
03819 time_minus(VALUE time1, VALUE time2)
03820 {
03821 struct time_object *tobj;
03822
03823 GetTimeval(time1, tobj);
03824 if (IsTimeval(time2)) {
03825 struct time_object *tobj2;
03826
03827 GetTimeval(time2, tobj2);
03828 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
03829 }
03830 return time_add(tobj, time2, -1);
03831 }
03832
03833
03834
03835
03836
03837
03838
03839
03840
03841
03842
03843
03844
03845
03846
03847
03848 VALUE
03849 rb_time_succ(VALUE time)
03850 {
03851 struct time_object *tobj;
03852 struct time_object *tobj2;
03853
03854 rb_warn("Time#succ is obsolete; use time + 1");
03855 GetTimeval(time, tobj);
03856 time = time_new_timew(rb_cTime, wadd(tobj->timew, WINT2FIXWV(TIME_SCALE)));
03857 GetTimeval(time, tobj2);
03858 TIME_COPY_GMT(tobj2, tobj);
03859 return time;
03860 }
03861
03862 #define time_succ rb_time_succ
03863
03864
03865
03866
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901 static VALUE
03902 time_round(int argc, VALUE *argv, VALUE time)
03903 {
03904 VALUE ndigits, v, a, b, den;
03905 long nd;
03906 struct time_object *tobj;
03907
03908 rb_scan_args(argc, argv, "01", &ndigits);
03909
03910 if (NIL_P(ndigits))
03911 ndigits = INT2FIX(0);
03912 else
03913 ndigits = rb_to_int(ndigits);
03914
03915 nd = NUM2LONG(ndigits);
03916 if (nd < 0)
03917 rb_raise(rb_eArgError, "negative ndigits given");
03918
03919 GetTimeval(time, tobj);
03920 v = w2v(rb_time_unmagnify(tobj->timew));
03921
03922 a = INT2FIX(1);
03923 b = INT2FIX(10);
03924 while (0 < nd) {
03925 if (nd & 1)
03926 a = mul(a, b);
03927 b = mul(b, b);
03928 nd = nd >> 1;
03929 }
03930 den = quo(INT2FIX(1), a);
03931 v = mod(v, den);
03932 if (lt(v, quo(den, INT2FIX(2))))
03933 return time_add(tobj, v, -1);
03934 else
03935 return time_add(tobj, sub(den, v), 1);
03936 }
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947
03948
03949
03950
03951
03952 static VALUE
03953 time_sec(VALUE time)
03954 {
03955 struct time_object *tobj;
03956
03957 GetTimeval(time, tobj);
03958 MAKE_TM(time, tobj);
03959 return INT2FIX(tobj->vtm.sec);
03960 }
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972 static VALUE
03973 time_min(VALUE time)
03974 {
03975 struct time_object *tobj;
03976
03977 GetTimeval(time, tobj);
03978 MAKE_TM(time, tobj);
03979 return INT2FIX(tobj->vtm.min);
03980 }
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991
03992 static VALUE
03993 time_hour(VALUE time)
03994 {
03995 struct time_object *tobj;
03996
03997 GetTimeval(time, tobj);
03998 MAKE_TM(time, tobj);
03999 return INT2FIX(tobj->vtm.hour);
04000 }
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014 static VALUE
04015 time_mday(VALUE time)
04016 {
04017 struct time_object *tobj;
04018
04019 GetTimeval(time, tobj);
04020 MAKE_TM(time, tobj);
04021 return INT2FIX(tobj->vtm.mday);
04022 }
04023
04024
04025
04026
04027
04028
04029
04030
04031
04032
04033
04034
04035
04036 static VALUE
04037 time_mon(VALUE time)
04038 {
04039 struct time_object *tobj;
04040
04041 GetTimeval(time, tobj);
04042 MAKE_TM(time, tobj);
04043 return INT2FIX(tobj->vtm.mon);
04044 }
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 static VALUE
04057 time_year(VALUE time)
04058 {
04059 struct time_object *tobj;
04060
04061 GetTimeval(time, tobj);
04062 MAKE_TM(time, tobj);
04063 return tobj->vtm.year;
04064 }
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083
04084 static VALUE
04085 time_wday(VALUE time)
04086 {
04087 struct time_object *tobj;
04088
04089 GetTimeval(time, tobj);
04090 MAKE_TM(time, tobj);
04091 return INT2FIX(tobj->vtm.wday);
04092 }
04093
04094 #define wday_p(n) {\
04095 struct time_object *tobj;\
04096 GetTimeval(time, tobj);\
04097 MAKE_TM(time, tobj);\
04098 return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\
04099 }
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111 static VALUE
04112 time_sunday(VALUE time)
04113 {
04114 wday_p(0);
04115 }
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127 static VALUE
04128 time_monday(VALUE time)
04129 {
04130 wday_p(1);
04131 }
04132
04133
04134
04135
04136
04137
04138
04139
04140
04141
04142
04143 static VALUE
04144 time_tuesday(VALUE time)
04145 {
04146 wday_p(2);
04147 }
04148
04149
04150
04151
04152
04153
04154
04155
04156
04157
04158
04159 static VALUE
04160 time_wednesday(VALUE time)
04161 {
04162 wday_p(3);
04163 }
04164
04165
04166
04167
04168
04169
04170
04171
04172
04173
04174
04175 static VALUE
04176 time_thursday(VALUE time)
04177 {
04178 wday_p(4);
04179 }
04180
04181
04182
04183
04184
04185
04186
04187
04188
04189
04190
04191 static VALUE
04192 time_friday(VALUE time)
04193 {
04194 wday_p(5);
04195 }
04196
04197
04198
04199
04200
04201
04202
04203
04204
04205
04206
04207 static VALUE
04208 time_saturday(VALUE time)
04209 {
04210 wday_p(6);
04211 }
04212
04213
04214
04215
04216
04217
04218
04219
04220
04221
04222
04223 static VALUE
04224 time_yday(VALUE time)
04225 {
04226 struct time_object *tobj;
04227
04228 GetTimeval(time, tobj);
04229 MAKE_TM(time, tobj);
04230 return INT2FIX(tobj->vtm.yday);
04231 }
04232
04233
04234
04235
04236
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248
04249
04250
04251
04252
04253
04254
04255
04256
04257
04258 static VALUE
04259 time_isdst(VALUE time)
04260 {
04261 struct time_object *tobj;
04262
04263 GetTimeval(time, tobj);
04264 MAKE_TM(time, tobj);
04265 return tobj->vtm.isdst ? Qtrue : Qfalse;
04266 }
04267
04268
04269
04270
04271
04272
04273
04274
04275
04276
04277
04278
04279
04280
04281 static VALUE
04282 time_zone(VALUE time)
04283 {
04284 struct time_object *tobj;
04285
04286 GetTimeval(time, tobj);
04287 MAKE_TM(time, tobj);
04288
04289 if (TIME_UTC_P(tobj)) {
04290 return rb_obj_untaint(rb_locale_str_new_cstr("UTC"));
04291 }
04292 if (tobj->vtm.zone == NULL)
04293 return Qnil;
04294 return rb_obj_untaint(rb_locale_str_new_cstr(tobj->vtm.zone));
04295 }
04296
04297
04298
04299
04300
04301
04302
04303
04304
04305
04306
04307
04308
04309
04310
04311
04312 static VALUE
04313 time_utc_offset(VALUE time)
04314 {
04315 struct time_object *tobj;
04316
04317 GetTimeval(time, tobj);
04318 MAKE_TM(time, tobj);
04319
04320 if (TIME_UTC_P(tobj)) {
04321 return INT2FIX(0);
04322 }
04323 else {
04324 return tobj->vtm.utc_offset;
04325 }
04326 }
04327
04328
04329
04330
04331
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345 static VALUE
04346 time_to_a(VALUE time)
04347 {
04348 struct time_object *tobj;
04349
04350 GetTimeval(time, tobj);
04351 MAKE_TM(time, tobj);
04352 return rb_ary_new3(10,
04353 INT2FIX(tobj->vtm.sec),
04354 INT2FIX(tobj->vtm.min),
04355 INT2FIX(tobj->vtm.hour),
04356 INT2FIX(tobj->vtm.mday),
04357 INT2FIX(tobj->vtm.mon),
04358 tobj->vtm.year,
04359 INT2FIX(tobj->vtm.wday),
04360 INT2FIX(tobj->vtm.yday),
04361 tobj->vtm.isdst?Qtrue:Qfalse,
04362 time_zone(time));
04363 }
04364
04365 #define SMALLBUF 100
04366 static size_t
04367 rb_strftime_alloc(char **buf, VALUE formatv, const char *format, rb_encoding *enc,
04368 struct vtm *vtm, wideval_t timew, int gmt)
04369 {
04370 size_t size, len, flen;
04371 VALUE timev = Qnil;
04372 struct timespec ts;
04373
04374 if (!timew2timespec_exact(timew, &ts))
04375 timev = w2v(rb_time_unmagnify(timew));
04376
04377 (*buf)[0] = '\0';
04378 flen = strlen(format);
04379 if (flen == 0) {
04380 return 0;
04381 }
04382 errno = 0;
04383 if (timev == Qnil)
04384 len = rb_strftime_timespec(*buf, SMALLBUF, format, enc, vtm, &ts, gmt);
04385 else
04386 len = rb_strftime(*buf, SMALLBUF, format, enc, vtm, timev, gmt);
04387 if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
04388 for (size=1024; ; size*=2) {
04389 *buf = xmalloc(size);
04390 (*buf)[0] = '\0';
04391 if (timev == Qnil)
04392 len = rb_strftime_timespec(*buf, size, format, enc, vtm, &ts, gmt);
04393 else
04394 len = rb_strftime(*buf, size, format, enc, vtm, timev, gmt);
04395
04396
04397
04398
04399
04400
04401
04402 if (len > 0) break;
04403 xfree(*buf);
04404 if (size >= 1024 * flen) {
04405 if (!NIL_P(formatv)) rb_sys_fail_str(formatv);
04406 rb_sys_fail(format);
04407 break;
04408 }
04409 }
04410 return len;
04411 }
04412
04413 static VALUE
04414 strftimev(const char *fmt, VALUE time, rb_encoding *enc)
04415 {
04416 struct time_object *tobj;
04417 char buffer[SMALLBUF], *buf = buffer;
04418 long len;
04419 VALUE str;
04420
04421 GetTimeval(time, tobj);
04422 MAKE_TM(time, tobj);
04423 len = rb_strftime_alloc(&buf, Qnil, fmt, enc, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04424 str = rb_enc_str_new(buf, len, enc);
04425 if (buf != buffer) xfree(buf);
04426 return str;
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
04564
04565
04566
04567
04568
04569
04570
04571
04572
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584
04585
04586
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601
04602
04603
04604
04605
04606
04607
04608
04609
04610
04611
04612
04613 static VALUE
04614 time_strftime(VALUE time, VALUE format)
04615 {
04616 struct time_object *tobj;
04617 char buffer[SMALLBUF], *buf = buffer;
04618 const char *fmt;
04619 long len;
04620 rb_encoding *enc;
04621 VALUE str;
04622
04623 GetTimeval(time, tobj);
04624 MAKE_TM(time, tobj);
04625 StringValue(format);
04626 if (!rb_enc_str_asciicompat_p(format)) {
04627 rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
04628 }
04629 format = rb_str_new4(format);
04630 fmt = RSTRING_PTR(format);
04631 len = RSTRING_LEN(format);
04632 enc = rb_enc_get(format);
04633 if (len == 0) {
04634 rb_warning("strftime called with empty format string");
04635 }
04636 else if (memchr(fmt, '\0', len)) {
04637
04638 const char *p = fmt, *pe = fmt + len;
04639
04640 str = rb_str_new(0, 0);
04641 while (p < pe) {
04642 len = rb_strftime_alloc(&buf, format, p, enc,
04643 &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04644 rb_str_cat(str, buf, len);
04645 p += strlen(p);
04646 if (buf != buffer) {
04647 xfree(buf);
04648 buf = buffer;
04649 }
04650 for (fmt = p; p < pe && !*p; ++p);
04651 if (p > fmt) rb_str_cat(str, fmt, p - fmt);
04652 }
04653 return str;
04654 }
04655 else {
04656 len = rb_strftime_alloc(&buf, format, RSTRING_PTR(format), enc,
04657 &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
04658 }
04659 str = rb_enc_str_new(buf, len, enc);
04660 if (buf != buffer) xfree(buf);
04661 return str;
04662 }
04663
04664
04665 static VALUE
04666 time_mdump(VALUE time)
04667 {
04668 struct time_object *tobj;
04669 unsigned long p, s;
04670 char buf[8];
04671 int i;
04672 VALUE str;
04673
04674 struct vtm vtm;
04675 long year;
04676 long usec, nsec;
04677 VALUE subsecx, nano, subnano, v;
04678
04679 GetTimeval(time, tobj);
04680
04681 gmtimew(tobj->timew, &vtm);
04682
04683 if (FIXNUM_P(vtm.year)) {
04684 year = FIX2LONG(vtm.year);
04685 if (year < 1900 || 1900+0xffff < year)
04686 rb_raise(rb_eArgError, "year too big to marshal: %ld UTC", year);
04687 }
04688 else {
04689 rb_raise(rb_eArgError, "year too big to marshal");
04690 }
04691
04692 subsecx = vtm.subsecx;
04693
04694 nano = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
04695 divmodv(nano, INT2FIX(1), &v, &subnano);
04696 nsec = FIX2LONG(v);
04697 usec = nsec / 1000;
04698 nsec = nsec % 1000;
04699
04700 nano = add(LONG2FIX(nsec), subnano);
04701
04702 p = 0x1UL << 31 |
04703 TIME_UTC_P(tobj) << 30 |
04704 (year-1900) << 14 |
04705 (vtm.mon-1) << 10 |
04706 vtm.mday << 5 |
04707 vtm.hour;
04708 s = vtm.min << 26 |
04709 vtm.sec << 20 |
04710 usec;
04711
04712 for (i=0; i<4; i++) {
04713 buf[i] = (unsigned char)p;
04714 p = RSHIFT(p, 8);
04715 }
04716 for (i=4; i<8; i++) {
04717 buf[i] = (unsigned char)s;
04718 s = RSHIFT(s, 8);
04719 }
04720
04721 str = rb_str_new(buf, 8);
04722 rb_copy_generic_ivar(str, time);
04723 if (!rb_equal(nano, INT2FIX(0))) {
04724 if (RB_TYPE_P(nano, T_RATIONAL)) {
04725 rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
04726 rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
04727 }
04728 else {
04729 rb_ivar_set(str, id_nano_num, nano);
04730 rb_ivar_set(str, id_nano_den, INT2FIX(1));
04731 }
04732 }
04733 if (nsec) {
04734
04735
04736
04737
04738
04739
04740
04741 char buf[2];
04742 int len = (int)sizeof(buf);
04743 buf[1] = (char)((nsec % 10) << 4);
04744 nsec /= 10;
04745 buf[0] = (char)(nsec % 10);
04746 nsec /= 10;
04747 buf[0] |= (char)((nsec % 10) << 4);
04748 if (buf[1] == 0)
04749 len = 1;
04750 rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
04751 }
04752 if (!TIME_UTC_P(tobj)) {
04753 VALUE off = time_utc_offset(time), div, mod;
04754 divmodv(off, INT2FIX(1), &div, &mod);
04755 if (rb_equal(mod, INT2FIX(0)))
04756 off = rb_Integer(div);
04757 rb_ivar_set(str, id_offset, off);
04758 }
04759 if (tobj->vtm.zone) {
04760 rb_ivar_set(str, id_zone, rb_locale_str_new_cstr(tobj->vtm.zone));
04761 }
04762 return str;
04763 }
04764
04765
04766 static VALUE
04767 time_dump(int argc, VALUE *argv, VALUE time)
04768 {
04769 VALUE str;
04770
04771 rb_scan_args(argc, argv, "01", 0);
04772 str = time_mdump(time);
04773
04774 return str;
04775 }
04776
04777
04778 static VALUE
04779 time_mload(VALUE time, VALUE str)
04780 {
04781 struct time_object *tobj;
04782 unsigned long p, s;
04783 time_t sec;
04784 long usec;
04785 unsigned char *buf;
04786 struct vtm vtm;
04787 int i, gmt;
04788 long nsec;
04789 VALUE submicro, nano_num, nano_den, offset, zone;
04790 wideval_t timew;
04791 st_data_t data;
04792
04793 time_modify(time);
04794
04795 #define get_attr(attr, iffound) \
04796 attr = rb_attr_get(str, id_##attr); \
04797 if (!NIL_P(attr)) { \
04798 data = id_##attr; \
04799 iffound; \
04800 st_delete(rb_generic_ivar_table(str), &data, 0); \
04801 }
04802
04803 get_attr(nano_num, {});
04804 get_attr(nano_den, {});
04805 get_attr(submicro, {});
04806 get_attr(offset, (offset = rb_rescue(validate_utc_offset, offset, NULL, Qnil)));
04807 get_attr(zone, (zone = rb_rescue(validate_zone_name, zone, NULL, Qnil)));
04808
04809 #undef get_attr
04810
04811 rb_copy_generic_ivar(time, str);
04812
04813 StringValue(str);
04814 buf = (unsigned char *)RSTRING_PTR(str);
04815 if (RSTRING_LEN(str) != 8) {
04816 rb_raise(rb_eTypeError, "marshaled time format differ");
04817 }
04818
04819 p = s = 0;
04820 for (i=0; i<4; i++) {
04821 p |= buf[i]<<(8*i);
04822 }
04823 for (i=4; i<8; i++) {
04824 s |= buf[i]<<(8*(i-4));
04825 }
04826
04827 if ((p & (1UL<<31)) == 0) {
04828 gmt = 0;
04829 offset = Qnil;
04830 sec = p;
04831 usec = s;
04832 nsec = usec * 1000;
04833 timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
04834 }
04835 else {
04836 p &= ~(1UL<<31);
04837 gmt = (int)((p >> 30) & 0x1);
04838
04839 vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
04840 vtm.mon = ((int)(p >> 10) & 0xf) + 1;
04841 vtm.mday = (int)(p >> 5) & 0x1f;
04842 vtm.hour = (int) p & 0x1f;
04843 vtm.min = (int)(s >> 26) & 0x3f;
04844 vtm.sec = (int)(s >> 20) & 0x3f;
04845 vtm.utc_offset = INT2FIX(0);
04846 vtm.yday = vtm.wday = 0;
04847 vtm.isdst = 0;
04848 vtm.zone = "";
04849
04850 usec = (long)(s & 0xfffff);
04851 nsec = usec * 1000;
04852
04853
04854 vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
04855 if (nano_num != Qnil) {
04856 VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
04857 vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
04858 }
04859 else if (submicro != Qnil) {
04860 unsigned char *ptr;
04861 long len;
04862 int digit;
04863 ptr = (unsigned char*)StringValuePtr(submicro);
04864 len = RSTRING_LEN(submicro);
04865 nsec = 0;
04866 if (0 < len) {
04867 if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
04868 nsec += digit * 100;
04869 if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
04870 nsec += digit * 10;
04871 }
04872 if (1 < len) {
04873 if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
04874 nsec += digit;
04875 }
04876 vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
04877 end_submicro: ;
04878 }
04879 timew = timegmw(&vtm);
04880 }
04881
04882 GetNewTimeval(time, tobj);
04883 tobj->gmt = 0;
04884 tobj->tm_got = 0;
04885 tobj->timew = timew;
04886 if (gmt) {
04887 TIME_SET_UTC(tobj);
04888 }
04889 else if (!NIL_P(offset)) {
04890 time_set_utc_offset(time, offset);
04891 time_fixoff(time);
04892 }
04893 if (!NIL_P(zone)) {
04894 zone = rb_str_new_frozen(zone);
04895 tobj->vtm.zone = RSTRING_PTR(zone);
04896 rb_ivar_set(time, id_zone, zone);
04897 }
04898
04899 return time;
04900 }
04901
04902
04903 static VALUE
04904 time_load(VALUE klass, VALUE str)
04905 {
04906 VALUE time = time_s_alloc(klass);
04907
04908 time_mload(time, str);
04909 return time;
04910 }
04911
04912
04913
04914
04915
04916
04917
04918
04919
04920
04921
04922
04923
04924
04925
04926
04927
04928
04929
04930
04931
04932
04933
04934
04935
04936
04937
04938
04939
04940
04941
04942
04943
04944
04945
04946
04947
04948
04949
04950
04951
04952
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964
04965
04966
04967
04968
04969
04970
04971
04972
04973
04974
04975
04976
04977
04978
04979
04980
04981
04982
04983
04984
04985
04986
04987
04988
04989
04990
04991
04992
04993
04994
04995
04996
04997
04998
04999
05000 void
05001 Init_Time(void)
05002 {
05003 #undef rb_intern
05004 #define rb_intern(str) rb_intern_const(str)
05005
05006 id_eq = rb_intern("==");
05007 id_ne = rb_intern("!=");
05008 id_quo = rb_intern("quo");
05009 id_div = rb_intern("div");
05010 id_cmp = rb_intern("<=>");
05011 id_lshift = rb_intern("<<");
05012 id_divmod = rb_intern("divmod");
05013 id_mul = rb_intern("*");
05014 id_submicro = rb_intern("submicro");
05015 id_nano_num = rb_intern("nano_num");
05016 id_nano_den = rb_intern("nano_den");
05017 id_offset = rb_intern("offset");
05018 id_zone = rb_intern("zone");
05019
05020 rb_cTime = rb_define_class("Time", rb_cObject);
05021 rb_include_module(rb_cTime, rb_mComparable);
05022
05023 rb_define_alloc_func(rb_cTime, time_s_alloc);
05024 rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
05025 rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
05026 rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
05027 rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
05028 rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
05029 rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
05030
05031 rb_define_method(rb_cTime, "to_i", time_to_i, 0);
05032 rb_define_method(rb_cTime, "to_f", time_to_f, 0);
05033 rb_define_method(rb_cTime, "to_r", time_to_r, 0);
05034 rb_define_method(rb_cTime, "<=>", time_cmp, 1);
05035 rb_define_method(rb_cTime, "eql?", time_eql, 1);
05036 rb_define_method(rb_cTime, "hash", time_hash, 0);
05037 rb_define_method(rb_cTime, "initialize", time_init, -1);
05038 rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1);
05039
05040 rb_define_method(rb_cTime, "localtime", time_localtime_m, -1);
05041 rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
05042 rb_define_method(rb_cTime, "utc", time_gmtime, 0);
05043 rb_define_method(rb_cTime, "getlocal", time_getlocaltime, -1);
05044 rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
05045 rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
05046
05047 rb_define_method(rb_cTime, "ctime", time_asctime, 0);
05048 rb_define_method(rb_cTime, "asctime", time_asctime, 0);
05049 rb_define_method(rb_cTime, "to_s", time_to_s, 0);
05050 rb_define_method(rb_cTime, "inspect", time_to_s, 0);
05051 rb_define_method(rb_cTime, "to_a", time_to_a, 0);
05052
05053 rb_define_method(rb_cTime, "+", time_plus, 1);
05054 rb_define_method(rb_cTime, "-", time_minus, 1);
05055
05056 rb_define_method(rb_cTime, "succ", time_succ, 0);
05057 rb_define_method(rb_cTime, "round", time_round, -1);
05058
05059 rb_define_method(rb_cTime, "sec", time_sec, 0);
05060 rb_define_method(rb_cTime, "min", time_min, 0);
05061 rb_define_method(rb_cTime, "hour", time_hour, 0);
05062 rb_define_method(rb_cTime, "mday", time_mday, 0);
05063 rb_define_method(rb_cTime, "day", time_mday, 0);
05064 rb_define_method(rb_cTime, "mon", time_mon, 0);
05065 rb_define_method(rb_cTime, "month", time_mon, 0);
05066 rb_define_method(rb_cTime, "year", time_year, 0);
05067 rb_define_method(rb_cTime, "wday", time_wday, 0);
05068 rb_define_method(rb_cTime, "yday", time_yday, 0);
05069 rb_define_method(rb_cTime, "isdst", time_isdst, 0);
05070 rb_define_method(rb_cTime, "dst?", time_isdst, 0);
05071 rb_define_method(rb_cTime, "zone", time_zone, 0);
05072 rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
05073 rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
05074 rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
05075
05076 rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
05077 rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
05078
05079 rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
05080 rb_define_method(rb_cTime, "monday?", time_monday, 0);
05081 rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
05082 rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
05083 rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
05084 rb_define_method(rb_cTime, "friday?", time_friday, 0);
05085 rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
05086
05087 rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
05088 rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
05089 rb_define_method(rb_cTime, "usec", time_usec, 0);
05090 rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
05091 rb_define_method(rb_cTime, "nsec", time_nsec, 0);
05092 rb_define_method(rb_cTime, "subsec", time_subsec, 0);
05093
05094 rb_define_method(rb_cTime, "strftime", time_strftime, 1);
05095
05096
05097 rb_define_private_method(rb_cTime, "_dump", time_dump, -1);
05098 rb_define_private_method(rb_singleton_class(rb_cTime), "_load", time_load, 1);
05099 #if 0
05100
05101 rb_define_private_method(rb_cTime, "marshal_dump", time_mdump, 0);
05102 rb_define_private_method(rb_cTime, "marshal_load", time_mload, 1);
05103 #endif
05104
05105 #ifdef DEBUG_FIND_TIME_NUMGUESS
05106 rb_define_virtual_variable("$find_time_numguess", find_time_numguess_getter, NULL);
05107 #endif
05108 }
05109