Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# time.c

Go to the documentation of this file.

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