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