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