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