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