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