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