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