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