• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

time.c

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

Generated on Thu Sep 8 2011 03:50:48 for Ruby by  doxygen 1.7.1