time.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7