Ruby  2.0.0p481(2014-05-08revision45883)
ext/date/date_core.c
Go to the documentation of this file.
00001 /*
00002   date_core.c: Coded by Tadayoshi Funaba 2010-2013
00003 */
00004 
00005 #include "ruby.h"
00006 #include "ruby/encoding.h"
00007 #include <math.h>
00008 #include <time.h>
00009 
00010 #define NDEBUG
00011 #include <assert.h>
00012 
00013 #ifdef RUBY_EXTCONF_H
00014 #include RUBY_EXTCONF_H
00015 #endif
00016 
00017 #define USE_PACK
00018 
00019 static ID id_cmp, id_le_p, id_ge_p, id_eqeq_p;
00020 static VALUE cDate, cDateTime;
00021 static VALUE half_days_in_day, day_in_nanoseconds;
00022 static double positive_inf, negative_inf;
00023 
00024 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
00025 
00026 #define f_abs(x) rb_funcall(x, rb_intern("abs"), 0)
00027 #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
00028 #define f_add(x,y) rb_funcall(x, '+', 1, y)
00029 #define f_sub(x,y) rb_funcall(x, '-', 1, y)
00030 #define f_mul(x,y) rb_funcall(x, '*', 1, y)
00031 #define f_div(x,y) rb_funcall(x, '/', 1, y)
00032 #define f_quo(x,y) rb_funcall(x, rb_intern("quo"), 1, y)
00033 #define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
00034 #define f_mod(x,y) rb_funcall(x, '%', 1, y)
00035 #define f_remainder(x,y) rb_funcall(x, rb_intern("remainder"), 1, y)
00036 #define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
00037 #define f_floor(x) rb_funcall(x, rb_intern("floor"), 0)
00038 #define f_ceil(x) rb_funcall(x, rb_intern("ceil"), 0)
00039 #define f_truncate(x) rb_funcall(x, rb_intern("truncate"), 0)
00040 #define f_round(x) rb_funcall(x, rb_intern("round"), 0)
00041 
00042 #define f_to_i(x) rb_funcall(x, rb_intern("to_i"), 0)
00043 #define f_to_r(x) rb_funcall(x, rb_intern("to_r"), 0)
00044 #define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0)
00045 #define f_inspect(x) rb_funcall(x, rb_intern("inspect"), 0)
00046 
00047 #define f_add3(x,y,z) f_add(f_add(x, y), z)
00048 #define f_sub3(x,y,z) f_sub(f_sub(x, y), z)
00049 
00050 inline static VALUE
00051 f_cmp(VALUE x, VALUE y)
00052 {
00053     if (FIXNUM_P(x) && FIXNUM_P(y)) {
00054         long c = FIX2LONG(x) - FIX2LONG(y);
00055         if (c > 0)
00056             c = 1;
00057         else if (c < 0)
00058             c = -1;
00059         return INT2FIX(c);
00060     }
00061     return rb_funcall(x, id_cmp, 1, y);
00062 }
00063 
00064 inline static VALUE
00065 f_lt_p(VALUE x, VALUE y)
00066 {
00067     if (FIXNUM_P(x) && FIXNUM_P(y))
00068         return f_boolcast(FIX2LONG(x) < FIX2LONG(y));
00069     return rb_funcall(x, '<', 1, y);
00070 }
00071 
00072 inline static VALUE
00073 f_gt_p(VALUE x, VALUE y)
00074 {
00075     if (FIXNUM_P(x) && FIXNUM_P(y))
00076         return f_boolcast(FIX2LONG(x) > FIX2LONG(y));
00077     return rb_funcall(x, '>', 1, y);
00078 }
00079 
00080 inline static VALUE
00081 f_le_p(VALUE x, VALUE y)
00082 {
00083     if (FIXNUM_P(x) && FIXNUM_P(y))
00084         return f_boolcast(FIX2LONG(x) <= FIX2LONG(y));
00085     return rb_funcall(x, id_le_p, 1, y);
00086 }
00087 
00088 inline static VALUE
00089 f_ge_p(VALUE x, VALUE y)
00090 {
00091     if (FIXNUM_P(x) && FIXNUM_P(y))
00092         return f_boolcast(FIX2LONG(x) >= FIX2LONG(y));
00093     return rb_funcall(x, rb_intern(">="), 1, y);
00094 }
00095 
00096 inline static VALUE
00097 f_eqeq_p(VALUE x, VALUE y)
00098 {
00099     if (FIXNUM_P(x) && FIXNUM_P(y))
00100         return f_boolcast(FIX2LONG(x) == FIX2LONG(y));
00101     return rb_funcall(x, rb_intern("=="), 1, y);
00102 }
00103 
00104 inline static VALUE
00105 f_zero_p(VALUE x)
00106 {
00107     switch (TYPE(x)) {
00108       case T_FIXNUM:
00109         return f_boolcast(FIX2LONG(x) == 0);
00110       case T_BIGNUM:
00111         return Qfalse;
00112       case T_RATIONAL:
00113         {
00114             VALUE num = RRATIONAL(x)->num;
00115             return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0);
00116         }
00117     }
00118     return rb_funcall(x, id_eqeq_p, 1, INT2FIX(0));
00119 }
00120 
00121 #define f_nonzero_p(x) (!f_zero_p(x))
00122 
00123 inline static VALUE
00124 f_negative_p(VALUE x)
00125 {
00126     if (FIXNUM_P(x))
00127         return f_boolcast(FIX2LONG(x) < 0);
00128     return rb_funcall(x, '<', 1, INT2FIX(0));
00129 }
00130 
00131 #define f_positive_p(x) (!f_negative_p(x))
00132 
00133 #define f_ajd(x) rb_funcall(x, rb_intern("ajd"), 0)
00134 #define f_jd(x) rb_funcall(x, rb_intern("jd"), 0)
00135 #define f_year(x) rb_funcall(x, rb_intern("year"), 0)
00136 #define f_mon(x) rb_funcall(x, rb_intern("mon"), 0)
00137 #define f_mday(x) rb_funcall(x, rb_intern("mday"), 0)
00138 #define f_wday(x) rb_funcall(x, rb_intern("wday"), 0)
00139 #define f_hour(x) rb_funcall(x, rb_intern("hour"), 0)
00140 #define f_min(x) rb_funcall(x, rb_intern("min"), 0)
00141 #define f_sec(x) rb_funcall(x, rb_intern("sec"), 0)
00142 
00143 /* copied from time.c */
00144 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
00145 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
00146 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
00147 #define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
00148 
00149 #define HAVE_JD     (1 << 0)
00150 #define HAVE_DF     (1 << 1)
00151 #define HAVE_CIVIL  (1 << 2)
00152 #define HAVE_TIME   (1 << 3)
00153 #define COMPLEX_DAT (1 << 7)
00154 
00155 #define have_jd_p(x) ((x)->flags & HAVE_JD)
00156 #define have_df_p(x) ((x)->flags & HAVE_DF)
00157 #define have_civil_p(x) ((x)->flags & HAVE_CIVIL)
00158 #define have_time_p(x) ((x)->flags & HAVE_TIME)
00159 #define complex_dat_p(x) ((x)->flags & COMPLEX_DAT)
00160 #define simple_dat_p(x) (!complex_dat_p(x))
00161 
00162 #define ITALY 2299161 /* 1582-10-15 */
00163 #define ENGLAND 2361222 /* 1752-09-14 */
00164 #define JULIAN positive_inf
00165 #define GREGORIAN negative_inf
00166 #define DEFAULT_SG ITALY
00167 
00168 #define UNIX_EPOCH_IN_CJD INT2FIX(2440588) /* 1970-01-01 */
00169 
00170 #define MINUTE_IN_SECONDS 60
00171 #define HOUR_IN_SECONDS 3600
00172 #define DAY_IN_SECONDS 86400
00173 #define SECOND_IN_MILLISECONDS 1000
00174 #define SECOND_IN_NANOSECONDS 1000000000
00175 
00176 #define JC_PERIOD0 1461         /* 365.25 * 4 */
00177 #define GC_PERIOD0 146097       /* 365.2425 * 400 */
00178 #define CM_PERIOD0 71149239     /* (lcm 7 1461 146097) */
00179 #define CM_PERIOD (0xfffffff / CM_PERIOD0 * CM_PERIOD0)
00180 #define CM_PERIOD_JCY (CM_PERIOD / JC_PERIOD0 * 4)
00181 #define CM_PERIOD_GCY (CM_PERIOD / GC_PERIOD0 * 400)
00182 
00183 #define REFORM_BEGIN_YEAR 1582
00184 #define REFORM_END_YEAR   1930
00185 #define REFORM_BEGIN_JD 2298874 /* ns 1582-01-01 */
00186 #define REFORM_END_JD   2426355 /* os 1930-12-31 */
00187 
00188 #ifdef USE_PACK
00189 #define SEC_WIDTH  6
00190 #define MIN_WIDTH  6
00191 #define HOUR_WIDTH 5
00192 #define MDAY_WIDTH 5
00193 #define MON_WIDTH  4
00194 
00195 #define SEC_SHIFT  0
00196 #define MIN_SHIFT  SEC_WIDTH
00197 #define HOUR_SHIFT (MIN_WIDTH + SEC_WIDTH)
00198 #define MDAY_SHIFT (HOUR_WIDTH + MIN_WIDTH + SEC_WIDTH)
00199 #define MON_SHIFT  (MDAY_WIDTH + HOUR_WIDTH + MIN_WIDTH + SEC_WIDTH)
00200 
00201 #define PK_MASK(x) ((1 << (x)) - 1)
00202 
00203 #define EX_SEC(x)  (((x) >> SEC_SHIFT)  & PK_MASK(SEC_WIDTH))
00204 #define EX_MIN(x)  (((x) >> MIN_SHIFT)  & PK_MASK(MIN_WIDTH))
00205 #define EX_HOUR(x) (((x) >> HOUR_SHIFT) & PK_MASK(HOUR_WIDTH))
00206 #define EX_MDAY(x) (((x) >> MDAY_SHIFT) & PK_MASK(MDAY_WIDTH))
00207 #define EX_MON(x)  (((x) >> MON_SHIFT)  & PK_MASK(MON_WIDTH))
00208 
00209 #define PACK5(m,d,h,min,s) \
00210     (((m) << MON_SHIFT) | ((d) << MDAY_SHIFT) |\
00211      ((h) << HOUR_SHIFT) | ((min) << MIN_SHIFT) | ((s) << SEC_SHIFT))
00212 
00213 #define PACK2(m,d) \
00214     (((m) << MON_SHIFT) | ((d) << MDAY_SHIFT))
00215 #endif
00216 
00217 #ifdef HAVE_FLOAT_H
00218 #include <float.h>
00219 #endif
00220 
00221 #if defined(FLT_RADIX) && defined(FLT_MANT_DIG) && FLT_RADIX == 2 && FLT_MANT_DIG > 22
00222 #define date_sg_t float
00223 #else
00224 #define date_sg_t double
00225 #endif
00226 
00227 /* A set of nth, jd, df and sf denote ajd + 1/2.  Each ajd begin at
00228  * noon of GMT (assume equal to UTC).  However, this begins at
00229  * midnight.
00230  */
00231 
00232 struct SimpleDateData
00233 {
00234     unsigned flags;
00235     VALUE nth;  /* not always canonicalized */
00236     int jd;     /* as utc */
00237     /* df is zero */
00238     /* sf is zero */
00239     /* of is zero */
00240     date_sg_t sg;  /* 2298874..2426355 or -/+oo -- at most 22 bits */
00241     /* decoded as utc=local */
00242     int year;   /* truncated */
00243 #ifndef USE_PACK
00244     int mon;
00245     int mday;
00246     /* hour is zero */
00247     /* min is zero */
00248     /* sec is zero */
00249 #else
00250     /* packed civil */
00251     unsigned pc;
00252 #endif
00253 };
00254 
00255 struct ComplexDateData
00256 {
00257     unsigned flags;
00258     VALUE nth;  /* not always canonicalized */
00259     int jd;     /* as utc */
00260     int df;     /* as utc, in secs */
00261     VALUE sf;   /* in nano secs */
00262     int of;     /* in secs */
00263     date_sg_t sg;  /* 2298874..2426355 or -/+oo -- at most 22 bits */
00264     /* decoded as local */
00265     int year;   /* truncated */
00266 #ifndef USE_PACK
00267     int mon;
00268     int mday;
00269     int hour;
00270     int min;
00271     int sec;
00272 #else
00273     /* packed civil */
00274     unsigned pc;
00275 #endif
00276 };
00277 
00278 union DateData {
00279     unsigned flags;
00280     struct SimpleDateData s;
00281     struct ComplexDateData c;
00282 };
00283 
00284 #define get_d1(x)\
00285     union DateData *dat;\
00286     Data_Get_Struct(x, union DateData, dat);
00287 
00288 #define get_d1a(x)\
00289     union DateData *adat;\
00290     Data_Get_Struct(x, union DateData, adat);
00291 
00292 #define get_d1b(x)\
00293     union DateData *bdat;\
00294     Data_Get_Struct(x, union DateData, bdat);
00295 
00296 #define get_d2(x,y)\
00297     union DateData *adat, *bdat;\
00298     Data_Get_Struct(x, union DateData, adat);\
00299     Data_Get_Struct(y, union DateData, bdat);
00300 
00301 inline static VALUE
00302 canon(VALUE x)
00303 {
00304     if (TYPE(x) == T_RATIONAL) {
00305         VALUE den = RRATIONAL(x)->den;
00306         if (FIXNUM_P(den) && FIX2LONG(den) == 1)
00307             return RRATIONAL(x)->num;
00308     }
00309     return x;
00310 }
00311 
00312 #ifndef USE_PACK
00313 #define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \
00314 {\
00315     (x)->nth = canon(_nth);\
00316     (x)->jd = _jd;\
00317     (x)->sg = (date_sg_t)(_sg);\
00318     (x)->year = _year;\
00319     (x)->mon = _mon;\
00320     (x)->mday = _mday;\
00321     (x)->flags = _flags;\
00322 }
00323 #else
00324 #define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \
00325 {\
00326     (x)->nth = canon(_nth);\
00327     (x)->jd = _jd;\
00328     (x)->sg = (date_sg_t)(_sg);\
00329     (x)->year = _year;\
00330     (x)->pc = PACK2(_mon, _mday);\
00331     (x)->flags = _flags;\
00332 }
00333 #endif
00334 
00335 #ifndef USE_PACK
00336 #define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\
00337 _year, _mon, _mday, _hour, _min, _sec, _flags) \
00338 {\
00339     (x)->nth = canon(_nth);\
00340     (x)->jd = _jd;\
00341     (x)->df = _df;\
00342     (x)->sf = canon(_sf);\
00343     (x)->of = _of;\
00344     (x)->sg = (date_sg_t)(_sg);\
00345     (x)->year = _year;\
00346     (x)->mon = _mon;\
00347     (x)->mday = _mday;\
00348     (x)->hour = _hour;\
00349     (x)->min = _min;\
00350     (x)->sec = _sec;\
00351     (x)->flags = _flags;\
00352 }
00353 #else
00354 #define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\
00355 _year, _mon, _mday, _hour, _min, _sec, _flags) \
00356 {\
00357     (x)->nth = canon(_nth);\
00358     (x)->jd = _jd;\
00359     (x)->df = _df;\
00360     (x)->sf = canon(_sf);\
00361     (x)->of = _of;\
00362     (x)->sg = (date_sg_t)(_sg);\
00363     (x)->year = _year;\
00364     (x)->pc = PACK5(_mon, _mday, _hour, _min, _sec);\
00365     (x)->flags = _flags;\
00366 }
00367 #endif
00368 
00369 #ifndef USE_PACK
00370 #define copy_simple_to_complex(x, y) \
00371 {\
00372     (x)->nth = (y)->nth;\
00373     (x)->jd = (y)->jd;\
00374     (x)->df = 0;\
00375     (x)->sf = INT2FIX(0);\
00376     (x)->of = 0;\
00377     (x)->sg = (date_sg_t)((y)->sg);\
00378     (x)->year = (y)->year;\
00379     (x)->mon = (y)->mon;\
00380     (x)->mday = (y)->mday;\
00381     (x)->hour = 0;\
00382     (x)->min = 0;\
00383     (x)->sec = 0;\
00384     (x)->flags = (y)->flags;\
00385 }
00386 #else
00387 #define copy_simple_to_complex(x, y) \
00388 {\
00389     (x)->nth = (y)->nth;\
00390     (x)->jd = (y)->jd;\
00391     (x)->df = 0;\
00392     (x)->sf = INT2FIX(0);\
00393     (x)->of = 0;\
00394     (x)->sg = (date_sg_t)((y)->sg);\
00395     (x)->year = (y)->year;\
00396     (x)->pc = PACK5(EX_MON((y)->pc), EX_MDAY((y)->pc), 0, 0, 0);\
00397     (x)->flags = (y)->flags;\
00398 }
00399 #endif
00400 
00401 #ifndef USE_PACK
00402 #define copy_complex_to_simple(x, y) \
00403 {\
00404     (x)->nth = (y)->nth;\
00405     (x)->jd = (y)->jd;\
00406     (x)->sg = (date_sg_t)((y)->sg);\
00407     (x)->year = (y)->year;\
00408     (x)->mon = (y)->mon;\
00409     (x)->mday = (y)->mday;\
00410     (x)->flags = (y)->flags;\
00411 }
00412 #else
00413 #define copy_complex_to_simple(x, y) \
00414 {\
00415     (x)->nth = (y)->nth;\
00416     (x)->jd = (y)->jd;\
00417     (x)->sg = (date_sg_t)((y)->sg);\
00418     (x)->year = (y)->year;\
00419     (x)->pc = PACK2(EX_MON((y)->pc), EX_MDAY((y)->pc));\
00420     (x)->flags = (y)->flags;\
00421 }
00422 #endif
00423 
00424 /* base */
00425 
00426 static int c_valid_civil_p(int, int, int, double,
00427                            int *, int *, int *, int *);
00428 
00429 static int
00430 c_find_fdoy(int y, double sg, int *rjd, int *ns)
00431 {
00432     int d, rm, rd;
00433 
00434     for (d = 1; d < 31; d++)
00435         if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns))
00436             return 1;
00437     return 0;
00438 }
00439 
00440 static int
00441 c_find_ldoy(int y, double sg, int *rjd, int *ns)
00442 {
00443     int i, rm, rd;
00444 
00445     for (i = 0; i < 30; i++)
00446         if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns))
00447             return 1;
00448     return 0;
00449 }
00450 
00451 #ifndef NDEBUG
00452 static int
00453 c_find_fdom(int y, int m, double sg, int *rjd, int *ns)
00454 {
00455     int d, rm, rd;
00456 
00457     for (d = 1; d < 31; d++)
00458         if (c_valid_civil_p(y, m, d, sg, &rm, &rd, rjd, ns))
00459             return 1;
00460     return 0;
00461 }
00462 #endif
00463 
00464 static int
00465 c_find_ldom(int y, int m, double sg, int *rjd, int *ns)
00466 {
00467     int i, rm, rd;
00468 
00469     for (i = 0; i < 30; i++)
00470         if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns))
00471             return 1;
00472     return 0;
00473 }
00474 
00475 static void
00476 c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns)
00477 {
00478     double a, b, jd;
00479 
00480     if (m <= 2) {
00481         y -= 1;
00482         m += 12;
00483     }
00484     a = floor(y / 100.0);
00485     b = 2 - a + floor(a / 4.0);
00486     jd = floor(365.25 * (y + 4716)) +
00487         floor(30.6001 * (m + 1)) +
00488         d + b - 1524;
00489     if (jd < sg) {
00490         jd -= b;
00491         *ns = 0;
00492     }
00493     else
00494         *ns = 1;
00495 
00496     *rjd = (int)jd;
00497 }
00498 
00499 static void
00500 c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom)
00501 {
00502     double x, a, b, c, d, e, y, m, dom;
00503 
00504     if (jd < sg)
00505         a = jd;
00506     else {
00507         x = floor((jd - 1867216.25) / 36524.25);
00508         a = jd + 1 + x - floor(x / 4.0);
00509     }
00510     b = a + 1524;
00511     c = floor((b - 122.1) / 365.25);
00512     d = floor(365.25 * c);
00513     e = floor((b - d) / 30.6001);
00514     dom = b - d - floor(30.6001 * e);
00515     if (e <= 13) {
00516         m = e - 1;
00517         y = c - 4716;
00518     }
00519     else {
00520         m = e - 13;
00521         y = c - 4715;
00522     }
00523 
00524     *ry = (int)y;
00525     *rm = (int)m;
00526     *rdom = (int)dom;
00527 }
00528 
00529 static void
00530 c_ordinal_to_jd(int y, int d, double sg, int *rjd, int *ns)
00531 {
00532     int ns2;
00533 
00534     c_find_fdoy(y, sg, rjd, &ns2);
00535     *rjd += d - 1;
00536     *ns = (*rjd < sg) ? 0 : 1;
00537 }
00538 
00539 static void
00540 c_jd_to_ordinal(int jd, double sg, int *ry, int *rd)
00541 {
00542     int rm2, rd2, rjd, ns;
00543 
00544     c_jd_to_civil(jd, sg, ry, &rm2, &rd2);
00545     c_find_fdoy(*ry, sg, &rjd, &ns);
00546     *rd = (jd - rjd) + 1;
00547 }
00548 
00549 static void
00550 c_commercial_to_jd(int y, int w, int d, double sg, int *rjd, int *ns)
00551 {
00552     int rjd2, ns2;
00553 
00554     c_find_fdoy(y, sg, &rjd2, &ns2);
00555     rjd2 += 3;
00556     *rjd =
00557         (rjd2 - MOD((rjd2 - 1) + 1, 7)) +
00558         7 * (w - 1) +
00559         (d - 1);
00560     *ns = (*rjd < sg) ? 0 : 1;
00561 }
00562 
00563 static void
00564 c_jd_to_commercial(int jd, double sg, int *ry, int *rw, int *rd)
00565 {
00566     int ry2, rm2, rd2, a, rjd2, ns2;
00567 
00568     c_jd_to_civil(jd - 3, sg, &ry2, &rm2, &rd2);
00569     a = ry2;
00570     c_commercial_to_jd(a + 1, 1, 1, sg, &rjd2, &ns2);
00571     if (jd >= rjd2)
00572         *ry = a + 1;
00573     else {
00574         c_commercial_to_jd(a, 1, 1, sg, &rjd2, &ns2);
00575         *ry = a;
00576     }
00577     *rw = 1 + DIV(jd - rjd2, 7);
00578     *rd = MOD(jd + 1, 7);
00579     if (*rd == 0)
00580         *rd = 7;
00581 }
00582 
00583 static void
00584 c_weeknum_to_jd(int y, int w, int d, int f, double sg, int *rjd, int *ns)
00585 {
00586     int rjd2, ns2;
00587 
00588     c_find_fdoy(y, sg, &rjd2, &ns2);
00589     rjd2 += 6;
00590     *rjd = (rjd2 - MOD(((rjd2 - f) + 1), 7) - 7) + 7 * w + d;
00591     *ns = (*rjd < sg) ? 0 : 1;
00592 }
00593 
00594 static void
00595 c_jd_to_weeknum(int jd, int f, double sg, int *ry, int *rw, int *rd)
00596 {
00597     int rm, rd2, rjd, ns, j;
00598 
00599     c_jd_to_civil(jd, sg, ry, &rm, &rd2);
00600     c_find_fdoy(*ry, sg, &rjd, &ns);
00601     rjd += 6;
00602     j = jd - (rjd - MOD((rjd - f) + 1, 7)) + 7;
00603     *rw = (int)DIV(j, 7);
00604     *rd = (int)MOD(j, 7);
00605 }
00606 
00607 #ifndef NDEBUG
00608 static void
00609 c_nth_kday_to_jd(int y, int m, int n, int k, double sg, int *rjd, int *ns)
00610 {
00611     int rjd2, ns2;
00612 
00613     if (n > 0) {
00614         c_find_fdom(y, m, sg, &rjd2, &ns2);
00615         rjd2 -= 1;
00616     }
00617     else {
00618         c_find_ldom(y, m, sg, &rjd2, &ns2);
00619         rjd2 += 7;
00620     }
00621     *rjd = (rjd2 - MOD((rjd2 - k) + 1, 7)) + 7 * n;
00622     *ns = (*rjd < sg) ? 0 : 1;
00623 }
00624 #endif
00625 
00626 inline static int
00627 c_jd_to_wday(int jd)
00628 {
00629     return MOD(jd + 1, 7);
00630 }
00631 
00632 #ifndef NDEBUG
00633 static void
00634 c_jd_to_nth_kday(int jd, double sg, int *ry, int *rm, int *rn, int *rk)
00635 {
00636     int rd, rjd, ns2;
00637 
00638     c_jd_to_civil(jd, sg, ry, rm, &rd);
00639     c_find_fdom(*ry, *rm, sg, &rjd, &ns2);
00640     *rn = DIV(jd - rjd, 7) + 1;
00641     *rk = c_jd_to_wday(jd);
00642 }
00643 #endif
00644 
00645 static int
00646 c_valid_ordinal_p(int y, int d, double sg,
00647                   int *rd, int *rjd, int *ns)
00648 {
00649     int ry2, rd2;
00650 
00651     if (d < 0) {
00652         int rjd2, ns2;
00653 
00654         if (!c_find_ldoy(y, sg, &rjd2, &ns2))
00655             return 0;
00656         c_jd_to_ordinal(rjd2 + d + 1, sg, &ry2, &rd2);
00657         if (ry2 != y)
00658             return 0;
00659         d = rd2;
00660     }
00661     c_ordinal_to_jd(y, d, sg, rjd, ns);
00662     c_jd_to_ordinal(*rjd, sg, &ry2, &rd2);
00663     if (ry2 != y || rd2 != d)
00664         return 0;
00665     return 1;
00666 }
00667 
00668 static const int monthtab[2][13] = {
00669     { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
00670     { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
00671 };
00672 
00673 inline static int
00674 c_julian_leap_p(int y)
00675 {
00676     return MOD(y, 4) == 0;
00677 }
00678 
00679 inline static int
00680 c_gregorian_leap_p(int y)
00681 {
00682     return MOD(y, 4) == 0 && y % 100 != 0 || MOD(y, 400) == 0;
00683 }
00684 
00685 static int
00686 c_julian_last_day_of_month(int y, int m)
00687 {
00688     assert(m >= 1 && m <= 12);
00689     return monthtab[c_julian_leap_p(y) ? 1 : 0][m];
00690 }
00691 
00692 static int
00693 c_gregorian_last_day_of_month(int y, int m)
00694 {
00695     assert(m >= 1 && m <= 12);
00696     return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m];
00697 }
00698 
00699 static int
00700 c_valid_julian_p(int y, int m, int d, int *rm, int *rd)
00701 {
00702     int last;
00703 
00704     if (m < 0)
00705         m += 13;
00706     if (m < 1 || m > 12)
00707         return 0;
00708     last = c_julian_last_day_of_month(y, m);
00709     if (d < 0)
00710         d = last + d + 1;
00711     if (d < 1 || d > last)
00712         return 0;
00713     *rm = m;
00714     *rd = d;
00715     return 1;
00716 }
00717 
00718 static int
00719 c_valid_gregorian_p(int y, int m, int d, int *rm, int *rd)
00720 {
00721     int last;
00722 
00723     if (m < 0)
00724         m += 13;
00725     if (m < 1 || m > 12)
00726         return 0;
00727     last = c_gregorian_last_day_of_month(y, m);
00728     if (d < 0)
00729         d = last + d + 1;
00730     if (d < 1 || d > last)
00731         return 0;
00732     *rm = m;
00733     *rd = d;
00734     return 1;
00735 }
00736 
00737 static int
00738 c_valid_civil_p(int y, int m, int d, double sg,
00739                 int *rm, int *rd, int *rjd, int *ns)
00740 {
00741     int ry;
00742 
00743     if (m < 0)
00744         m += 13;
00745     if (d < 0) {
00746         if (!c_find_ldom(y, m, sg, rjd, ns))
00747             return 0;
00748         c_jd_to_civil(*rjd + d + 1, sg, &ry, rm, rd);
00749         if (ry != y || *rm != m)
00750             return 0;
00751         d = *rd;
00752     }
00753     c_civil_to_jd(y, m, d, sg, rjd, ns);
00754     c_jd_to_civil(*rjd, sg, &ry, rm, rd);
00755     if (ry != y || *rm != m || *rd != d)
00756         return 0;
00757     return 1;
00758 }
00759 
00760 static int
00761 c_valid_commercial_p(int y, int w, int d, double sg,
00762                      int *rw, int *rd, int *rjd, int *ns)
00763 {
00764     int ns2, ry2, rw2, rd2;
00765 
00766     if (d < 0)
00767         d += 8;
00768     if (w < 0) {
00769         int rjd2;
00770 
00771         c_commercial_to_jd(y + 1, 1, 1, sg, &rjd2, &ns2);
00772         c_jd_to_commercial(rjd2 + w * 7, sg, &ry2, &rw2, &rd2);
00773         if (ry2 != y)
00774             return 0;
00775         w = rw2;
00776     }
00777     c_commercial_to_jd(y, w, d, sg, rjd, ns);
00778     c_jd_to_commercial(*rjd, sg, &ry2, rw, rd);
00779     if (y != ry2 || w != *rw || d != *rd)
00780         return 0;
00781     return 1;
00782 }
00783 
00784 static int
00785 c_valid_weeknum_p(int y, int w, int d, int f, double sg,
00786                   int *rw, int *rd, int *rjd, int *ns)
00787 {
00788     int ns2, ry2, rw2, rd2;
00789 
00790     if (d < 0)
00791         d += 7;
00792     if (w < 0) {
00793         int rjd2;
00794 
00795         c_weeknum_to_jd(y + 1, 1, f, f, sg, &rjd2, &ns2);
00796         c_jd_to_weeknum(rjd2 + w * 7, f, sg, &ry2, &rw2, &rd2);
00797         if (ry2 != y)
00798             return 0;
00799         w = rw2;
00800     }
00801     c_weeknum_to_jd(y, w, d, f, sg, rjd, ns);
00802     c_jd_to_weeknum(*rjd, f, sg, &ry2, rw, rd);
00803     if (y != ry2 || w != *rw || d != *rd)
00804         return 0;
00805     return 1;
00806 }
00807 
00808 #ifndef NDEBUG
00809 static int
00810 c_valid_nth_kday_p(int y, int m, int n, int k, double sg,
00811                    int *rm, int *rn, int *rk, int *rjd, int *ns)
00812 {
00813     int ns2, ry2, rm2, rn2, rk2;
00814 
00815     if (k < 0)
00816         k += 7;
00817     if (n < 0) {
00818         int t, ny, nm, rjd2;
00819 
00820         t = y * 12 + m;
00821         ny = DIV(t, 12);
00822         nm = MOD(t, 12) + 1;
00823 
00824         c_nth_kday_to_jd(ny, nm, 1, k, sg, &rjd2, &ns2);
00825         c_jd_to_nth_kday(rjd2 + n * 7, sg, &ry2, &rm2, &rn2, &rk2);
00826         if (ry2 != y || rm2 != m)
00827             return 0;
00828         n = rn2;
00829     }
00830     c_nth_kday_to_jd(y, m, n, k, sg, rjd, ns);
00831     c_jd_to_nth_kday(*rjd, sg, &ry2, rm, rn, rk);
00832     if (y != ry2 || m != *rm || n != *rn || k != *rk)
00833         return 0;
00834     return 1;
00835 }
00836 #endif
00837 
00838 static int
00839 c_valid_time_p(int h, int min, int s, int *rh, int *rmin, int *rs)
00840 {
00841     if (h < 0)
00842         h += 24;
00843     if (min < 0)
00844         min += 60;
00845     if (s < 0)
00846         s += 60;
00847     *rh = h;
00848     *rmin = min;
00849     *rs = s;
00850     return !(h   < 0 || h   > 24 ||
00851              min < 0 || min > 59 ||
00852              s   < 0 || s   > 59 ||
00853              (h == 24 && (min > 0 || s > 0)));
00854 }
00855 
00856 inline static int
00857 c_valid_start_p(double sg)
00858 {
00859     if (isnan(sg))
00860         return 0;
00861     if (isinf(sg))
00862         return 1;
00863     if (sg < REFORM_BEGIN_JD || sg > REFORM_END_JD)
00864         return 0;
00865     return 1;
00866 }
00867 
00868 inline static int
00869 df_local_to_utc(int df, int of)
00870 {
00871     df -= of;
00872     if (df < 0)
00873         df += DAY_IN_SECONDS;
00874     else if (df >= DAY_IN_SECONDS)
00875         df -= DAY_IN_SECONDS;
00876     return df;
00877 }
00878 
00879 inline static int
00880 df_utc_to_local(int df, int of)
00881 {
00882     df += of;
00883     if (df < 0)
00884         df += DAY_IN_SECONDS;
00885     else if (df >= DAY_IN_SECONDS)
00886         df -= DAY_IN_SECONDS;
00887     return df;
00888 }
00889 
00890 inline static int
00891 jd_local_to_utc(int jd, int df, int of)
00892 {
00893     df -= of;
00894     if (df < 0)
00895         jd -= 1;
00896     else if (df >= DAY_IN_SECONDS)
00897         jd += 1;
00898     return jd;
00899 }
00900 
00901 inline static int
00902 jd_utc_to_local(int jd, int df, int of)
00903 {
00904     df += of;
00905     if (df < 0)
00906         jd -= 1;
00907     else if (df >= DAY_IN_SECONDS)
00908         jd += 1;
00909     return jd;
00910 }
00911 
00912 inline static int
00913 time_to_df(int h, int min, int s)
00914 {
00915     return h * HOUR_IN_SECONDS + min * MINUTE_IN_SECONDS + s;
00916 }
00917 
00918 inline static void
00919 df_to_time(int df, int *h, int *min, int *s)
00920 {
00921     *h = df / HOUR_IN_SECONDS;
00922     df %= HOUR_IN_SECONDS;
00923     *min = df / MINUTE_IN_SECONDS;
00924     *s = df % MINUTE_IN_SECONDS;
00925 }
00926 
00927 static VALUE
00928 sec_to_day(VALUE s)
00929 {
00930     if (FIXNUM_P(s))
00931         return rb_rational_new2(s, INT2FIX(DAY_IN_SECONDS));
00932     return f_quo(s, INT2FIX(DAY_IN_SECONDS));
00933 }
00934 
00935 inline static VALUE
00936 isec_to_day(int s)
00937 {
00938     return sec_to_day(INT2FIX(s));
00939 }
00940 
00941 static VALUE
00942 ns_to_day(VALUE n)
00943 {
00944     if (FIXNUM_P(n))
00945         return rb_rational_new2(n, day_in_nanoseconds);
00946     return f_quo(n, day_in_nanoseconds);
00947 }
00948 
00949 #ifndef NDEBUG
00950 static VALUE
00951 ms_to_sec(VALUE m)
00952 {
00953     if (FIXNUM_P(m))
00954         return rb_rational_new2(m, INT2FIX(SECOND_IN_MILLISECONDS));
00955     return f_quo(m, INT2FIX(SECOND_IN_MILLISECONDS));
00956 }
00957 #endif
00958 
00959 static VALUE
00960 ns_to_sec(VALUE n)
00961 {
00962     if (FIXNUM_P(n))
00963         return rb_rational_new2(n, INT2FIX(SECOND_IN_NANOSECONDS));
00964     return f_quo(n, INT2FIX(SECOND_IN_NANOSECONDS));
00965 }
00966 
00967 #ifndef NDEBUG
00968 inline static VALUE
00969 ins_to_day(int n)
00970 {
00971     return ns_to_day(INT2FIX(n));
00972 }
00973 #endif
00974 
00975 static int
00976 safe_mul_p(VALUE x, long m)
00977 {
00978     long ix;
00979 
00980     if (!FIXNUM_P(x))
00981         return 0;
00982     ix = FIX2LONG(x);
00983     if (ix < 0) {
00984         if (ix <= (FIXNUM_MIN / m))
00985             return 0;
00986     }
00987     else {
00988         if (ix >= (FIXNUM_MAX / m))
00989             return 0;
00990     }
00991     return 1;
00992 }
00993 
00994 static VALUE
00995 day_to_sec(VALUE d)
00996 {
00997     if (safe_mul_p(d, DAY_IN_SECONDS))
00998         return LONG2FIX(FIX2LONG(d) * DAY_IN_SECONDS);
00999     return f_mul(d, INT2FIX(DAY_IN_SECONDS));
01000 }
01001 
01002 #ifndef NDEBUG
01003 static VALUE
01004 day_to_ns(VALUE d)
01005 {
01006     return f_mul(d, day_in_nanoseconds);
01007 }
01008 #endif
01009 
01010 static VALUE
01011 sec_to_ms(VALUE s)
01012 {
01013     if (safe_mul_p(s, SECOND_IN_MILLISECONDS))
01014         return LONG2FIX(FIX2LONG(s) * SECOND_IN_MILLISECONDS);
01015     return f_mul(s, INT2FIX(SECOND_IN_MILLISECONDS));
01016 }
01017 
01018 static VALUE
01019 sec_to_ns(VALUE s)
01020 {
01021     if (safe_mul_p(s, SECOND_IN_NANOSECONDS))
01022         return LONG2FIX(FIX2LONG(s) * SECOND_IN_NANOSECONDS);
01023     return f_mul(s, INT2FIX(SECOND_IN_NANOSECONDS));
01024 }
01025 
01026 #ifndef NDEBUG
01027 static VALUE
01028 isec_to_ns(int s)
01029 {
01030     return sec_to_ns(INT2FIX(s));
01031 }
01032 #endif
01033 
01034 static VALUE
01035 div_day(VALUE d, VALUE *f)
01036 {
01037     if (f)
01038         *f = f_mod(d, INT2FIX(1));
01039     return f_floor(d);
01040 }
01041 
01042 static VALUE
01043 div_df(VALUE d, VALUE *f)
01044 {
01045     VALUE s = day_to_sec(d);
01046 
01047     if (f)
01048         *f = f_mod(s, INT2FIX(1));
01049     return f_floor(s);
01050 }
01051 
01052 #ifndef NDEBUG
01053 static VALUE
01054 div_sf(VALUE s, VALUE *f)
01055 {
01056     VALUE n = sec_to_ns(s);
01057 
01058     if (f)
01059         *f = f_mod(n, INT2FIX(1));
01060     return f_floor(n);
01061 }
01062 #endif
01063 
01064 static void
01065 decode_day(VALUE d, VALUE *jd, VALUE *df, VALUE *sf)
01066 {
01067     VALUE f;
01068 
01069     *jd = div_day(d, &f);
01070     *df = div_df(f, &f);
01071     *sf = sec_to_ns(f);
01072 }
01073 
01074 inline static double
01075 s_virtual_sg(union DateData *x)
01076 {
01077     if (isinf(x->s.sg))
01078         return x->s.sg;
01079     if (f_zero_p(x->s.nth))
01080         return x->s.sg;
01081     else if (f_negative_p(x->s.nth))
01082         return positive_inf;
01083     return negative_inf;
01084 }
01085 
01086 inline static double
01087 c_virtual_sg(union DateData *x)
01088 {
01089     if (isinf(x->c.sg))
01090         return x->c.sg;
01091     if (f_zero_p(x->c.nth))
01092         return x->c.sg;
01093     else if (f_negative_p(x->c.nth))
01094         return positive_inf;
01095     return negative_inf;
01096 }
01097 
01098 inline static double
01099 m_virtual_sg(union DateData *x)
01100 {
01101     if (simple_dat_p(x))
01102         return s_virtual_sg(x);
01103     else
01104         return c_virtual_sg(x);
01105 }
01106 
01107 #define canonicalize_jd(_nth, _jd) \
01108 {\
01109     if (_jd < 0) {\
01110         _nth = f_sub(_nth, INT2FIX(1));\
01111         _jd += CM_PERIOD;\
01112     }\
01113     if (_jd >= CM_PERIOD) {\
01114         _nth = f_add(_nth, INT2FIX(1));\
01115         _jd -= CM_PERIOD;\
01116     }\
01117 }
01118 
01119 inline static void
01120 canonicalize_s_jd(union DateData *x)
01121 {
01122     int j = x->s.jd;
01123     assert(have_jd_p(x));
01124     canonicalize_jd(x->s.nth, x->s.jd);
01125     if (x->s.jd != j)
01126         x->flags &= ~HAVE_CIVIL;
01127 }
01128 
01129 inline static void
01130 get_s_jd(union DateData *x)
01131 {
01132     assert(simple_dat_p(x));
01133     if (!have_jd_p(x)) {
01134         int jd, ns;
01135 
01136         assert(have_civil_p(x));
01137 #ifndef USE_PACK
01138         c_civil_to_jd(x->s.year, x->s.mon, x->s.mday,
01139                       s_virtual_sg(x), &jd, &ns);
01140 #else
01141         c_civil_to_jd(x->s.year, EX_MON(x->s.pc), EX_MDAY(x->s.pc),
01142                       s_virtual_sg(x), &jd, &ns);
01143 #endif
01144         x->s.jd = jd;
01145         x->s.flags |= HAVE_JD;
01146     }
01147 }
01148 
01149 inline static void
01150 get_s_civil(union DateData *x)
01151 {
01152     assert(simple_dat_p(x));
01153     if (!have_civil_p(x)) {
01154         int y, m, d;
01155 
01156         assert(have_jd_p(x));
01157         c_jd_to_civil(x->s.jd, s_virtual_sg(x), &y, &m, &d);
01158         x->s.year = y;
01159 #ifndef USE_PACK
01160         x->s.mon = m;
01161         x->s.mday = d;
01162 #else
01163         x->s.pc = PACK2(m, d);
01164 #endif
01165         x->s.flags |= HAVE_CIVIL;
01166     }
01167 }
01168 
01169 inline static void
01170 get_c_df(union DateData *x)
01171 {
01172     assert(complex_dat_p(x));
01173     if (!have_df_p(x)) {
01174         assert(have_time_p(x));
01175 #ifndef USE_PACK
01176         x->c.df = df_local_to_utc(time_to_df(x->c.hour, x->c.min, x->c.sec),
01177                                   x->c.of);
01178 #else
01179         x->c.df = df_local_to_utc(time_to_df(EX_HOUR(x->c.pc),
01180                                              EX_MIN(x->c.pc),
01181                                              EX_SEC(x->c.pc)),
01182                                   x->c.of);
01183 #endif
01184         x->c.flags |= HAVE_DF;
01185     }
01186 }
01187 
01188 inline static void
01189 get_c_time(union DateData *x)
01190 {
01191     assert(complex_dat_p(x));
01192     if (!have_time_p(x)) {
01193 #ifndef USE_PACK
01194         int r;
01195         assert(have_df_p(x));
01196         r = df_utc_to_local(x->c.df, x->c.of);
01197         df_to_time(r, &x->c.hour, &x->c.min, &x->c.sec);
01198         x->c.flags |= HAVE_TIME;
01199 #else
01200         int r, m, d, h, min, s;
01201 
01202         assert(have_df_p(x));
01203         m = EX_MON(x->c.pc);
01204         d = EX_MDAY(x->c.pc);
01205         r = df_utc_to_local(x->c.df, x->c.of);
01206         df_to_time(r, &h, &min, &s);
01207         x->c.pc = PACK5(m, d, h, min, s);
01208         x->c.flags |= HAVE_TIME;
01209 #endif
01210     }
01211 }
01212 
01213 inline static void
01214 canonicalize_c_jd(union DateData *x)
01215 {
01216     int j = x->c.jd;
01217     assert(have_jd_p(x));
01218     canonicalize_jd(x->c.nth, x->c.jd);
01219     if (x->c.jd != j)
01220         x->flags &= ~HAVE_CIVIL;
01221 }
01222 
01223 inline static void
01224 get_c_jd(union DateData *x)
01225 {
01226     assert(complex_dat_p(x));
01227     if (!have_jd_p(x)) {
01228         int jd, ns;
01229 
01230         assert(have_civil_p(x));
01231 #ifndef USE_PACK
01232         c_civil_to_jd(x->c.year, x->c.mon, x->c.mday,
01233                       c_virtual_sg(x), &jd, &ns);
01234 #else
01235         c_civil_to_jd(x->c.year, EX_MON(x->c.pc), EX_MDAY(x->c.pc),
01236                       c_virtual_sg(x), &jd, &ns);
01237 #endif
01238 
01239         get_c_time(x);
01240 #ifndef USE_PACK
01241         x->c.jd = jd_local_to_utc(jd,
01242                                   time_to_df(x->c.hour, x->c.min, x->c.sec),
01243                                   x->c.of);
01244 #else
01245         x->c.jd = jd_local_to_utc(jd,
01246                                   time_to_df(EX_HOUR(x->c.pc),
01247                                              EX_MIN(x->c.pc),
01248                                              EX_SEC(x->c.pc)),
01249                                   x->c.of);
01250 #endif
01251         x->c.flags |= HAVE_JD;
01252     }
01253 }
01254 
01255 inline static void
01256 get_c_civil(union DateData *x)
01257 {
01258     assert(complex_dat_p(x));
01259     if (!have_civil_p(x)) {
01260 #ifndef USE_PACK
01261         int jd, y, m, d;
01262 #else
01263         int jd, y, m, d, h, min, s;
01264 #endif
01265 
01266         assert(have_jd_p(x));
01267         get_c_df(x);
01268         jd = jd_utc_to_local(x->c.jd, x->c.df, x->c.of);
01269         c_jd_to_civil(jd, c_virtual_sg(x), &y, &m, &d);
01270         x->c.year = y;
01271 #ifndef USE_PACK
01272         x->c.mon = m;
01273         x->c.mday = d;
01274 #else
01275         h = EX_HOUR(x->c.pc);
01276         min = EX_MIN(x->c.pc);
01277         s = EX_SEC(x->c.pc);
01278         x->c.pc = PACK5(m, d, h, min, s);
01279 #endif
01280         x->c.flags |= HAVE_CIVIL;
01281     }
01282 }
01283 
01284 inline static int
01285 local_jd(union DateData *x)
01286 {
01287     assert(complex_dat_p(x));
01288     assert(have_jd_p(x));
01289     assert(have_df_p(x));
01290     return jd_utc_to_local(x->c.jd, x->c.df, x->c.of);
01291 }
01292 
01293 inline static int
01294 local_df(union DateData *x)
01295 {
01296     assert(complex_dat_p(x));
01297     assert(have_df_p(x));
01298     return df_utc_to_local(x->c.df, x->c.of);
01299 }
01300 
01301 static void
01302 decode_year(VALUE y, double style,
01303             VALUE *nth, int *ry)
01304 {
01305     int period;
01306     VALUE t;
01307 
01308     period = (style < 0) ?
01309         CM_PERIOD_GCY :
01310         CM_PERIOD_JCY;
01311     if (FIXNUM_P(y)) {
01312         long iy, it, inth;
01313 
01314         iy = FIX2LONG(y);
01315         if (iy >= (FIXNUM_MAX - 4712))
01316             goto big;
01317         it = iy + 4712; /* shift */
01318         inth = DIV(it, ((long)period));
01319         *nth = LONG2FIX(inth);
01320         if (inth)
01321             it = MOD(it, ((long)period));
01322         *ry = (int)it - 4712; /* unshift */
01323         return;
01324     }
01325   big:
01326     t = f_add(y, INT2FIX(4712)); /* shift */
01327     *nth = f_idiv(t, INT2FIX(period));
01328     if (f_nonzero_p(*nth))
01329         t = f_mod(t, INT2FIX(period));
01330     *ry = FIX2INT(t) - 4712; /* unshift */
01331 }
01332 
01333 static void
01334 encode_year(VALUE nth, int y, double style,
01335             VALUE *ry)
01336 {
01337     int period;
01338     VALUE t;
01339 
01340     period = (style < 0) ?
01341         CM_PERIOD_GCY :
01342         CM_PERIOD_JCY;
01343     if (f_zero_p(nth))
01344         *ry = INT2FIX(y);
01345     else {
01346         t = f_mul(INT2FIX(period), nth);
01347         t = f_add(t, INT2FIX(y));
01348         *ry = t;
01349     }
01350 }
01351 
01352 static void
01353 decode_jd(VALUE jd, VALUE *nth, int *rjd)
01354 {
01355     assert(FIXNUM_P(jd) || RB_TYPE_P(jd, T_BIGNUM));
01356     *nth = f_idiv(jd, INT2FIX(CM_PERIOD));
01357     if (f_zero_p(*nth)) {
01358         assert(FIXNUM_P(jd));
01359         *rjd = FIX2INT(jd);
01360         return;
01361     }
01362     *rjd = FIX2INT(f_mod(jd, INT2FIX(CM_PERIOD)));
01363 }
01364 
01365 static void
01366 encode_jd(VALUE nth, int jd, VALUE *rjd)
01367 {
01368     if (f_zero_p(nth)) {
01369         *rjd = INT2FIX(jd);
01370         return;
01371     }
01372     *rjd = f_add(f_mul(INT2FIX(CM_PERIOD), nth), INT2FIX(jd));
01373 }
01374 
01375 inline static double
01376 guess_style(VALUE y, double sg) /* -/+oo or zero */
01377 {
01378     double style = 0;
01379 
01380     if (isinf(sg))
01381         style = sg;
01382     else if (!FIXNUM_P(y))
01383         style = f_positive_p(y) ? negative_inf : positive_inf;
01384     else {
01385         long iy = FIX2LONG(y);
01386 
01387         assert(FIXNUM_P(y));
01388         if (iy < REFORM_BEGIN_YEAR)
01389             style = positive_inf;
01390         else if (iy > REFORM_END_YEAR)
01391             style = negative_inf;
01392     }
01393     return style;
01394 }
01395 
01396 inline static void
01397 m_canonicalize_jd(union DateData *x)
01398 {
01399     if (simple_dat_p(x)) {
01400         get_s_jd(x);
01401         canonicalize_s_jd(x);
01402     }
01403     else {
01404         get_c_jd(x);
01405         canonicalize_c_jd(x);
01406     }
01407 }
01408 
01409 inline static VALUE
01410 m_nth(union DateData *x)
01411 {
01412     if (simple_dat_p(x))
01413         return x->s.nth;
01414     else {
01415         get_c_civil(x);
01416         return x->c.nth;
01417     }
01418 }
01419 
01420 inline static int
01421 m_jd(union DateData *x)
01422 {
01423     if (simple_dat_p(x)) {
01424         get_s_jd(x);
01425         return x->s.jd;
01426     }
01427     else {
01428         get_c_jd(x);
01429         return x->c.jd;
01430     }
01431 }
01432 
01433 static VALUE
01434 m_real_jd(union DateData *x)
01435 {
01436     VALUE nth, rjd;
01437     int jd;
01438 
01439     nth = m_nth(x);
01440     jd = m_jd(x);
01441 
01442     encode_jd(nth, jd, &rjd);
01443     return rjd;
01444 }
01445 
01446 static int
01447 m_local_jd(union DateData *x)
01448 {
01449     if (simple_dat_p(x)) {
01450         get_s_jd(x);
01451         return x->s.jd;
01452     }
01453     else {
01454         get_c_jd(x);
01455         get_c_df(x);
01456         return local_jd(x);
01457     }
01458 }
01459 
01460 static VALUE
01461 m_real_local_jd(union DateData *x)
01462 {
01463     VALUE nth, rjd;
01464     int jd;
01465 
01466     nth = m_nth(x);
01467     jd = m_local_jd(x);
01468 
01469     encode_jd(nth, jd, &rjd);
01470     return rjd;
01471 }
01472 
01473 inline static int
01474 m_df(union DateData *x)
01475 {
01476     if (simple_dat_p(x))
01477         return 0;
01478     else {
01479         get_c_df(x);
01480         return x->c.df;
01481     }
01482 }
01483 
01484 #ifndef NDEBUG
01485 static VALUE
01486 m_df_in_day(union DateData *x)
01487 {
01488     return isec_to_day(m_df(x));
01489 }
01490 #endif
01491 
01492 static int
01493 m_local_df(union DateData *x)
01494 {
01495     if (simple_dat_p(x))
01496         return 0;
01497     else {
01498         get_c_df(x);
01499         return local_df(x);
01500     }
01501 }
01502 
01503 #ifndef NDEBUG
01504 static VALUE
01505 m_local_df_in_day(union DateData *x)
01506 {
01507     return isec_to_day(m_local_df(x));
01508 }
01509 #endif
01510 
01511 inline static VALUE
01512 m_sf(union DateData *x)
01513 {
01514     if (simple_dat_p(x))
01515         return INT2FIX(0);
01516     else
01517         return x->c.sf;
01518 }
01519 
01520 #ifndef NDEBUG
01521 static VALUE
01522 m_sf_in_day(union DateData *x)
01523 {
01524     return ns_to_day(m_sf(x));
01525 }
01526 #endif
01527 
01528 static VALUE
01529 m_sf_in_sec(union DateData *x)
01530 {
01531     return ns_to_sec(m_sf(x));
01532 }
01533 
01534 static VALUE
01535 m_fr(union DateData *x)
01536 {
01537     if (simple_dat_p(x))
01538         return INT2FIX(0);
01539     else {
01540         int df;
01541         VALUE sf, fr;
01542 
01543         df = m_local_df(x);
01544         sf = m_sf(x);
01545         fr = isec_to_day(df);
01546         if (f_nonzero_p(sf))
01547             fr = f_add(fr, ns_to_day(sf));
01548         return fr;
01549     }
01550 }
01551 
01552 #define HALF_DAYS_IN_SECONDS (DAY_IN_SECONDS / 2)
01553 
01554 static VALUE
01555 m_ajd(union DateData *x)
01556 {
01557     VALUE r, sf;
01558     int df;
01559 
01560     if (simple_dat_p(x)) {
01561         r = m_real_jd(x);
01562         if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2)) {
01563             long ir = FIX2LONG(r);
01564             ir = ir * 2 - 1;
01565             return rb_rational_new2(LONG2FIX(ir), INT2FIX(2));
01566         }
01567         else
01568             return rb_rational_new2(f_sub(f_mul(r,
01569                                                 INT2FIX(2)),
01570                                           INT2FIX(1)),
01571                                     INT2FIX(2));
01572     }
01573 
01574     r = m_real_jd(x);
01575     df = m_df(x);
01576     df -= HALF_DAYS_IN_SECONDS;
01577     if (df)
01578         r = f_add(r, isec_to_day(df));
01579     sf = m_sf(x);
01580     if (f_nonzero_p(sf))
01581         r = f_add(r, ns_to_day(sf));
01582 
01583     return r;
01584 }
01585 
01586 static VALUE
01587 m_amjd(union DateData *x)
01588 {
01589     VALUE r, sf;
01590     int df;
01591 
01592     r = m_real_jd(x);
01593     if (FIXNUM_P(r) && FIX2LONG(r) >= (FIXNUM_MIN + 2400001)) {
01594         long ir = FIX2LONG(r);
01595         ir -= 2400001;
01596         r = rb_rational_new1(LONG2FIX(ir));
01597     }
01598     else
01599         r = rb_rational_new1(f_sub(m_real_jd(x),
01600                                    INT2FIX(2400001)));
01601 
01602     if (simple_dat_p(x))
01603         return r;
01604 
01605     df = m_df(x);
01606     if (df)
01607         r = f_add(r, isec_to_day(df));
01608     sf = m_sf(x);
01609     if (f_nonzero_p(sf))
01610         r = f_add(r, ns_to_day(sf));
01611 
01612     return r;
01613 }
01614 
01615 inline static int
01616 m_of(union DateData *x)
01617 {
01618     if (simple_dat_p(x))
01619         return 0;
01620     else {
01621         get_c_jd(x);
01622         return x->c.of;
01623     }
01624 }
01625 
01626 static VALUE
01627 m_of_in_day(union DateData *x)
01628 {
01629     return isec_to_day(m_of(x));
01630 }
01631 
01632 inline static double
01633 m_sg(union DateData *x)
01634 {
01635     if (simple_dat_p(x))
01636         return x->s.sg;
01637     else {
01638         get_c_jd(x);
01639         return x->c.sg;
01640     }
01641 }
01642 
01643 static int
01644 m_julian_p(union DateData *x)
01645 {
01646     int jd;
01647     double sg;
01648 
01649     if (simple_dat_p(x)) {
01650         get_s_jd(x);
01651         jd = x->s.jd;
01652         sg = s_virtual_sg(x);
01653     }
01654     else {
01655         get_c_jd(x);
01656         jd = x->c.jd;
01657         sg = c_virtual_sg(x);
01658     }
01659     if (isinf(sg))
01660         return sg == positive_inf;
01661     return jd < sg;
01662 }
01663 
01664 inline static int
01665 m_gregorian_p(union DateData *x)
01666 {
01667     return !m_julian_p(x);
01668 }
01669 
01670 inline static int
01671 m_proleptic_julian_p(union DateData *x)
01672 {
01673     double sg;
01674 
01675     sg = m_sg(x);
01676     if (isinf(sg) && sg > 0)
01677         return 1;
01678     return 0;
01679 }
01680 
01681 inline static int
01682 m_proleptic_gregorian_p(union DateData *x)
01683 {
01684     double sg;
01685 
01686     sg = m_sg(x);
01687     if (isinf(sg) && sg < 0)
01688         return 1;
01689     return 0;
01690 }
01691 
01692 inline static int
01693 m_year(union DateData *x)
01694 {
01695     if (simple_dat_p(x)) {
01696         get_s_civil(x);
01697         return x->s.year;
01698     }
01699     else {
01700         get_c_civil(x);
01701         return x->c.year;
01702     }
01703 }
01704 
01705 static VALUE
01706 m_real_year(union DateData *x)
01707 {
01708     VALUE nth, ry;
01709     int year;
01710 
01711     nth = m_nth(x);
01712     year = m_year(x);
01713 
01714     if (f_zero_p(nth))
01715         return INT2FIX(year);
01716 
01717     encode_year(nth, year,
01718                 m_gregorian_p(x) ? -1 : +1,
01719                 &ry);
01720     return ry;
01721 }
01722 
01723 
01724 #ifdef USE_PACK
01725 inline static int
01726 m_pc(union DateData *x)
01727 {
01728     if (simple_dat_p(x)) {
01729         get_s_civil(x);
01730         return x->s.pc;
01731     }
01732     else {
01733         get_c_civil(x);
01734         get_c_time(x);
01735         return x->c.pc;
01736     }
01737 }
01738 #endif
01739 
01740 inline static int
01741 m_mon(union DateData *x)
01742 {
01743     if (simple_dat_p(x)) {
01744         get_s_civil(x);
01745 #ifndef USE_PACK
01746         return x->s.mon;
01747 #else
01748         return EX_MON(x->s.pc);
01749 #endif
01750     }
01751     else {
01752         get_c_civil(x);
01753 #ifndef USE_PACK
01754         return x->c.mon;
01755 #else
01756         return EX_MON(x->c.pc);
01757 #endif
01758     }
01759 }
01760 
01761 inline static int
01762 m_mday(union DateData *x)
01763 {
01764     if (simple_dat_p(x)) {
01765         get_s_civil(x);
01766 #ifndef USE_PACK
01767         return x->s.mday;
01768 #else
01769         return EX_MDAY(x->s.pc);
01770 #endif
01771     }
01772     else {
01773         get_c_civil(x);
01774 #ifndef USE_PACK
01775         return x->c.mday;
01776 #else
01777         return EX_MDAY(x->c.pc);
01778 #endif
01779     }
01780 }
01781 
01782 static const int yeartab[2][13] = {
01783     { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
01784     { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
01785 };
01786 
01787 static int
01788 c_julian_to_yday(int y, int m, int d)
01789 {
01790     assert(m >= 1 && m <= 12);
01791     return yeartab[c_julian_leap_p(y) ? 1 : 0][m] + d;
01792 }
01793 
01794 static int
01795 c_gregorian_to_yday(int y, int m, int d)
01796 {
01797     assert(m >= 1 && m <= 12);
01798     return yeartab[c_gregorian_leap_p(y) ? 1 : 0][m] + d;
01799 }
01800 
01801 static int
01802 m_yday(union DateData *x)
01803 {
01804     int jd, ry, rd;
01805     double sg;
01806 
01807     jd = m_local_jd(x);
01808     sg = m_virtual_sg(x); /* !=m_sg() */
01809 
01810     if (m_proleptic_gregorian_p(x) ||
01811         (jd - sg) > 366)
01812         return c_gregorian_to_yday(m_year(x), m_mon(x), m_mday(x));
01813     if (m_proleptic_julian_p(x))
01814         return c_julian_to_yday(m_year(x), m_mon(x), m_mday(x));
01815     c_jd_to_ordinal(jd, sg, &ry, &rd);
01816     return rd;
01817 }
01818 
01819 static int
01820 m_wday(union DateData *x)
01821 {
01822     return c_jd_to_wday(m_local_jd(x));
01823 }
01824 
01825 static int
01826 m_cwyear(union DateData *x)
01827 {
01828     int ry, rw, rd;
01829 
01830     c_jd_to_commercial(m_local_jd(x), m_virtual_sg(x), /* !=m_sg() */
01831                        &ry, &rw, &rd);
01832     return ry;
01833 }
01834 
01835 static VALUE
01836 m_real_cwyear(union DateData *x)
01837 {
01838     VALUE nth, ry;
01839     int year;
01840 
01841     nth = m_nth(x);
01842     year = m_cwyear(x);
01843 
01844     if (f_zero_p(nth))
01845         return INT2FIX(year);
01846 
01847     encode_year(nth, year,
01848                 m_gregorian_p(x) ? -1 : +1,
01849                 &ry);
01850     return ry;
01851 }
01852 
01853 static int
01854 m_cweek(union DateData *x)
01855 {
01856     int ry, rw, rd;
01857 
01858     c_jd_to_commercial(m_local_jd(x), m_virtual_sg(x), /* !=m_sg() */
01859                        &ry, &rw, &rd);
01860     return rw;
01861 }
01862 
01863 static int
01864 m_cwday(union DateData *x)
01865 {
01866     int w;
01867 
01868     w = m_wday(x);
01869     if (w == 0)
01870         w = 7;
01871     return w;
01872 }
01873 
01874 static int
01875 m_wnumx(union DateData *x, int f)
01876 {
01877     int ry, rw, rd;
01878 
01879     c_jd_to_weeknum(m_local_jd(x), f, m_virtual_sg(x), /* !=m_sg() */
01880                     &ry, &rw, &rd);
01881     return rw;
01882 }
01883 
01884 static int
01885 m_wnum0(union DateData *x)
01886 {
01887     return m_wnumx(x, 0);
01888 }
01889 
01890 static int
01891 m_wnum1(union DateData *x)
01892 {
01893     return m_wnumx(x, 1);
01894 }
01895 
01896 inline static int
01897 m_hour(union DateData *x)
01898 {
01899     if (simple_dat_p(x))
01900         return 0;
01901     else {
01902         get_c_time(x);
01903 #ifndef USE_PACK
01904         return x->c.hour;
01905 #else
01906         return EX_HOUR(x->c.pc);
01907 #endif
01908     }
01909 }
01910 
01911 inline static int
01912 m_min(union DateData *x)
01913 {
01914     if (simple_dat_p(x))
01915         return 0;
01916     else {
01917         get_c_time(x);
01918 #ifndef USE_PACK
01919         return x->c.min;
01920 #else
01921         return EX_MIN(x->c.pc);
01922 #endif
01923     }
01924 }
01925 
01926 inline static int
01927 m_sec(union DateData *x)
01928 {
01929     if (simple_dat_p(x))
01930         return 0;
01931     else {
01932         get_c_time(x);
01933 #ifndef USE_PACK
01934         return x->c.sec;
01935 #else
01936         return EX_SEC(x->c.pc);
01937 #endif
01938     }
01939 }
01940 
01941 #define decode_offset(of,s,h,m)\
01942 {\
01943     int a;\
01944     s = (of < 0) ? '-' : '+';\
01945     a = (of < 0) ? -of : of;\
01946     h = a / HOUR_IN_SECONDS;\
01947     m = a % HOUR_IN_SECONDS / MINUTE_IN_SECONDS;\
01948 }
01949 
01950 static VALUE
01951 of2str(int of)
01952 {
01953     int s, h, m;
01954 
01955     decode_offset(of, s, h, m);
01956     return rb_enc_sprintf(rb_usascii_encoding(), "%c%02d:%02d", s, h, m);
01957 }
01958 
01959 static VALUE
01960 m_zone(union DateData *x)
01961 {
01962     if (simple_dat_p(x))
01963         return rb_usascii_str_new2("+00:00");
01964     return of2str(m_of(x));
01965 }
01966 
01967 inline static VALUE
01968 f_kind_of_p(VALUE x, VALUE c)
01969 {
01970     return rb_obj_is_kind_of(x, c);
01971 }
01972 
01973 inline static VALUE
01974 k_date_p(VALUE x)
01975 {
01976     return f_kind_of_p(x, cDate);
01977 }
01978 
01979 inline static VALUE
01980 k_datetime_p(VALUE x)
01981 {
01982     return f_kind_of_p(x, cDateTime);
01983 }
01984 
01985 inline static VALUE
01986 k_numeric_p(VALUE x)
01987 {
01988     return f_kind_of_p(x, rb_cNumeric);
01989 }
01990 
01991 inline static VALUE
01992 k_rational_p(VALUE x)
01993 {
01994     return f_kind_of_p(x, rb_cRational);
01995 }
01996 
01997 #ifndef NDEBUG
01998 static void
01999 civil_to_jd(VALUE y, int m, int d, double sg,
02000             VALUE *nth, int *ry,
02001             int *rjd,
02002             int *ns)
02003 {
02004     double style = guess_style(y, sg);
02005 
02006     if (style == 0) {
02007         int jd;
02008 
02009         c_civil_to_jd(FIX2INT(y), m, d, sg, &jd, ns);
02010         decode_jd(INT2FIX(jd), nth, rjd);
02011         if (f_zero_p(*nth))
02012             *ry = FIX2INT(y);
02013         else {
02014             VALUE nth2;
02015             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02016         }
02017     }
02018     else {
02019         decode_year(y, style, nth, ry);
02020         c_civil_to_jd(*ry, m, d, style, rjd, ns);
02021     }
02022 }
02023 
02024 static void
02025 jd_to_civil(VALUE jd, double sg,
02026             VALUE *nth, int *rjd,
02027             int *ry, int *rm, int *rd)
02028 {
02029     decode_jd(jd, nth, rjd);
02030     c_jd_to_civil(*rjd, sg, ry, rm, rd);
02031 }
02032 
02033 static void
02034 ordinal_to_jd(VALUE y, int d, double sg,
02035               VALUE *nth, int *ry,
02036               int *rjd,
02037               int *ns)
02038 {
02039     double style = guess_style(y, sg);
02040 
02041     if (style == 0) {
02042         int jd;
02043 
02044         c_ordinal_to_jd(FIX2INT(y), d, sg, &jd, ns);
02045         decode_jd(INT2FIX(jd), nth, rjd);
02046         if (f_zero_p(*nth))
02047             *ry = FIX2INT(y);
02048         else {
02049             VALUE nth2;
02050             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02051         }
02052     }
02053     else {
02054         decode_year(y, style, nth, ry);
02055         c_ordinal_to_jd(*ry, d, style, rjd, ns);
02056     }
02057 }
02058 
02059 static void
02060 jd_to_ordinal(VALUE jd, double sg,
02061               VALUE *nth, int *rjd,
02062               int *ry, int *rd)
02063 {
02064     decode_jd(jd, nth, rjd);
02065     c_jd_to_ordinal(*rjd, sg, ry, rd);
02066 }
02067 
02068 static void
02069 commercial_to_jd(VALUE y, int w, int d, double sg,
02070                  VALUE *nth, int *ry,
02071                  int *rjd,
02072                  int *ns)
02073 {
02074     double style = guess_style(y, sg);
02075 
02076     if (style == 0) {
02077         int jd;
02078 
02079         c_commercial_to_jd(FIX2INT(y), w, d, sg, &jd, ns);
02080         decode_jd(INT2FIX(jd), nth, rjd);
02081         if (f_zero_p(*nth))
02082             *ry = FIX2INT(y);
02083         else {
02084             VALUE nth2;
02085             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02086         }
02087     }
02088     else {
02089         decode_year(y, style, nth, ry);
02090         c_commercial_to_jd(*ry, w, d, style, rjd, ns);
02091     }
02092 }
02093 
02094 static void
02095 jd_to_commercial(VALUE jd, double sg,
02096                  VALUE *nth, int *rjd,
02097                  int *ry, int *rw, int *rd)
02098 {
02099     decode_jd(jd, nth, rjd);
02100     c_jd_to_commercial(*rjd, sg, ry, rw, rd);
02101 }
02102 
02103 static void
02104 weeknum_to_jd(VALUE y, int w, int d, int f, double sg,
02105               VALUE *nth, int *ry,
02106               int *rjd,
02107               int *ns)
02108 {
02109     double style = guess_style(y, sg);
02110 
02111     if (style == 0) {
02112         int jd;
02113 
02114         c_weeknum_to_jd(FIX2INT(y), w, d, f, sg, &jd, ns);
02115         decode_jd(INT2FIX(jd), nth, rjd);
02116         if (f_zero_p(*nth))
02117             *ry = FIX2INT(y);
02118         else {
02119             VALUE nth2;
02120             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02121         }
02122     }
02123     else {
02124         decode_year(y, style, nth, ry);
02125         c_weeknum_to_jd(*ry, w, d, f, style, rjd, ns);
02126     }
02127 }
02128 
02129 static void
02130 jd_to_weeknum(VALUE jd, int f, double sg,
02131               VALUE *nth, int *rjd,
02132               int *ry, int *rw, int *rd)
02133 {
02134     decode_jd(jd, nth, rjd);
02135     c_jd_to_weeknum(*rjd, f, sg, ry, rw, rd);
02136 }
02137 
02138 static void
02139 nth_kday_to_jd(VALUE y, int m, int n, int k, double sg,
02140                VALUE *nth, int *ry,
02141                int *rjd,
02142                int *ns)
02143 {
02144     double style = guess_style(y, sg);
02145 
02146     if (style == 0) {
02147         int jd;
02148 
02149         c_nth_kday_to_jd(FIX2INT(y), m, n, k, sg, &jd, ns);
02150         decode_jd(INT2FIX(jd), nth, rjd);
02151         if (f_zero_p(*nth))
02152             *ry = FIX2INT(y);
02153         else {
02154             VALUE nth2;
02155             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02156         }
02157     }
02158     else {
02159         decode_year(y, style, nth, ry);
02160         c_nth_kday_to_jd(*ry, m, n, k, style, rjd, ns);
02161     }
02162 }
02163 
02164 static void
02165 jd_to_nth_kday(VALUE jd, double sg,
02166                VALUE *nth, int *rjd,
02167                int *ry, int *rm, int *rn, int *rk)
02168 {
02169     decode_jd(jd, nth, rjd);
02170     c_jd_to_nth_kday(*rjd, sg, ry, rm, rn, rk);
02171 }
02172 #endif
02173 
02174 static int
02175 valid_ordinal_p(VALUE y, int d, double sg,
02176                 VALUE *nth, int *ry,
02177                 int *rd, int *rjd,
02178                 int *ns)
02179 {
02180     double style = guess_style(y, sg);
02181     int r;
02182 
02183     if (style == 0) {
02184         int jd;
02185 
02186         r = c_valid_ordinal_p(FIX2INT(y), d, sg, rd, &jd, ns);
02187         if (!r)
02188             return 0;
02189         decode_jd(INT2FIX(jd), nth, rjd);
02190         if (f_zero_p(*nth))
02191             *ry = FIX2INT(y);
02192         else {
02193             VALUE nth2;
02194             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02195         }
02196     }
02197     else {
02198         decode_year(y, style, nth, ry);
02199         r = c_valid_ordinal_p(*ry, d, style, rd, rjd, ns);
02200     }
02201     return r;
02202 }
02203 
02204 static int
02205 valid_gregorian_p(VALUE y, int m, int d,
02206                   VALUE *nth, int *ry,
02207                   int *rm, int *rd)
02208 {
02209     decode_year(y, -1, nth, ry);
02210     return c_valid_gregorian_p(*ry, m, d, rm, rd);
02211 }
02212 
02213 static int
02214 valid_civil_p(VALUE y, int m, int d, double sg,
02215               VALUE *nth, int *ry,
02216               int *rm, int *rd, int *rjd,
02217               int *ns)
02218 {
02219     double style = guess_style(y, sg);
02220     int r;
02221 
02222     if (style == 0) {
02223         int jd;
02224 
02225         r = c_valid_civil_p(FIX2INT(y), m, d, sg, rm, rd, &jd, ns);
02226         if (!r)
02227             return 0;
02228         decode_jd(INT2FIX(jd), nth, rjd);
02229         if (f_zero_p(*nth))
02230             *ry = FIX2INT(y);
02231         else {
02232             VALUE nth2;
02233             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02234         }
02235     }
02236     else {
02237         decode_year(y, style, nth, ry);
02238         if (style < 0)
02239             r = c_valid_gregorian_p(*ry, m, d, rm, rd);
02240         else
02241             r = c_valid_julian_p(*ry, m, d, rm, rd);
02242         if (!r)
02243             return 0;
02244         c_civil_to_jd(*ry, *rm, *rd, style, rjd, ns);
02245     }
02246     return r;
02247 }
02248 
02249 static int
02250 valid_commercial_p(VALUE y, int w, int d, double sg,
02251                    VALUE *nth, int *ry,
02252                    int *rw, int *rd, int *rjd,
02253                    int *ns)
02254 {
02255     double style = guess_style(y, sg);
02256     int r;
02257 
02258     if (style == 0) {
02259         int jd;
02260 
02261         r = c_valid_commercial_p(FIX2INT(y), w, d, sg, rw, rd, &jd, ns);
02262         if (!r)
02263             return 0;
02264         decode_jd(INT2FIX(jd), nth, rjd);
02265         if (f_zero_p(*nth))
02266             *ry = FIX2INT(y);
02267         else {
02268             VALUE nth2;
02269             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02270         }
02271     }
02272     else {
02273         decode_year(y, style, nth, ry);
02274         r = c_valid_commercial_p(*ry, w, d, style, rw, rd, rjd, ns);
02275     }
02276     return r;
02277 }
02278 
02279 static int
02280 valid_weeknum_p(VALUE y, int w, int d, int f, double sg,
02281                 VALUE *nth, int *ry,
02282                 int *rw, int *rd, int *rjd,
02283                 int *ns)
02284 {
02285     double style = guess_style(y, sg);
02286     int r;
02287 
02288     if (style == 0) {
02289         int jd;
02290 
02291         r = c_valid_weeknum_p(FIX2INT(y), w, d, f, sg, rw, rd, &jd, ns);
02292         if (!r)
02293             return 0;
02294         decode_jd(INT2FIX(jd), nth, rjd);
02295         if (f_zero_p(*nth))
02296             *ry = FIX2INT(y);
02297         else {
02298             VALUE nth2;
02299             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02300         }
02301     }
02302     else {
02303         decode_year(y, style, nth, ry);
02304         r = c_valid_weeknum_p(*ry, w, d, f, style, rw, rd, rjd, ns);
02305     }
02306     return r;
02307 }
02308 
02309 #ifndef NDEBUG
02310 static int
02311 valid_nth_kday_p(VALUE y, int m, int n, int k, double sg,
02312                  VALUE *nth, int *ry,
02313                  int *rm, int *rn, int *rk, int *rjd,
02314                  int *ns)
02315 {
02316     double style = guess_style(y, sg);
02317     int r;
02318 
02319     if (style == 0) {
02320         int jd;
02321 
02322         r = c_valid_nth_kday_p(FIX2INT(y), m, n, k, sg, rm, rn, rk, &jd, ns);
02323         if (!r)
02324             return 0;
02325         decode_jd(INT2FIX(jd), nth, rjd);
02326         if (f_zero_p(*nth))
02327             *ry = FIX2INT(y);
02328         else {
02329             VALUE nth2;
02330             decode_year(y, *ns ? -1 : +1, &nth2, ry);
02331         }
02332     }
02333     else {
02334         decode_year(y, style, nth, ry);
02335         r = c_valid_nth_kday_p(*ry, m, n, k, style, rm, rn, rk, rjd, ns);
02336     }
02337     return r;
02338 }
02339 #endif
02340 
02341 VALUE date_zone_to_diff(VALUE);
02342 
02343 static int
02344 offset_to_sec(VALUE vof, int *rof)
02345 {
02346     switch (TYPE(vof)) {
02347       case T_FIXNUM:
02348         {
02349             long n;
02350 
02351             n = FIX2LONG(vof);
02352             if (n != -1 && n != 0 && n != 1)
02353                 return 0;
02354             *rof = (int)n * DAY_IN_SECONDS;
02355             return 1;
02356         }
02357       case T_FLOAT:
02358         {
02359             double n;
02360 
02361             n = RFLOAT_VALUE(vof) * DAY_IN_SECONDS;
02362             if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
02363                 return 0;
02364             *rof = (int)round(n);
02365             if (*rof != n)
02366                 rb_warning("fraction of offset is ignored");
02367             return 1;
02368         }
02369       default:
02370         if (!k_numeric_p(vof))
02371             rb_raise(rb_eTypeError, "expected numeric");
02372         vof = f_to_r(vof);
02373 #ifdef CANONICALIZATION_FOR_MATHN
02374         if (!k_rational_p(vof))
02375             return offset_to_sec(vof, rof);
02376 #endif
02377         /* fall through */
02378       case T_RATIONAL:
02379         {
02380             VALUE vs, vn, vd;
02381             long n;
02382 
02383             vs = day_to_sec(vof);
02384 
02385 #ifdef CANONICALIZATION_FOR_MATHN
02386             if (!k_rational_p(vs)) {
02387                 if (!FIXNUM_P(vs))
02388                     return 0;
02389                 n = FIX2LONG(vs);
02390                 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
02391                     return 0;
02392                 *rof = (int)n;
02393                 return 1;
02394             }
02395 #endif
02396             vn = RRATIONAL(vs)->num;
02397             vd = RRATIONAL(vs)->den;
02398 
02399             if (FIXNUM_P(vn) && FIXNUM_P(vd) && (FIX2LONG(vd) == 1))
02400                 n = FIX2LONG(vn);
02401             else {
02402                 vn = f_round(vs);
02403                 if (!f_eqeq_p(vn, vs))
02404                     rb_warning("fraction of offset is ignored");
02405                 if (!FIXNUM_P(vn))
02406                     return 0;
02407                 n = FIX2LONG(vn);
02408                 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
02409                     return 0;
02410             }
02411             *rof = (int)n;
02412             return 1;
02413         }
02414       case T_STRING:
02415         {
02416             VALUE vs = date_zone_to_diff(vof);
02417             long n;
02418 
02419             if (!FIXNUM_P(vs))
02420                 return 0;
02421             n = FIX2LONG(vs);
02422             if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
02423                 return 0;
02424             *rof = (int)n;
02425             return 1;
02426         }
02427     }
02428     return 0;
02429 }
02430 
02431 /* date */
02432 
02433 #define valid_sg(sg) \
02434 {\
02435     if (!c_valid_start_p(sg)) {\
02436         sg = 0;\
02437         rb_warning("invalid start is ignored");\
02438     }\
02439 }
02440 
02441 static VALUE
02442 valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02443 {
02444     double sg = NUM2DBL(argv[1]);
02445     valid_sg(sg);
02446     return argv[0];
02447 }
02448 
02449 #ifndef NDEBUG
02450 static VALUE
02451 date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass)
02452 {
02453     VALUE vjd, vsg;
02454     VALUE argv2[2];
02455 
02456     rb_scan_args(argc, argv, "11", &vjd, &vsg);
02457 
02458     argv2[0] = vjd;
02459     if (argc < 2)
02460         argv2[1] = DBL2NUM(GREGORIAN);
02461     else
02462         argv2[1] = vsg;
02463 
02464     return valid_jd_sub(2, argv2, klass, 1);
02465 }
02466 #endif
02467 
02468 /*
02469  * call-seq:
02470  *    Date.valid_jd?(jd[, start=Date::ITALY])  ->  bool
02471  *
02472  * Just returns true.  It's nonsense, but is for symmetry.
02473  *
02474  *    Date.valid_jd?(2451944)           #=> true
02475  *
02476  * See also jd.
02477  */
02478 static VALUE
02479 date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass)
02480 {
02481     VALUE vjd, vsg;
02482     VALUE argv2[2];
02483 
02484     rb_scan_args(argc, argv, "11", &vjd, &vsg);
02485 
02486     argv2[0] = vjd;
02487     if (argc < 2)
02488         argv2[1] = INT2FIX(DEFAULT_SG);
02489     else
02490         argv2[1] = vsg;
02491 
02492     if (NIL_P(valid_jd_sub(2, argv2, klass, 0)))
02493         return Qfalse;
02494     return Qtrue;
02495 }
02496 
02497 static VALUE
02498 valid_civil_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02499 {
02500     VALUE nth, y;
02501     int m, d, ry, rm, rd;
02502     double sg;
02503 
02504     y = argv[0];
02505     m = NUM2INT(argv[1]);
02506     d = NUM2INT(argv[2]);
02507     sg = NUM2DBL(argv[3]);
02508 
02509     valid_sg(sg);
02510 
02511     if (!need_jd && (guess_style(y, sg) < 0)) {
02512         if (!valid_gregorian_p(y, m, d,
02513                                &nth, &ry,
02514                                &rm, &rd))
02515             return Qnil;
02516         return INT2FIX(0); /* dummy */
02517     }
02518     else {
02519         int rjd, ns;
02520         VALUE rjd2;
02521 
02522         if (!valid_civil_p(y, m, d, sg,
02523                            &nth, &ry,
02524                            &rm, &rd, &rjd,
02525                            &ns))
02526             return Qnil;
02527         if (!need_jd)
02528             return INT2FIX(0); /* dummy */
02529         encode_jd(nth, rjd, &rjd2);
02530         return rjd2;
02531     }
02532 }
02533 
02534 #ifndef NDEBUG
02535 static VALUE
02536 date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
02537 {
02538     VALUE vy, vm, vd, vsg;
02539     VALUE argv2[4];
02540 
02541     rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg);
02542 
02543     argv2[0] = vy;
02544     argv2[1] = vm;
02545     argv2[2] = vd;
02546     if (argc < 4)
02547         argv2[3] = DBL2NUM(GREGORIAN);
02548     else
02549         argv2[3] = vsg;
02550 
02551     return valid_civil_sub(4, argv2, klass, 1);
02552 }
02553 #endif
02554 
02555 /*
02556  * call-seq:
02557  *    Date.valid_civil?(year, month, mday[, start=Date::ITALY])  ->  bool
02558  *    Date.valid_date?(year, month, mday[, start=Date::ITALY])   ->  bool
02559  *
02560  * Returns true if the given calendar date is valid, and false if not.
02561  *
02562  *    Date.valid_date?(2001,2,3)        #=> true
02563  *    Date.valid_date?(2001,2,29)       #=> false
02564  *
02565  * See also jd and civil.
02566  */
02567 static VALUE
02568 date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass)
02569 {
02570     VALUE vy, vm, vd, vsg;
02571     VALUE argv2[4];
02572 
02573     rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg);
02574 
02575     argv2[0] = vy;
02576     argv2[1] = vm;
02577     argv2[2] = vd;
02578     if (argc < 4)
02579         argv2[3] = INT2FIX(DEFAULT_SG);
02580     else
02581         argv2[3] = vsg;
02582 
02583     if (NIL_P(valid_civil_sub(4, argv2, klass, 0)))
02584         return Qfalse;
02585     return Qtrue;
02586 }
02587 
02588 static VALUE
02589 valid_ordinal_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02590 {
02591     VALUE nth, y;
02592     int d, ry, rd;
02593     double sg;
02594 
02595     y = argv[0];
02596     d = NUM2INT(argv[1]);
02597     sg = NUM2DBL(argv[2]);
02598 
02599     valid_sg(sg);
02600 
02601     {
02602         int rjd, ns;
02603         VALUE rjd2;
02604 
02605         if (!valid_ordinal_p(y, d, sg,
02606                              &nth, &ry,
02607                              &rd, &rjd,
02608                              &ns))
02609             return Qnil;
02610         if (!need_jd)
02611             return INT2FIX(0); /* dummy */
02612         encode_jd(nth, rjd, &rjd2);
02613         return rjd2;
02614     }
02615 }
02616 
02617 #ifndef NDEBUG
02618 static VALUE
02619 date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
02620 {
02621     VALUE vy, vd, vsg;
02622     VALUE argv2[3];
02623 
02624     rb_scan_args(argc, argv, "21", &vy, &vd, &vsg);
02625 
02626     argv2[0] = vy;
02627     argv2[1] = vd;
02628     if (argc < 3)
02629         argv2[2] = DBL2NUM(GREGORIAN);
02630     else
02631         argv2[2] = vsg;
02632 
02633     return valid_ordinal_sub(3, argv2, klass, 1);
02634 }
02635 #endif
02636 
02637 /*
02638  * call-seq:
02639  *    Date.valid_ordinal?(year, yday[, start=Date::ITALY])  ->  bool
02640  *
02641  * Returns true if the given ordinal date is valid, and false if not.
02642  *
02643  *    Date.valid_ordinal?(2001,34)      #=> true
02644  *    Date.valid_ordinal?(2001,366)     #=> false
02645  *
02646  * See also jd and ordinal.
02647  */
02648 static VALUE
02649 date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
02650 {
02651     VALUE vy, vd, vsg;
02652     VALUE argv2[3];
02653 
02654     rb_scan_args(argc, argv, "21", &vy, &vd, &vsg);
02655 
02656     argv2[0] = vy;
02657     argv2[1] = vd;
02658     if (argc < 3)
02659         argv2[2] = INT2FIX(DEFAULT_SG);
02660     else
02661         argv2[2] = vsg;
02662 
02663     if (NIL_P(valid_ordinal_sub(3, argv2, klass, 0)))
02664         return Qfalse;
02665     return Qtrue;
02666 }
02667 
02668 static VALUE
02669 valid_commercial_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02670 {
02671     VALUE nth, y;
02672     int w, d, ry, rw, rd;
02673     double sg;
02674 
02675     y = argv[0];
02676     w = NUM2INT(argv[1]);
02677     d = NUM2INT(argv[2]);
02678     sg = NUM2DBL(argv[3]);
02679 
02680     valid_sg(sg);
02681 
02682     {
02683         int rjd, ns;
02684         VALUE rjd2;
02685 
02686         if (!valid_commercial_p(y, w, d, sg,
02687                                 &nth, &ry,
02688                                 &rw, &rd, &rjd,
02689                                 &ns))
02690             return Qnil;
02691         if (!need_jd)
02692             return INT2FIX(0); /* dummy */
02693         encode_jd(nth, rjd, &rjd2);
02694         return rjd2;
02695     }
02696 }
02697 
02698 #ifndef NDEBUG
02699 static VALUE
02700 date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass)
02701 {
02702     VALUE vy, vw, vd, vsg;
02703     VALUE argv2[4];
02704 
02705     rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg);
02706 
02707     argv2[0] = vy;
02708     argv2[1] = vw;
02709     argv2[2] = vd;
02710     if (argc < 4)
02711         argv2[3] = DBL2NUM(GREGORIAN);
02712     else
02713         argv2[3] = vsg;
02714 
02715     return valid_commercial_sub(4, argv2, klass, 1);
02716 }
02717 #endif
02718 
02719 /*
02720  * call-seq:
02721  *    Date.valid_commercial?(cwyear, cweek, cwday[, start=Date::ITALY])  ->  bool
02722  *
02723  * Returns true if the given week date is valid, and false if not.
02724  *
02725  *    Date.valid_commercial?(2001,5,6)  #=> true
02726  *    Date.valid_commercial?(2001,5,8)  #=> false
02727  *
02728  * See also jd and commercial.
02729  */
02730 static VALUE
02731 date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass)
02732 {
02733     VALUE vy, vw, vd, vsg;
02734     VALUE argv2[4];
02735 
02736     rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg);
02737 
02738     argv2[0] = vy;
02739     argv2[1] = vw;
02740     argv2[2] = vd;
02741     if (argc < 4)
02742         argv2[3] = INT2FIX(DEFAULT_SG);
02743     else
02744         argv2[3] = vsg;
02745 
02746     if (NIL_P(valid_commercial_sub(4, argv2, klass, 0)))
02747         return Qfalse;
02748     return Qtrue;
02749 }
02750 
02751 #ifndef NDEBUG
02752 static VALUE
02753 valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02754 {
02755     VALUE nth, y;
02756     int w, d, f, ry, rw, rd;
02757     double sg;
02758 
02759     y = argv[0];
02760     w = NUM2INT(argv[1]);
02761     d = NUM2INT(argv[2]);
02762     f = NUM2INT(argv[3]);
02763     sg = NUM2DBL(argv[4]);
02764 
02765     valid_sg(sg);
02766 
02767     {
02768         int rjd, ns;
02769         VALUE rjd2;
02770 
02771         if (!valid_weeknum_p(y, w, d, f, sg,
02772                              &nth, &ry,
02773                              &rw, &rd, &rjd,
02774                              &ns))
02775             return Qnil;
02776         if (!need_jd)
02777             return INT2FIX(0); /* dummy */
02778         encode_jd(nth, rjd, &rjd2);
02779         return rjd2;
02780     }
02781 }
02782 
02783 static VALUE
02784 date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass)
02785 {
02786     VALUE vy, vw, vd, vf, vsg;
02787     VALUE argv2[5];
02788 
02789     rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg);
02790 
02791     argv2[0] = vy;
02792     argv2[1] = vw;
02793     argv2[2] = vd;
02794     argv2[3] = vf;
02795     if (argc < 5)
02796         argv2[4] = DBL2NUM(GREGORIAN);
02797     else
02798         argv2[4] = vsg;
02799 
02800     return valid_weeknum_sub(5, argv2, klass, 1);
02801 }
02802 
02803 static VALUE
02804 date_s_valid_weeknum_p(int argc, VALUE *argv, VALUE klass)
02805 {
02806     VALUE vy, vw, vd, vf, vsg;
02807     VALUE argv2[5];
02808 
02809     rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg);
02810 
02811     argv2[0] = vy;
02812     argv2[1] = vw;
02813     argv2[2] = vd;
02814     argv2[3] = vf;
02815     if (argc < 5)
02816         argv2[4] = INT2FIX(DEFAULT_SG);
02817     else
02818         argv2[4] = vsg;
02819 
02820     if (NIL_P(valid_weeknum_sub(5, argv2, klass, 0)))
02821         return Qfalse;
02822     return Qtrue;
02823 }
02824 
02825 static VALUE
02826 valid_nth_kday_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
02827 {
02828     VALUE nth, y;
02829     int m, n, k, ry, rm, rn, rk;
02830     double sg;
02831 
02832     y = argv[0];
02833     m = NUM2INT(argv[1]);
02834     n = NUM2INT(argv[2]);
02835     k = NUM2INT(argv[3]);
02836     sg = NUM2DBL(argv[4]);
02837 
02838     {
02839         int rjd, ns;
02840         VALUE rjd2;
02841 
02842         if (!valid_nth_kday_p(y, m, n, k, sg,
02843                               &nth, &ry,
02844                               &rm, &rn, &rk, &rjd,
02845                               &ns))
02846             return Qnil;
02847         if (!need_jd)
02848             return INT2FIX(0); /* dummy */
02849         encode_jd(nth, rjd, &rjd2);
02850         return rjd2;
02851     }
02852 }
02853 
02854 static VALUE
02855 date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass)
02856 {
02857     VALUE vy, vm, vn, vk, vsg;
02858     VALUE argv2[5];
02859 
02860     rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg);
02861 
02862     argv2[0] = vy;
02863     argv2[1] = vm;
02864     argv2[2] = vn;
02865     argv2[3] = vk;
02866     if (argc < 5)
02867         argv2[4] = DBL2NUM(GREGORIAN);
02868     else
02869         argv2[4] = vsg;
02870 
02871     return valid_nth_kday_sub(5, argv2, klass, 1);
02872 }
02873 
02874 static VALUE
02875 date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass)
02876 {
02877     VALUE vy, vm, vn, vk, vsg;
02878     VALUE argv2[5];
02879 
02880     rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg);
02881 
02882     argv2[0] = vy;
02883     argv2[1] = vm;
02884     argv2[2] = vn;
02885     argv2[3] = vk;
02886     if (argc < 5)
02887         argv2[4] = INT2FIX(DEFAULT_SG);
02888     else
02889         argv2[4] = vsg;
02890 
02891     if (NIL_P(valid_nth_kday_sub(5, argv2, klass, 0)))
02892         return Qfalse;
02893     return Qtrue;
02894 }
02895 
02896 static VALUE
02897 date_s_zone_to_diff(VALUE klass, VALUE str)
02898 {
02899     return date_zone_to_diff(str);
02900 }
02901 #endif
02902 
02903 /*
02904  * call-seq:
02905  *    Date.julian_leap?(year)  ->  bool
02906  *
02907  * Returns true if the given year is a leap year of the proleptic
02908  * Julian calendar.
02909  *
02910  *    Date.julian_leap?(1900)           #=> true
02911  *    Date.julian_leap?(1901)           #=> false
02912  */
02913 static VALUE
02914 date_s_julian_leap_p(VALUE klass, VALUE y)
02915 {
02916     VALUE nth;
02917     int ry;
02918 
02919     decode_year(y, +1, &nth, &ry);
02920     return f_boolcast(c_julian_leap_p(ry));
02921 }
02922 
02923 /*
02924  * call-seq:
02925  *    Date.gregorian_leap?(year)  ->  bool
02926  *    Date.leap?(year)            ->  bool
02927  *
02928  * Returns true if the given year is a leap year of the proleptic
02929  * Gregorian calendar.
02930  *
02931  *    Date.gregorian_leap?(1900)        #=> false
02932  *    Date.gregorian_leap?(2000)        #=> true
02933  */
02934 static VALUE
02935 date_s_gregorian_leap_p(VALUE klass, VALUE y)
02936 {
02937     VALUE nth;
02938     int ry;
02939 
02940     decode_year(y, -1, &nth, &ry);
02941     return f_boolcast(c_gregorian_leap_p(ry));
02942 }
02943 
02944 static void
02945 d_lite_gc_mark(union DateData *dat)
02946 {
02947     if (simple_dat_p(dat))
02948         rb_gc_mark(dat->s.nth);
02949     else {
02950         rb_gc_mark(dat->c.nth);
02951         rb_gc_mark(dat->c.sf);
02952 
02953     }
02954 }
02955 
02956 inline static VALUE
02957 d_simple_new_internal(VALUE klass,
02958                       VALUE nth, int jd,
02959                       double sg,
02960                       int y, int m, int d,
02961                       unsigned flags)
02962 {
02963     struct SimpleDateData *dat;
02964     VALUE obj;
02965 
02966     obj = Data_Make_Struct(klass, struct SimpleDateData,
02967                            d_lite_gc_mark, -1, dat);
02968     set_to_simple(dat, nth, jd, sg, y, m, d, flags & ~COMPLEX_DAT);
02969 
02970     assert(have_jd_p(dat) || have_civil_p(dat));
02971 
02972     return obj;
02973 }
02974 
02975 inline static VALUE
02976 d_complex_new_internal(VALUE klass,
02977                        VALUE nth, int jd,
02978                        int df, VALUE sf,
02979                        int of, double sg,
02980                        int y, int m, int d,
02981                        int h, int min, int s,
02982                        unsigned flags)
02983 {
02984     struct ComplexDateData *dat;
02985     VALUE obj;
02986 
02987     obj = Data_Make_Struct(klass, struct ComplexDateData,
02988                            d_lite_gc_mark, -1, dat);
02989     set_to_complex(dat, nth, jd, df, sf, of, sg,
02990                    y, m, d, h, min, s, flags | COMPLEX_DAT);
02991 
02992     assert(have_jd_p(dat) || have_civil_p(dat));
02993     assert(have_df_p(dat) || have_time_p(dat));
02994 
02995     return obj;
02996 }
02997 
02998 static VALUE
02999 d_lite_s_alloc_simple(VALUE klass)
03000 {
03001     return d_simple_new_internal(klass,
03002                                  INT2FIX(0), 0,
03003                                  DEFAULT_SG,
03004                                  0, 0, 0,
03005                                  HAVE_JD);
03006 }
03007 
03008 static VALUE
03009 d_lite_s_alloc_complex(VALUE klass)
03010 {
03011     return d_complex_new_internal(klass,
03012                                   INT2FIX(0), 0,
03013                                   0, INT2FIX(0),
03014                                   0, DEFAULT_SG,
03015                                   0, 0, 0,
03016                                   0, 0, 0,
03017                                   HAVE_JD | HAVE_DF);
03018 }
03019 
03020 static VALUE
03021 d_lite_s_alloc(VALUE klass)
03022 {
03023     return d_lite_s_alloc_complex(klass);
03024 }
03025 
03026 static void
03027 old_to_new(VALUE ajd, VALUE of, VALUE sg,
03028            VALUE *rnth, int *rjd, int *rdf, VALUE *rsf,
03029            int *rof, double *rsg)
03030 {
03031     VALUE jd, df, sf, of2, t;
03032 
03033     decode_day(f_add(ajd, half_days_in_day),
03034                &jd, &df, &sf);
03035     t = day_to_sec(of);
03036     of2 = f_round(t);
03037 
03038     if (!f_eqeq_p(of2, t))
03039         rb_warning("fraction of offset is ignored");
03040 
03041     decode_jd(jd, rnth, rjd);
03042 
03043     *rdf = NUM2INT(df);
03044     *rsf = sf;
03045     *rof = NUM2INT(of2);
03046     *rsg = NUM2DBL(sg);
03047 
03048     if (*rdf < 0 || *rdf >= DAY_IN_SECONDS)
03049         rb_raise(rb_eArgError, "invalid day fraction");
03050 
03051     if (f_lt_p(*rsf, INT2FIX(0)) ||
03052         f_ge_p(*rsf, INT2FIX(SECOND_IN_NANOSECONDS)))
03053 
03054     if (*rof < -DAY_IN_SECONDS || *rof > DAY_IN_SECONDS) {
03055         *rof = 0;
03056         rb_warning("invalid offset is ignored");
03057     }
03058 
03059     if (!c_valid_start_p(*rsg)) {
03060         *rsg = DEFAULT_SG;
03061         rb_warning("invalid start is ignored");
03062     }
03063 }
03064 
03065 #ifndef NDEBUG
03066 static VALUE
03067 date_s_new_bang(int argc, VALUE *argv, VALUE klass)
03068 {
03069     VALUE ajd, of, sg, nth, sf;
03070     int jd, df, rof;
03071     double rsg;
03072 
03073     rb_scan_args(argc, argv, "03", &ajd, &of, &sg);
03074 
03075     switch (argc) {
03076       case 0:
03077         ajd = INT2FIX(0);
03078       case 1:
03079         of = INT2FIX(0);
03080       case 2:
03081         sg = INT2FIX(DEFAULT_SG);
03082     }
03083 
03084     old_to_new(ajd, of, sg,
03085                &nth, &jd, &df, &sf, &rof, &rsg);
03086 
03087     if (!df && f_zero_p(sf) && !rof)
03088         return d_simple_new_internal(klass,
03089                                      nth, jd,
03090                                      rsg,
03091                                      0, 0, 0,
03092                                      HAVE_JD);
03093     else
03094         return d_complex_new_internal(klass,
03095                                       nth, jd,
03096                                       df, sf,
03097                                       rof, rsg,
03098                                       0, 0, 0,
03099                                       0, 0, 0,
03100                                       HAVE_JD | HAVE_DF);
03101 }
03102 #endif
03103 
03104 inline static int
03105 wholenum_p(VALUE x)
03106 {
03107     if (FIXNUM_P(x))
03108         return 1;
03109     switch (TYPE(x)) {
03110       case T_BIGNUM:
03111         return 1;
03112       case T_FLOAT:
03113         {
03114             double d = RFLOAT_VALUE(x);
03115             return round(d) == d;
03116         }
03117         break;
03118       case T_RATIONAL:
03119         {
03120             VALUE den = RRATIONAL(x)->den;
03121             return FIXNUM_P(den) && FIX2LONG(den) == 1;
03122         }
03123         break;
03124     }
03125     return 0;
03126 }
03127 
03128 inline static VALUE
03129 to_integer(VALUE x)
03130 {
03131     if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM))
03132         return x;
03133     return f_to_i(x);
03134 }
03135 
03136 inline static VALUE
03137 d_trunc(VALUE d, VALUE *fr)
03138 {
03139     VALUE rd;
03140 
03141     if (wholenum_p(d)) {
03142         rd = to_integer(d);
03143         *fr = INT2FIX(0);
03144     }
03145     else {
03146         rd = f_idiv(d, INT2FIX(1));
03147         *fr = f_mod(d, INT2FIX(1));
03148     }
03149     return rd;
03150 }
03151 
03152 #define jd_trunc d_trunc
03153 #define k_trunc d_trunc
03154 
03155 inline static VALUE
03156 h_trunc(VALUE h, VALUE *fr)
03157 {
03158     VALUE rh;
03159 
03160     if (wholenum_p(h)) {
03161         rh = to_integer(h);
03162         *fr = INT2FIX(0);
03163     }
03164     else {
03165         rh = f_idiv(h, INT2FIX(1));
03166         *fr = f_mod(h, INT2FIX(1));
03167         *fr = f_quo(*fr, INT2FIX(24));
03168     }
03169     return rh;
03170 }
03171 
03172 inline static VALUE
03173 min_trunc(VALUE min, VALUE *fr)
03174 {
03175     VALUE rmin;
03176 
03177     if (wholenum_p(min)) {
03178         rmin = to_integer(min);
03179         *fr = INT2FIX(0);
03180     }
03181     else {
03182         rmin = f_idiv(min, INT2FIX(1));
03183         *fr = f_mod(min, INT2FIX(1));
03184         *fr = f_quo(*fr, INT2FIX(1440));
03185     }
03186     return rmin;
03187 }
03188 
03189 inline static VALUE
03190 s_trunc(VALUE s, VALUE *fr)
03191 {
03192     VALUE rs;
03193 
03194     if (wholenum_p(s)) {
03195         rs = to_integer(s);
03196         *fr = INT2FIX(0);
03197     }
03198     else {
03199         rs = f_idiv(s, INT2FIX(1));
03200         *fr = f_mod(s, INT2FIX(1));
03201         *fr = f_quo(*fr, INT2FIX(86400));
03202     }
03203     return rs;
03204 }
03205 
03206 #define num2num_with_frac(s,n) \
03207 {\
03208     s = s##_trunc(v##s, &fr);\
03209     if (f_nonzero_p(fr)) {\
03210         if (argc > n)\
03211             rb_raise(rb_eArgError, "invalid fraction");\
03212         fr2 = fr;\
03213     }\
03214 }
03215 
03216 #define num2int_with_frac(s,n) \
03217 {\
03218     s = NUM2INT(s##_trunc(v##s, &fr));\
03219     if (f_nonzero_p(fr)) {\
03220         if (argc > n)\
03221             rb_raise(rb_eArgError, "invalid fraction");\
03222         fr2 = fr;\
03223     }\
03224 }
03225 
03226 #define canon24oc() \
03227 {\
03228     if (rh == 24) {\
03229         rh = 0;\
03230         fr2 = f_add(fr2, INT2FIX(1));\
03231     }\
03232 }
03233 
03234 #define add_frac() \
03235 {\
03236     if (f_nonzero_p(fr2))\
03237         ret = d_lite_plus(ret, fr2);\
03238 }
03239 
03240 #define val2sg(vsg,dsg) \
03241 {\
03242     dsg = NUM2DBL(vsg);\
03243     if (!c_valid_start_p(dsg)) {\
03244         dsg = DEFAULT_SG;\
03245         rb_warning("invalid start is ignored");\
03246     }\
03247 }
03248 
03249 static VALUE d_lite_plus(VALUE, VALUE);
03250 
03251 /*
03252  * call-seq:
03253  *    Date.jd([jd=0[, start=Date::ITALY]])  ->  date
03254  *
03255  * Creates a date object denoting the given chronological Julian day
03256  * number.
03257  *
03258  *    Date.jd(2451944)          #=> #<Date: 2001-02-03 ...>
03259  *    Date.jd(2451945)          #=> #<Date: 2001-02-04 ...>
03260  *    Date.jd(0)                #=> #<Date: -4712-01-01 ...>
03261  *
03262  * See also new.
03263  */
03264 static VALUE
03265 date_s_jd(int argc, VALUE *argv, VALUE klass)
03266 {
03267     VALUE vjd, vsg, jd, fr, fr2, ret;
03268     double sg;
03269 
03270     rb_scan_args(argc, argv, "02", &vjd, &vsg);
03271 
03272     jd = INT2FIX(0);
03273     fr2 = INT2FIX(0);
03274     sg = DEFAULT_SG;
03275 
03276     switch (argc) {
03277       case 2:
03278         val2sg(vsg, sg);
03279       case 1:
03280         num2num_with_frac(jd, positive_inf);
03281     }
03282 
03283     {
03284         VALUE nth;
03285         int rjd;
03286 
03287         decode_jd(jd, &nth, &rjd);
03288         ret = d_simple_new_internal(klass,
03289                                     nth, rjd,
03290                                     sg,
03291                                     0, 0, 0,
03292                                     HAVE_JD);
03293     }
03294     add_frac();
03295     return ret;
03296 }
03297 
03298 /*
03299  * call-seq:
03300  *    Date.ordinal([year=-4712[, yday=1[, start=Date::ITALY]]])  ->  date
03301  *
03302  * Creates a date object denoting the given ordinal date.
03303  *
03304  * The day of year should be a negative or a positive number (as a
03305  * relative day from the end of year when negative).  It should not be
03306  * zero.
03307  *
03308  *    Date.ordinal(2001)        #=> #<Date: 2001-01-01 ...>
03309  *    Date.ordinal(2001,34)     #=> #<Date: 2001-02-03 ...>
03310  *    Date.ordinal(2001,-1)     #=> #<Date: 2001-12-31 ...>
03311  *
03312  * See also jd and new.
03313  */
03314 static VALUE
03315 date_s_ordinal(int argc, VALUE *argv, VALUE klass)
03316 {
03317     VALUE vy, vd, vsg, y, fr, fr2, ret;
03318     int d;
03319     double sg;
03320 
03321     rb_scan_args(argc, argv, "03", &vy, &vd, &vsg);
03322 
03323     y = INT2FIX(-4712);
03324     d = 1;
03325     fr2 = INT2FIX(0);
03326     sg = DEFAULT_SG;
03327 
03328     switch (argc) {
03329       case 3:
03330         val2sg(vsg, sg);
03331       case 2:
03332         num2int_with_frac(d, positive_inf);
03333       case 1:
03334         y = vy;
03335     }
03336 
03337     {
03338         VALUE nth;
03339         int ry, rd, rjd, ns;
03340 
03341         if (!valid_ordinal_p(y, d, sg,
03342                              &nth, &ry,
03343                              &rd, &rjd,
03344                              &ns))
03345             rb_raise(rb_eArgError, "invalid date");
03346 
03347         ret = d_simple_new_internal(klass,
03348                                      nth, rjd,
03349                                      sg,
03350                                      0, 0, 0,
03351                                      HAVE_JD);
03352     }
03353     add_frac();
03354     return ret;
03355 }
03356 
03357 /*
03358  * call-seq:
03359  *    Date.civil([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]])  ->  date
03360  *    Date.new([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]])    ->  date
03361  *
03362  * Creates a date object denoting the given calendar date.
03363  *
03364  * In this class, BCE years are counted astronomically.  Thus, the
03365  * year before the year 1 is the year zero, and the year preceding the
03366  * year zero is the year -1.  The month and the day of month should be
03367  * a negative or a positive number (as a relative month/day from the
03368  * end of year/month when negative).  They should not be zero.
03369  *
03370  * The last argument should be a Julian day number which denotes the
03371  * day of calendar reform.  Date::ITALY (2299161=1582-10-15),
03372  * Date::ENGLAND (2361222=1752-09-14), Date::GREGORIAN (the proleptic
03373  * Gregorian calendar) and Date::JULIAN (the proleptic Julian
03374  * calendar) can be specified as a day of calendar reform.
03375  *
03376  *    Date.new(2001)            #=> #<Date: 2001-01-01 ...>
03377  *    Date.new(2001,2,3)        #=> #<Date: 2001-02-03 ...>
03378  *    Date.new(2001,2,-1)       #=> #<Date: 2001-02-28 ...>
03379  *
03380  * See also jd.
03381  */
03382 static VALUE
03383 date_s_civil(int argc, VALUE *argv, VALUE klass)
03384 {
03385     VALUE vy, vm, vd, vsg, y, fr, fr2, ret;
03386     int m, d;
03387     double sg;
03388 
03389     rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg);
03390 
03391     y = INT2FIX(-4712);
03392     m = 1;
03393     d = 1;
03394     fr2 = INT2FIX(0);
03395     sg = DEFAULT_SG;
03396 
03397     switch (argc) {
03398       case 4:
03399         val2sg(vsg, sg);
03400       case 3:
03401         num2int_with_frac(d, positive_inf);
03402       case 2:
03403         m = NUM2INT(vm);
03404       case 1:
03405         y = vy;
03406     }
03407 
03408     if (guess_style(y, sg) < 0) {
03409         VALUE nth;
03410         int ry, rm, rd;
03411 
03412         if (!valid_gregorian_p(y, m, d,
03413                                &nth, &ry,
03414                                &rm, &rd))
03415             rb_raise(rb_eArgError, "invalid date");
03416 
03417         ret = d_simple_new_internal(klass,
03418                                     nth, 0,
03419                                     sg,
03420                                     ry, rm, rd,
03421                                     HAVE_CIVIL);
03422     }
03423     else {
03424         VALUE nth;
03425         int ry, rm, rd, rjd, ns;
03426 
03427         if (!valid_civil_p(y, m, d, sg,
03428                            &nth, &ry,
03429                            &rm, &rd, &rjd,
03430                            &ns))
03431             rb_raise(rb_eArgError, "invalid date");
03432 
03433         ret = d_simple_new_internal(klass,
03434                                     nth, rjd,
03435                                     sg,
03436                                     ry, rm, rd,
03437                                     HAVE_JD | HAVE_CIVIL);
03438     }
03439     add_frac();
03440     return ret;
03441 }
03442 
03443 /*
03444  * call-seq:
03445  *    Date.commercial([cwyear=-4712[, cweek=1[, cwday=1[, start=Date::ITALY]]]])  ->  date
03446  *
03447  * Creates a date object denoting the given week date.
03448  *
03449  * The week and the day of week should be a negative or a positive
03450  * number (as a relative week/day from the end of year/week when
03451  * negative).  They should not be zero.
03452  *
03453  *    Date.commercial(2001)     #=> #<Date: 2001-01-01 ...>
03454  *    Date.commercial(2002)     #=> #<Date: 2001-12-31 ...>
03455  *    Date.commercial(2001,5,6) #=> #<Date: 2001-02-03 ...>
03456  *
03457  * See also jd and new.
03458  */
03459 static VALUE
03460 date_s_commercial(int argc, VALUE *argv, VALUE klass)
03461 {
03462     VALUE vy, vw, vd, vsg, y, fr, fr2, ret;
03463     int w, d;
03464     double sg;
03465 
03466     rb_scan_args(argc, argv, "04", &vy, &vw, &vd, &vsg);
03467 
03468     y = INT2FIX(-4712);
03469     w = 1;
03470     d = 1;
03471     fr2 = INT2FIX(0);
03472     sg = DEFAULT_SG;
03473 
03474     switch (argc) {
03475       case 4:
03476         val2sg(vsg, sg);
03477       case 3:
03478         num2int_with_frac(d, positive_inf);
03479       case 2:
03480         w = NUM2INT(vw);
03481       case 1:
03482         y = vy;
03483     }
03484 
03485     {
03486         VALUE nth;
03487         int ry, rw, rd, rjd, ns;
03488 
03489         if (!valid_commercial_p(y, w, d, sg,
03490                                 &nth, &ry,
03491                                 &rw, &rd, &rjd,
03492                                 &ns))
03493             rb_raise(rb_eArgError, "invalid date");
03494 
03495         ret = d_simple_new_internal(klass,
03496                                     nth, rjd,
03497                                     sg,
03498                                     0, 0, 0,
03499                                     HAVE_JD);
03500     }
03501     add_frac();
03502     return ret;
03503 }
03504 
03505 #ifndef NDEBUG
03506 static VALUE
03507 date_s_weeknum(int argc, VALUE *argv, VALUE klass)
03508 {
03509     VALUE vy, vw, vd, vf, vsg, y, fr, fr2, ret;
03510     int w, d, f;
03511     double sg;
03512 
03513     rb_scan_args(argc, argv, "05", &vy, &vw, &vd, &vf, &vsg);
03514 
03515     y = INT2FIX(-4712);
03516     w = 0;
03517     d = 1;
03518     f = 0;
03519     fr2 = INT2FIX(0);
03520     sg = DEFAULT_SG;
03521 
03522     switch (argc) {
03523       case 5:
03524         val2sg(vsg, sg);
03525       case 4:
03526         f = NUM2INT(vf);
03527       case 3:
03528         num2int_with_frac(d, positive_inf);
03529       case 2:
03530         w = NUM2INT(vw);
03531       case 1:
03532         y = vy;
03533     }
03534 
03535     {
03536         VALUE nth;
03537         int ry, rw, rd, rjd, ns;
03538 
03539         if (!valid_weeknum_p(y, w, d, f, sg,
03540                              &nth, &ry,
03541                              &rw, &rd, &rjd,
03542                              &ns))
03543             rb_raise(rb_eArgError, "invalid date");
03544 
03545         ret = d_simple_new_internal(klass,
03546                                     nth, rjd,
03547                                     sg,
03548                                     0, 0, 0,
03549                                     HAVE_JD);
03550     }
03551     add_frac();
03552     return ret;
03553 }
03554 
03555 static VALUE
03556 date_s_nth_kday(int argc, VALUE *argv, VALUE klass)
03557 {
03558     VALUE vy, vm, vn, vk, vsg, y, fr, fr2, ret;
03559     int m, n, k;
03560     double sg;
03561 
03562     rb_scan_args(argc, argv, "05", &vy, &vm, &vn, &vk, &vsg);
03563 
03564     y = INT2FIX(-4712);
03565     m = 1;
03566     n = 1;
03567     k = 1;
03568     fr2 = INT2FIX(0);
03569     sg = DEFAULT_SG;
03570 
03571     switch (argc) {
03572       case 5:
03573         val2sg(vsg, sg);
03574       case 4:
03575         num2int_with_frac(k, positive_inf);
03576       case 3:
03577         n = NUM2INT(vn);
03578       case 2:
03579         m = NUM2INT(vm);
03580       case 1:
03581         y = vy;
03582     }
03583 
03584     {
03585         VALUE nth;
03586         int ry, rm, rn, rk, rjd, ns;
03587 
03588         if (!valid_nth_kday_p(y, m, n, k, sg,
03589                               &nth, &ry,
03590                               &rm, &rn, &rk, &rjd,
03591                               &ns))
03592             rb_raise(rb_eArgError, "invalid date");
03593 
03594         ret = d_simple_new_internal(klass,
03595                                     nth, rjd,
03596                                     sg,
03597                                     0, 0, 0,
03598                                     HAVE_JD);
03599     }
03600     add_frac();
03601     return ret;
03602 }
03603 #endif
03604 
03605 #if !defined(HAVE_GMTIME_R)
03606 static struct tm*
03607 gmtime_r(const time_t *t, struct tm *tm)
03608 {
03609     auto struct tm *tmp = gmtime(t);
03610     if (tmp)
03611         *tm = *tmp;
03612     return tmp;
03613 }
03614 
03615 static struct tm*
03616 localtime_r(const time_t *t, struct tm *tm)
03617 {
03618     auto struct tm *tmp = localtime(t);
03619     if (tmp)
03620         *tm = *tmp;
03621     return tmp;
03622 }
03623 #endif
03624 
03625 static void set_sg(union DateData *, double);
03626 
03627 /*
03628  * call-seq:
03629  *    Date.today([start=Date::ITALY])  ->  date
03630  *
03631  *    Date.today                #=> #<Date: 2011-06-11 ..>
03632  *
03633  * Creates a date object denoting the present day.
03634  */
03635 static VALUE
03636 date_s_today(int argc, VALUE *argv, VALUE klass)
03637 {
03638     VALUE vsg, nth, ret;
03639     double sg;
03640     time_t t;
03641     struct tm tm;
03642     int y, ry, m, d;
03643 
03644     rb_scan_args(argc, argv, "01", &vsg);
03645 
03646     if (argc < 1)
03647         sg = DEFAULT_SG;
03648     else
03649         val2sg(vsg, sg);
03650 
03651     if (time(&t) == -1)
03652         rb_sys_fail("time");
03653     tzset();
03654     if (!localtime_r(&t, &tm))
03655         rb_sys_fail("localtime");
03656 
03657     y = tm.tm_year + 1900;
03658     m = tm.tm_mon + 1;
03659     d = tm.tm_mday;
03660 
03661     decode_year(INT2FIX(y), -1, &nth, &ry);
03662 
03663     ret = d_simple_new_internal(klass,
03664                                 nth, 0,
03665                                 GREGORIAN,
03666                                 ry, m, d,
03667                                 HAVE_CIVIL);
03668     {
03669         get_d1(ret);
03670         set_sg(dat, sg);
03671     }
03672     return ret;
03673 }
03674 
03675 #define set_hash0(k,v) rb_hash_aset(hash, k, v)
03676 #define ref_hash0(k) rb_hash_aref(hash, k)
03677 #define del_hash0(k) rb_hash_delete(hash, k)
03678 
03679 #define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
03680 #define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
03681 #define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
03682 
03683 static VALUE
03684 rt_rewrite_frags(VALUE hash)
03685 {
03686     VALUE seconds;
03687 
03688     seconds = ref_hash("seconds");
03689     if (!NIL_P(seconds)) {
03690         VALUE d, h, min, s, fr;
03691 
03692         d = f_idiv(seconds, INT2FIX(DAY_IN_SECONDS));
03693         fr = f_mod(seconds, INT2FIX(DAY_IN_SECONDS));
03694 
03695         h = f_idiv(fr, INT2FIX(HOUR_IN_SECONDS));
03696         fr = f_mod(fr, INT2FIX(HOUR_IN_SECONDS));
03697 
03698         min = f_idiv(fr, INT2FIX(MINUTE_IN_SECONDS));
03699         fr = f_mod(fr, INT2FIX(MINUTE_IN_SECONDS));
03700 
03701         s = f_idiv(fr, INT2FIX(1));
03702         fr = f_mod(fr, INT2FIX(1));
03703 
03704         set_hash("jd", f_add(UNIX_EPOCH_IN_CJD, d));
03705         set_hash("hour", h);
03706         set_hash("min", min);
03707         set_hash("sec", s);
03708         set_hash("sec_fraction", fr);
03709         del_hash("seconds");
03710         del_hash("offset");
03711     }
03712     return hash;
03713 }
03714 
03715 #define sym(x) ID2SYM(rb_intern(x))
03716 
03717 static VALUE d_lite_year(VALUE);
03718 static VALUE d_lite_wday(VALUE);
03719 static VALUE d_lite_jd(VALUE);
03720 
03721 static VALUE
03722 rt_complete_frags(VALUE klass, VALUE hash)
03723 {
03724     static VALUE tab = Qnil;
03725     int g, e;
03726     VALUE k, a, d;
03727 
03728     if (NIL_P(tab)) {
03729         tab = rb_ary_new3(11,
03730                           rb_ary_new3(2,
03731                                       sym("time"),
03732                                       rb_ary_new3(3,
03733                                                   sym("hour"),
03734                                                   sym("min"),
03735                                                   sym("sec"))),
03736                           rb_ary_new3(2,
03737                                       Qnil,
03738                                       rb_ary_new3(1,
03739                                                   sym("jd"))),
03740                           rb_ary_new3(2,
03741                                       sym("ordinal"),
03742                                       rb_ary_new3(5,
03743                                                   sym("year"),
03744                                                   sym("yday"),
03745                                                   sym("hour"),
03746                                                   sym("min"),
03747                                                   sym("sec"))),
03748                           rb_ary_new3(2,
03749                                       sym("civil"),
03750                                       rb_ary_new3(6,
03751                                                   sym("year"),
03752                                                   sym("mon"),
03753                                                   sym("mday"),
03754                                                   sym("hour"),
03755                                                   sym("min"),
03756                                                   sym("sec"))),
03757                           rb_ary_new3(2,
03758                                       sym("commercial"),
03759                                       rb_ary_new3(6,
03760                                                   sym("cwyear"),
03761                                                   sym("cweek"),
03762                                                   sym("cwday"),
03763                                                   sym("hour"),
03764                                                   sym("min"),
03765                                                   sym("sec"))),
03766                           rb_ary_new3(2,
03767                                       sym("wday"),
03768                                       rb_ary_new3(4,
03769                                                   sym("wday"),
03770                                                   sym("hour"),
03771                                                   sym("min"),
03772                                                   sym("sec"))),
03773                           rb_ary_new3(2,
03774                                       sym("wnum0"),
03775                                       rb_ary_new3(6,
03776                                                   sym("year"),
03777                                                   sym("wnum0"),
03778                                                   sym("wday"),
03779                                                   sym("hour"),
03780                                                   sym("min"),
03781                                                   sym("sec"))),
03782                           rb_ary_new3(2,
03783                                       sym("wnum1"),
03784                                       rb_ary_new3(6,
03785                                                   sym("year"),
03786                                                   sym("wnum1"),
03787                                                   sym("wday"),
03788                                                   sym("hour"),
03789                                                   sym("min"),
03790                                                   sym("sec"))),
03791                           rb_ary_new3(2,
03792                                       Qnil,
03793                                       rb_ary_new3(6,
03794                                                   sym("cwyear"),
03795                                                   sym("cweek"),
03796                                                   sym("wday"),
03797                                                   sym("hour"),
03798                                                   sym("min"),
03799                                                   sym("sec"))),
03800                           rb_ary_new3(2,
03801                                       Qnil,
03802                                       rb_ary_new3(6,
03803                                                   sym("year"),
03804                                                   sym("wnum0"),
03805                                                   sym("cwday"),
03806                                                   sym("hour"),
03807                                                   sym("min"),
03808                                                   sym("sec"))),
03809                           rb_ary_new3(2,
03810                                       Qnil,
03811                                       rb_ary_new3(6,
03812                                                   sym("year"),
03813                                                   sym("wnum1"),
03814                                                   sym("cwday"),
03815                                                   sym("hour"),
03816                                                   sym("min"),
03817                                                   sym("sec"))));
03818         rb_gc_register_mark_object(tab);
03819     }
03820 
03821     {
03822         int i, eno = 0, idx = 0;
03823 
03824         for (i = 0; i < RARRAY_LENINT(tab); i++) {
03825             VALUE x, a;
03826 
03827             x = RARRAY_PTR(tab)[i];
03828             a = RARRAY_PTR(x)[1];
03829 
03830             {
03831                 int j, n = 0;
03832 
03833                 for (j = 0; j < RARRAY_LENINT(a); j++)
03834                     if (!NIL_P(ref_hash0(RARRAY_PTR(a)[j])))
03835                         n++;
03836                 if (n > eno) {
03837                     eno = n;
03838                     idx = i;
03839                 }
03840             }
03841         }
03842         if (eno == 0)
03843             g = 0;
03844         else {
03845             g = 1;
03846             k = RARRAY_PTR(RARRAY_PTR(tab)[idx])[0];
03847             a = RARRAY_PTR(RARRAY_PTR(tab)[idx])[1];
03848             e = eno;
03849         }
03850     }
03851 
03852     d = Qnil;
03853 
03854     if (g && !NIL_P(k) && (RARRAY_LENINT(a) - e)) {
03855         if (k == sym("ordinal")) {
03856             if (NIL_P(ref_hash("year"))) {
03857                 if (NIL_P(d))
03858                     d = date_s_today(0, (VALUE *)0, cDate);
03859                 set_hash("year", d_lite_year(d));
03860             }
03861             if (NIL_P(ref_hash("yday")))
03862                 set_hash("yday", INT2FIX(1));
03863         }
03864         else if (k == sym("civil")) {
03865             int i;
03866 
03867             for (i = 0; i < RARRAY_LENINT(a); i++) {
03868                 VALUE e = RARRAY_PTR(a)[i];
03869 
03870                 if (!NIL_P(ref_hash0(e)))
03871                     break;
03872                 if (NIL_P(d))
03873                     d = date_s_today(0, (VALUE *)0, cDate);
03874                 set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
03875             }
03876             if (NIL_P(ref_hash("mon")))
03877                 set_hash("mon", INT2FIX(1));
03878             if (NIL_P(ref_hash("mday")))
03879                 set_hash("mday", INT2FIX(1));
03880         }
03881         else if (k == sym("commercial")) {
03882             int i;
03883 
03884             for (i = 0; i < RARRAY_LENINT(a); i++) {
03885                 VALUE e = RARRAY_PTR(a)[i];
03886 
03887                 if (!NIL_P(ref_hash0(e)))
03888                     break;
03889                 if (NIL_P(d))
03890                     d = date_s_today(0, (VALUE *)0, cDate);
03891                 set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
03892             }
03893             if (NIL_P(ref_hash("cweek")))
03894                 set_hash("cweek", INT2FIX(1));
03895             if (NIL_P(ref_hash("cwday")))
03896                 set_hash("cwday", INT2FIX(1));
03897         }
03898         else if (k == sym("wday")) {
03899             if (NIL_P(d))
03900                 d = date_s_today(0, (VALUE *)0, cDate);
03901             set_hash("jd", d_lite_jd(f_add(f_sub(d,
03902                                                  d_lite_wday(d)),
03903                                            ref_hash("wday"))));
03904         }
03905         else if (k == sym("wnum0")) {
03906             int i;
03907 
03908             for (i = 0; i < RARRAY_LENINT(a); i++) {
03909                 VALUE e = RARRAY_PTR(a)[i];
03910 
03911                 if (!NIL_P(ref_hash0(e)))
03912                     break;
03913                 if (NIL_P(d))
03914                     d = date_s_today(0, (VALUE *)0, cDate);
03915                 set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
03916             }
03917             if (NIL_P(ref_hash("wnum0")))
03918                 set_hash("wnum0", INT2FIX(0));
03919             if (NIL_P(ref_hash("wday")))
03920                 set_hash("wday", INT2FIX(0));
03921         }
03922         else if (k == sym("wnum1")) {
03923             int i;
03924 
03925             for (i = 0; i < RARRAY_LENINT(a); i++) {
03926                 VALUE e = RARRAY_PTR(a)[i];
03927 
03928                 if (!NIL_P(ref_hash0(e)))
03929                     break;
03930                 if (NIL_P(d))
03931                     d = date_s_today(0, (VALUE *)0, cDate);
03932                 set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
03933             }
03934             if (NIL_P(ref_hash("wnum1")))
03935                 set_hash("wnum1", INT2FIX(0));
03936             if (NIL_P(ref_hash("wday")))
03937                 set_hash("wday", INT2FIX(1));
03938         }
03939     }
03940 
03941     if (g && k == sym("time")) {
03942         if (f_le_p(klass, cDateTime)) {
03943             if (NIL_P(d))
03944                 d = date_s_today(0, (VALUE *)0, cDate);
03945             if (NIL_P(ref_hash("jd")))
03946                 set_hash("jd", d_lite_jd(d));
03947         }
03948     }
03949 
03950     if (NIL_P(ref_hash("hour")))
03951         set_hash("hour", INT2FIX(0));
03952     if (NIL_P(ref_hash("min")))
03953         set_hash("min", INT2FIX(0));
03954     if (NIL_P(ref_hash("sec")))
03955         set_hash("sec", INT2FIX(0));
03956     else if (f_gt_p(ref_hash("sec"), INT2FIX(59)))
03957         set_hash("sec", INT2FIX(59));
03958 
03959     return hash;
03960 }
03961 
03962 static VALUE
03963 rt__valid_jd_p(VALUE jd, VALUE sg)
03964 {
03965     return jd;
03966 }
03967 
03968 static VALUE
03969 rt__valid_ordinal_p(VALUE y, VALUE d, VALUE sg)
03970 {
03971     VALUE nth, rjd2;
03972     int ry, rd, rjd, ns;
03973 
03974     if (!valid_ordinal_p(y, NUM2INT(d), NUM2DBL(sg),
03975                          &nth, &ry,
03976                          &rd, &rjd,
03977                          &ns))
03978         return Qnil;
03979     encode_jd(nth, rjd, &rjd2);
03980     return rjd2;
03981 }
03982 
03983 static VALUE
03984 rt__valid_civil_p(VALUE y, VALUE m, VALUE d, VALUE sg)
03985 {
03986     VALUE nth, rjd2;
03987     int ry, rm, rd, rjd, ns;
03988 
03989     if (!valid_civil_p(y, NUM2INT(m), NUM2INT(d), NUM2DBL(sg),
03990                        &nth, &ry,
03991                        &rm, &rd, &rjd,
03992                        &ns))
03993         return Qnil;
03994     encode_jd(nth, rjd, &rjd2);
03995     return rjd2;
03996 }
03997 
03998 static VALUE
03999 rt__valid_commercial_p(VALUE y, VALUE w, VALUE d, VALUE sg)
04000 {
04001     VALUE nth, rjd2;
04002     int ry, rw, rd, rjd, ns;
04003 
04004     if (!valid_commercial_p(y, NUM2INT(w), NUM2INT(d), NUM2DBL(sg),
04005                             &nth, &ry,
04006                             &rw, &rd, &rjd,
04007                             &ns))
04008         return Qnil;
04009     encode_jd(nth, rjd, &rjd2);
04010     return rjd2;
04011 }
04012 
04013 static VALUE
04014 rt__valid_weeknum_p(VALUE y, VALUE w, VALUE d, VALUE f, VALUE sg)
04015 {
04016     VALUE nth, rjd2;
04017     int ry, rw, rd, rjd, ns;
04018 
04019     if (!valid_weeknum_p(y, NUM2INT(w), NUM2INT(d), NUM2INT(f), NUM2DBL(sg),
04020                          &nth, &ry,
04021                          &rw, &rd, &rjd,
04022                          &ns))
04023         return Qnil;
04024     encode_jd(nth, rjd, &rjd2);
04025     return rjd2;
04026 }
04027 
04028 static VALUE
04029 rt__valid_date_frags_p(VALUE hash, VALUE sg)
04030 {
04031     {
04032         VALUE vjd;
04033 
04034         if (!NIL_P(vjd = ref_hash("jd"))) {
04035             VALUE jd = rt__valid_jd_p(vjd, sg);
04036             if (!NIL_P(jd))
04037                 return jd;
04038         }
04039     }
04040 
04041     {
04042         VALUE year, yday;
04043 
04044         if (!NIL_P(yday = ref_hash("yday")) &&
04045             !NIL_P(year = ref_hash("year"))) {
04046             VALUE jd = rt__valid_ordinal_p(year, yday, sg);
04047             if (!NIL_P(jd))
04048                 return jd;
04049         }
04050     }
04051 
04052     {
04053         VALUE year, mon, mday;
04054 
04055         if (!NIL_P(mday = ref_hash("mday")) &&
04056             !NIL_P(mon = ref_hash("mon")) &&
04057             !NIL_P(year = ref_hash("year"))) {
04058             VALUE jd = rt__valid_civil_p(year, mon, mday, sg);
04059             if (!NIL_P(jd))
04060                 return jd;
04061         }
04062     }
04063 
04064     {
04065         VALUE year, week, wday;
04066 
04067         wday = ref_hash("cwday");
04068         if (NIL_P(wday)) {
04069             wday = ref_hash("wday");
04070             if (!NIL_P(wday))
04071                 if (f_zero_p(wday))
04072                     wday = INT2FIX(7);
04073         }
04074 
04075         if (!NIL_P(wday) &&
04076             !NIL_P(week = ref_hash("cweek")) &&
04077             !NIL_P(year = ref_hash("cwyear"))) {
04078             VALUE jd = rt__valid_commercial_p(year, week, wday, sg);
04079             if (!NIL_P(jd))
04080                 return jd;
04081         }
04082     }
04083 
04084     {
04085         VALUE year, week, wday;
04086 
04087         wday = ref_hash("wday");
04088         if (NIL_P(wday)) {
04089             wday = ref_hash("cwday");
04090             if (!NIL_P(wday))
04091                 if (f_eqeq_p(wday, INT2FIX(7)))
04092                     wday = INT2FIX(0);
04093         }
04094 
04095         if (!NIL_P(wday) &&
04096             !NIL_P(week = ref_hash("wnum0")) &&
04097             !NIL_P(year = ref_hash("year"))) {
04098             VALUE jd = rt__valid_weeknum_p(year, week, wday, INT2FIX(0), sg);
04099             if (!NIL_P(jd))
04100                 return jd;
04101         }
04102     }
04103 
04104     {
04105         VALUE year, week, wday;
04106 
04107         wday = ref_hash("wday");
04108         if (NIL_P(wday))
04109             wday = ref_hash("cwday");
04110         if (!NIL_P(wday))
04111             wday = f_mod(f_sub(wday, INT2FIX(1)),
04112                          INT2FIX(7));
04113 
04114         if (!NIL_P(wday) &&
04115             !NIL_P(week = ref_hash("wnum1")) &&
04116             !NIL_P(year = ref_hash("year"))) {
04117             VALUE jd = rt__valid_weeknum_p(year, week, wday, INT2FIX(1), sg);
04118             if (!NIL_P(jd))
04119                 return jd;
04120         }
04121     }
04122     return Qnil;
04123 }
04124 
04125 static VALUE
04126 d_new_by_frags(VALUE klass, VALUE hash, VALUE sg)
04127 {
04128     VALUE jd;
04129 
04130     if (!c_valid_start_p(NUM2DBL(sg))) {
04131         sg = INT2FIX(DEFAULT_SG);
04132         rb_warning("invalid start is ignored");
04133     }
04134 
04135     if (NIL_P(hash))
04136         rb_raise(rb_eArgError, "invalid date");
04137 
04138     if (NIL_P(ref_hash("jd")) &&
04139         NIL_P(ref_hash("yday")) &&
04140         !NIL_P(ref_hash("year")) &&
04141         !NIL_P(ref_hash("mon")) &&
04142         !NIL_P(ref_hash("mday")))
04143         jd = rt__valid_civil_p(ref_hash("year"),
04144                                ref_hash("mon"),
04145                                ref_hash("mday"), sg);
04146     else {
04147         hash = rt_rewrite_frags(hash);
04148         hash = rt_complete_frags(klass, hash);
04149         jd = rt__valid_date_frags_p(hash, sg);
04150     }
04151 
04152     if (NIL_P(jd))
04153         rb_raise(rb_eArgError, "invalid date");
04154     {
04155         VALUE nth;
04156         int rjd;
04157 
04158         decode_jd(jd, &nth, &rjd);
04159         return d_simple_new_internal(klass,
04160                                      nth, rjd,
04161                                      NUM2DBL(sg),
04162                                      0, 0, 0,
04163                                      HAVE_JD);
04164     }
04165 }
04166 
04167 VALUE date__strptime(const char *str, size_t slen,
04168                      const char *fmt, size_t flen, VALUE hash);
04169 
04170 static VALUE
04171 date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
04172                           const char *default_fmt)
04173 {
04174     VALUE vstr, vfmt, hash;
04175     const char *str, *fmt;
04176     size_t slen, flen;
04177 
04178     rb_scan_args(argc, argv, "11", &vstr, &vfmt);
04179 
04180     StringValue(vstr);
04181     if (!rb_enc_str_asciicompat_p(vstr))
04182         rb_raise(rb_eArgError,
04183                  "string should have ASCII compatible encoding");
04184     str = RSTRING_PTR(vstr);
04185     slen = RSTRING_LEN(vstr);
04186     if (argc < 2) {
04187         fmt = default_fmt;
04188         flen = strlen(default_fmt);
04189     }
04190     else {
04191         StringValue(vfmt);
04192         if (!rb_enc_str_asciicompat_p(vfmt))
04193             rb_raise(rb_eArgError,
04194                      "format should have ASCII compatible encoding");
04195         fmt = RSTRING_PTR(vfmt);
04196         flen = RSTRING_LEN(vfmt);
04197     }
04198     hash = rb_hash_new();
04199     if (NIL_P(date__strptime(str, slen, fmt, flen, hash)))
04200         return Qnil;
04201 
04202     {
04203         VALUE zone = ref_hash("zone");
04204         VALUE left = ref_hash("leftover");
04205 
04206         if (!NIL_P(zone)) {
04207             rb_enc_copy(zone, vstr);
04208             OBJ_INFECT(zone, vstr);
04209             set_hash("zone", zone);
04210         }
04211         if (!NIL_P(left)) {
04212             rb_enc_copy(left, vstr);
04213             OBJ_INFECT(left, vstr);
04214             set_hash("leftover", left);
04215         }
04216     }
04217 
04218     return hash;
04219 }
04220 
04221 /*
04222  * call-seq:
04223  *    Date._strptime(string[, format='%F'])  ->  hash
04224  *
04225  * Parses the given representation of date and time with the given
04226  * template, and returns a hash of parsed elements.  _strptime does
04227  * not support specification of flags and width unlike strftime.
04228  *
04229  *    Date._strptime('2001-02-03', '%Y-%m-%d')
04230  *                              #=> {:year=>2001, :mon=>2, :mday=>3}
04231  *
04232  *  See also strptime(3) and strftime.
04233  */
04234 static VALUE
04235 date_s__strptime(int argc, VALUE *argv, VALUE klass)
04236 {
04237     return date_s__strptime_internal(argc, argv, klass, "%F");
04238 }
04239 
04240 /*
04241  * call-seq:
04242  *    Date.strptime([string='-4712-01-01'[, format='%F'[, start=ITALY]]])  ->  date
04243  *
04244  * Parses the given representation of date and time with the given
04245  * template, and creates a date object.  strptime does not support
04246  * specification of flags and width unlike strftime.
04247  *
04248  *    Date.strptime('2001-02-03', '%Y-%m-%d')   #=> #<Date: 2001-02-03 ...>
04249  *    Date.strptime('03-02-2001', '%d-%m-%Y')   #=> #<Date: 2001-02-03 ...>
04250  *    Date.strptime('2001-034', '%Y-%j')        #=> #<Date: 2001-02-03 ...>
04251  *    Date.strptime('2001-W05-6', '%G-W%V-%u')  #=> #<Date: 2001-02-03 ...>
04252  *    Date.strptime('2001 04 6', '%Y %U %w')    #=> #<Date: 2001-02-03 ...>
04253  *    Date.strptime('2001 05 6', '%Y %W %u')    #=> #<Date: 2001-02-03 ...>
04254  *    Date.strptime('sat3feb01', '%a%d%b%y')    #=> #<Date: 2001-02-03 ...>
04255  *
04256  * See also strptime(3) and strftime.
04257  */
04258 static VALUE
04259 date_s_strptime(int argc, VALUE *argv, VALUE klass)
04260 {
04261     VALUE str, fmt, sg;
04262 
04263     rb_scan_args(argc, argv, "03", &str, &fmt, &sg);
04264 
04265     switch (argc) {
04266       case 0:
04267         str = rb_str_new2("-4712-01-01");
04268       case 1:
04269         fmt = rb_str_new2("%F");
04270       case 2:
04271         sg = INT2FIX(DEFAULT_SG);
04272     }
04273 
04274     {
04275         VALUE argv2[2], hash;
04276 
04277         argv2[0] = str;
04278         argv2[1] = fmt;
04279         hash = date_s__strptime(2, argv2, klass);
04280         return d_new_by_frags(klass, hash, sg);
04281     }
04282 }
04283 
04284 VALUE date__parse(VALUE str, VALUE comp);
04285 
04286 static VALUE
04287 date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
04288 {
04289     VALUE vstr, vcomp, hash;
04290 
04291     rb_scan_args(argc, argv, "11", &vstr, &vcomp);
04292     StringValue(vstr);
04293     if (!rb_enc_str_asciicompat_p(vstr))
04294         rb_raise(rb_eArgError,
04295                  "string should have ASCII compatible encoding");
04296     if (argc < 2)
04297         vcomp = Qtrue;
04298 
04299     hash = date__parse(vstr, vcomp);
04300 
04301     {
04302         VALUE zone = ref_hash("zone");
04303 
04304         if (!NIL_P(zone)) {
04305             rb_enc_copy(zone, vstr);
04306             OBJ_INFECT(zone, vstr);
04307             set_hash("zone", zone);
04308         }
04309     }
04310 
04311     return hash;
04312 }
04313 
04314 /*
04315  * call-seq:
04316  *    Date._parse(string[, comp=true])  ->  hash
04317  *
04318  * Parses the given representation of date and time, and returns a
04319  * hash of parsed elements.  This method does not function as a
04320  * validator.
04321  *
04322  * If the optional second argument is true and the detected year is in
04323  * the range "00" to "99", considers the year a 2-digit form and makes
04324  * it full.
04325  *
04326  *    Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3}
04327  */
04328 static VALUE
04329 date_s__parse(int argc, VALUE *argv, VALUE klass)
04330 {
04331     return date_s__parse_internal(argc, argv, klass);
04332 }
04333 
04334 /*
04335  * call-seq:
04336  *    Date.parse(string='-4712-01-01'[, comp=true[, start=ITALY]])  ->  date
04337  *
04338  * Parses the given representation of date and time, and creates a
04339  * date object.  This method does not function as a validator.
04340  *
04341  * If the optional second argument is true and the detected year is in
04342  * the range "00" to "99", considers the year a 2-digit form and makes
04343  * it full.
04344  *
04345  *    Date.parse('2001-02-03')          #=> #<Date: 2001-02-03 ...>
04346  *    Date.parse('20010203')            #=> #<Date: 2001-02-03 ...>
04347  *    Date.parse('3rd Feb 2001')        #=> #<Date: 2001-02-03 ...>
04348  */
04349 static VALUE
04350 date_s_parse(int argc, VALUE *argv, VALUE klass)
04351 {
04352     VALUE str, comp, sg;
04353 
04354     rb_scan_args(argc, argv, "03", &str, &comp, &sg);
04355 
04356     switch (argc) {
04357       case 0:
04358         str = rb_str_new2("-4712-01-01");
04359       case 1:
04360         comp = Qtrue;
04361       case 2:
04362         sg = INT2FIX(DEFAULT_SG);
04363     }
04364 
04365     {
04366         VALUE argv2[2], hash;
04367 
04368         argv2[0] = str;
04369         argv2[1] = comp;
04370         hash = date_s__parse(2, argv2, klass);
04371         return d_new_by_frags(klass, hash, sg);
04372     }
04373 }
04374 
04375 VALUE date__iso8601(VALUE);
04376 VALUE date__rfc3339(VALUE);
04377 VALUE date__xmlschema(VALUE);
04378 VALUE date__rfc2822(VALUE);
04379 VALUE date__httpdate(VALUE);
04380 VALUE date__jisx0301(VALUE);
04381 
04382 /*
04383  * call-seq:
04384  *    Date._iso8601(string)  ->  hash
04385  *
04386  * Returns a hash of parsed elements.
04387  */
04388 static VALUE
04389 date_s__iso8601(VALUE klass, VALUE str)
04390 {
04391     return date__iso8601(str);
04392 }
04393 
04394 /*
04395  * call-seq:
04396  *    Date.iso8601(string='-4712-01-01'[, start=ITALY])  ->  date
04397  *
04398  * Creates a new Date object by parsing from a string according to
04399  * some typical ISO 8601 formats.
04400  *
04401  *    Date.iso8601('2001-02-03')        #=> #<Date: 2001-02-03 ...>
04402  *    Date.iso8601('20010203')          #=> #<Date: 2001-02-03 ...>
04403  *    Date.iso8601('2001-W05-6')        #=> #<Date: 2001-02-03 ...>
04404  */
04405 static VALUE
04406 date_s_iso8601(int argc, VALUE *argv, VALUE klass)
04407 {
04408     VALUE str, sg;
04409 
04410     rb_scan_args(argc, argv, "02", &str, &sg);
04411 
04412     switch (argc) {
04413       case 0:
04414         str = rb_str_new2("-4712-01-01");
04415       case 1:
04416         sg = INT2FIX(DEFAULT_SG);
04417     }
04418 
04419     {
04420         VALUE hash = date_s__iso8601(klass, str);
04421         return d_new_by_frags(klass, hash, sg);
04422     }
04423 }
04424 
04425 /*
04426  * call-seq:
04427  *    Date._rfc3339(string)  ->  hash
04428  *
04429  * Returns a hash of parsed elements.
04430  */
04431 static VALUE
04432 date_s__rfc3339(VALUE klass, VALUE str)
04433 {
04434     return date__rfc3339(str);
04435 }
04436 
04437 /*
04438  * call-seq:
04439  *    Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY])  ->  date
04440  *
04441  * Creates a new Date object by parsing from a string according to
04442  * some typical RFC 3339 formats.
04443  *
04444  *    Date.rfc3339('2001-02-03T04:05:06+07:00') #=> #<Date: 2001-02-03 ...>
04445  */
04446 static VALUE
04447 date_s_rfc3339(int argc, VALUE *argv, VALUE klass)
04448 {
04449     VALUE str, sg;
04450 
04451     rb_scan_args(argc, argv, "02", &str, &sg);
04452 
04453     switch (argc) {
04454       case 0:
04455         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
04456       case 1:
04457         sg = INT2FIX(DEFAULT_SG);
04458     }
04459 
04460     {
04461         VALUE hash = date_s__rfc3339(klass, str);
04462         return d_new_by_frags(klass, hash, sg);
04463     }
04464 }
04465 
04466 /*
04467  * call-seq:
04468  *    Date._xmlschema(string)  ->  hash
04469  *
04470  * Returns a hash of parsed elements.
04471  */
04472 static VALUE
04473 date_s__xmlschema(VALUE klass, VALUE str)
04474 {
04475     return date__xmlschema(str);
04476 }
04477 
04478 /*
04479  * call-seq:
04480  *    Date.xmlschema(string='-4712-01-01'[, start=ITALY])  ->  date
04481  *
04482  * Creates a new Date object by parsing from a string according to
04483  * some typical XML Schema formats.
04484  *
04485  *    Date.xmlschema('2001-02-03')      #=> #<Date: 2001-02-03 ...>
04486  */
04487 static VALUE
04488 date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
04489 {
04490     VALUE str, sg;
04491 
04492     rb_scan_args(argc, argv, "02", &str, &sg);
04493 
04494     switch (argc) {
04495       case 0:
04496         str = rb_str_new2("-4712-01-01");
04497       case 1:
04498         sg = INT2FIX(DEFAULT_SG);
04499     }
04500 
04501     {
04502         VALUE hash = date_s__xmlschema(klass, str);
04503         return d_new_by_frags(klass, hash, sg);
04504     }
04505 }
04506 
04507 /*
04508  * call-seq:
04509  *    Date._rfc2822(string)  ->  hash
04510  *    Date._rfc822(string)   ->  hash
04511  *
04512  * Returns a hash of parsed elements.
04513  */
04514 static VALUE
04515 date_s__rfc2822(VALUE klass, VALUE str)
04516 {
04517     return date__rfc2822(str);
04518 }
04519 
04520 /*
04521  * call-seq:
04522  *    Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY])  ->  date
04523  *    Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY])   ->  date
04524  *
04525  * Creates a new Date object by parsing from a string according to
04526  * some typical RFC 2822 formats.
04527  *
04528  *    Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000')
04529  *                                              #=> #<Date: 2001-02-03 ...>
04530  */
04531 static VALUE
04532 date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
04533 {
04534     VALUE str, sg;
04535 
04536     rb_scan_args(argc, argv, "02", &str, &sg);
04537 
04538     switch (argc) {
04539       case 0:
04540         str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
04541       case 1:
04542         sg = INT2FIX(DEFAULT_SG);
04543     }
04544 
04545     {
04546         VALUE hash = date_s__rfc2822(klass, str);
04547         return d_new_by_frags(klass, hash, sg);
04548     }
04549 }
04550 
04551 /*
04552  * call-seq:
04553  *    Date._httpdate(string)  ->  hash
04554  *
04555  * Returns a hash of parsed elements.
04556  */
04557 static VALUE
04558 date_s__httpdate(VALUE klass, VALUE str)
04559 {
04560     return date__httpdate(str);
04561 }
04562 
04563 /*
04564  * call-seq:
04565  *    Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY])  ->  date
04566  *
04567  * Creates a new Date object by parsing from a string according to
04568  * some RFC 2616 format.
04569  *
04570  *    Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT')
04571  *                                              #=> #<Date: 2001-02-03 ...>
04572  */
04573 static VALUE
04574 date_s_httpdate(int argc, VALUE *argv, VALUE klass)
04575 {
04576     VALUE str, sg;
04577 
04578     rb_scan_args(argc, argv, "02", &str, &sg);
04579 
04580     switch (argc) {
04581       case 0:
04582         str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
04583       case 1:
04584         sg = INT2FIX(DEFAULT_SG);
04585     }
04586 
04587     {
04588         VALUE hash = date_s__httpdate(klass, str);
04589         return d_new_by_frags(klass, hash, sg);
04590     }
04591 }
04592 
04593 /*
04594  * call-seq:
04595  *    Date._jisx0301(string)  ->  hash
04596  *
04597  * Returns a hash of parsed elements.
04598  */
04599 static VALUE
04600 date_s__jisx0301(VALUE klass, VALUE str)
04601 {
04602     return date__jisx0301(str);
04603 }
04604 
04605 /*
04606  * call-seq:
04607  *    Date.jisx0301(string='-4712-01-01'[, start=ITALY])  ->  date
04608  *
04609  * Creates a new Date object by parsing from a string according to
04610  * some typical JIS X 0301 formats.
04611  *
04612  *    Date.jisx0301('H13.02.03')                #=> #<Date: 2001-02-03 ...>
04613  */
04614 static VALUE
04615 date_s_jisx0301(int argc, VALUE *argv, VALUE klass)
04616 {
04617     VALUE str, sg;
04618 
04619     rb_scan_args(argc, argv, "02", &str, &sg);
04620 
04621     switch (argc) {
04622       case 0:
04623         str = rb_str_new2("-4712-01-01");
04624       case 1:
04625         sg = INT2FIX(DEFAULT_SG);
04626     }
04627 
04628     {
04629         VALUE hash = date_s__jisx0301(klass, str);
04630         return d_new_by_frags(klass, hash, sg);
04631     }
04632 }
04633 
04634 static VALUE
04635 dup_obj(VALUE self)
04636 {
04637     get_d1a(self);
04638 
04639     if (simple_dat_p(adat)) {
04640         VALUE new = d_lite_s_alloc_simple(rb_obj_class(self));
04641         {
04642             get_d1b(new);
04643             bdat->s = adat->s;
04644             return new;
04645         }
04646     }
04647     else {
04648         VALUE new = d_lite_s_alloc_complex(rb_obj_class(self));
04649         {
04650             get_d1b(new);
04651             bdat->c = adat->c;
04652             return new;
04653         }
04654     }
04655 }
04656 
04657 static VALUE
04658 dup_obj_as_complex(VALUE self)
04659 {
04660     get_d1a(self);
04661 
04662     if (simple_dat_p(adat)) {
04663         VALUE new = d_lite_s_alloc_complex(rb_obj_class(self));
04664         {
04665             get_d1b(new);
04666             copy_simple_to_complex(&bdat->c, &adat->s);
04667             bdat->c.flags |= HAVE_DF | COMPLEX_DAT;
04668             return new;
04669         }
04670     }
04671     else {
04672         VALUE new = d_lite_s_alloc_complex(rb_obj_class(self));
04673         {
04674             get_d1b(new);
04675             bdat->c = adat->c;
04676             return new;
04677         }
04678     }
04679 }
04680 
04681 #define val2off(vof,iof) \
04682 {\
04683     if (!offset_to_sec(vof, &iof)) {\
04684         iof = 0;\
04685         rb_warning("invalid offset is ignored");\
04686     }\
04687 }
04688 
04689 #ifndef NDEBUG
04690 static VALUE
04691 d_lite_initialize(int argc, VALUE *argv, VALUE self)
04692 {
04693     VALUE jd, vjd, vdf, sf, vsf, vof, vsg;
04694     int df, of;
04695     double sg;
04696 
04697     rb_check_frozen(self);
04698     rb_check_trusted(self);
04699 
04700     rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg);
04701 
04702     jd = INT2FIX(0);
04703     df = 0;
04704     sf = INT2FIX(0);
04705     of = 0;
04706     sg = DEFAULT_SG;
04707 
04708     switch (argc) {
04709       case 5:
04710         val2sg(vsg, sg);
04711       case 4:
04712         val2off(vof, of);
04713       case 3:
04714         sf = vsf;
04715         if (f_lt_p(sf, INT2FIX(0)) ||
04716             f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS)))
04717             rb_raise(rb_eArgError, "invalid second fraction");
04718       case 2:
04719         df = NUM2INT(vdf);
04720         if (df < 0 || df >= DAY_IN_SECONDS)
04721             rb_raise(rb_eArgError, "invalid day fraction");
04722       case 1:
04723         jd = vjd;
04724     }
04725 
04726     {
04727         VALUE nth;
04728         int rjd;
04729 
04730         get_d1(self);
04731 
04732         decode_jd(jd, &nth, &rjd);
04733         if (!df && f_zero_p(sf) && !of) {
04734             set_to_simple(&dat->s, nth, rjd, sg, 0, 0, 0, HAVE_JD);
04735         }
04736         else {
04737             if (!complex_dat_p(dat))
04738                 rb_raise(rb_eArgError,
04739                          "cannot load complex into simple");
04740 
04741             set_to_complex(&dat->c, nth, rjd, df, sf, of, sg,
04742                            0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF | COMPLEX_DAT);
04743         }
04744     }
04745     return self;
04746 }
04747 #endif
04748 
04749 /* :nodoc: */
04750 static VALUE
04751 d_lite_initialize_copy(VALUE copy, VALUE date)
04752 {
04753     rb_check_frozen(copy);
04754     rb_check_trusted(copy);
04755 
04756     if (copy == date)
04757         return copy;
04758     {
04759         get_d2(copy, date);
04760         if (simple_dat_p(bdat)) {
04761             adat->s = bdat->s;
04762             adat->s.flags &= ~COMPLEX_DAT;
04763         }
04764         else {
04765             if (!complex_dat_p(adat))
04766                 rb_raise(rb_eArgError,
04767                          "cannot load complex into simple");
04768 
04769             adat->c = bdat->c;
04770             adat->c.flags |= COMPLEX_DAT;
04771         }
04772     }
04773     return copy;
04774 }
04775 
04776 #ifndef NDEBUG
04777 static VALUE
04778 d_lite_fill(VALUE self)
04779 {
04780     get_d1(self);
04781 
04782     if (simple_dat_p(dat)) {
04783         get_s_jd(dat);
04784         get_s_civil(dat);
04785     }
04786     else {
04787         get_c_jd(dat);
04788         get_c_civil(dat);
04789         get_c_df(dat);
04790         get_c_time(dat);
04791     }
04792     return self;
04793 }
04794 #endif
04795 
04796 /*
04797  * call-seq:
04798  *    d.ajd  ->  rational
04799  *
04800  * Returns the astronomical Julian day number.  This is a fractional
04801  * number, which is not adjusted by the offset.
04802  *
04803  *    DateTime.new(2001,2,3,4,5,6,'+7').ajd     #=> (11769328217/4800)
04804  *    DateTime.new(2001,2,2,14,5,6,'-7').ajd    #=> (11769328217/4800)
04805  */
04806 static VALUE
04807 d_lite_ajd(VALUE self)
04808 {
04809     get_d1(self);
04810     return m_ajd(dat);
04811 }
04812 
04813 /*
04814  * call-seq:
04815  *    d.amjd  ->  rational
04816  *
04817  * Returns the astronomical modified Julian day number.  This is
04818  * a fractional number, which is not adjusted by the offset.
04819  *
04820  *    DateTime.new(2001,2,3,4,5,6,'+7').amjd    #=> (249325817/4800)
04821  *    DateTime.new(2001,2,2,14,5,6,'-7').amjd   #=> (249325817/4800)
04822  */
04823 static VALUE
04824 d_lite_amjd(VALUE self)
04825 {
04826     get_d1(self);
04827     return m_amjd(dat);
04828 }
04829 
04830 /*
04831  * call-seq:
04832  *    d.jd  ->  integer
04833  *
04834  * Returns the Julian day number.  This is a whole number, which is
04835  * adjusted by the offset as the local time.
04836  *
04837  *    DateTime.new(2001,2,3,4,5,6,'+7').jd      #=> 2451944
04838  *    DateTime.new(2001,2,3,4,5,6,'-7').jd      #=> 2451944
04839  */
04840 static VALUE
04841 d_lite_jd(VALUE self)
04842 {
04843     get_d1(self);
04844     return m_real_local_jd(dat);
04845 }
04846 
04847 /*
04848  * call-seq:
04849  *    d.mjd  ->  integer
04850  *
04851  * Returns the modified Julian day number.  This is a whole number,
04852  * which is adjusted by the offset as the local time.
04853  *
04854  *    DateTime.new(2001,2,3,4,5,6,'+7').mjd     #=> 51943
04855  *    DateTime.new(2001,2,3,4,5,6,'-7').mjd     #=> 51943
04856  */
04857 static VALUE
04858 d_lite_mjd(VALUE self)
04859 {
04860     get_d1(self);
04861     return f_sub(m_real_local_jd(dat), INT2FIX(2400001));
04862 }
04863 
04864 /*
04865  * call-seq:
04866  *    d.ld  ->  integer
04867  *
04868  * Returns the Lilian day number.  This is a whole number, which is
04869  * adjusted by the offset as the local time.
04870  *
04871  *     Date.new(2001,2,3).ld            #=> 152784
04872  */
04873 static VALUE
04874 d_lite_ld(VALUE self)
04875 {
04876     get_d1(self);
04877     return f_sub(m_real_local_jd(dat), INT2FIX(2299160));
04878 }
04879 
04880 /*
04881  * call-seq:
04882  *    d.year  ->  integer
04883  *
04884  * Returns the year.
04885  *
04886  *    Date.new(2001,2,3).year           #=> 2001
04887  *    (Date.new(1,1,1) - 1).year        #=> 0
04888  */
04889 static VALUE
04890 d_lite_year(VALUE self)
04891 {
04892     get_d1(self);
04893     return m_real_year(dat);
04894 }
04895 
04896 /*
04897  * call-seq:
04898  *    d.yday  ->  fixnum
04899  *
04900  * Returns the day of the year (1-366).
04901  *
04902  *    Date.new(2001,2,3).yday           #=> 34
04903  */
04904 static VALUE
04905 d_lite_yday(VALUE self)
04906 {
04907     get_d1(self);
04908     return INT2FIX(m_yday(dat));
04909 }
04910 
04911 /*
04912  * call-seq:
04913  *    d.mon    ->  fixnum
04914  *    d.month  ->  fixnum
04915  *
04916  * Returns the month (1-12).
04917  *
04918  *    Date.new(2001,2,3).mon            #=> 2
04919  */
04920 static VALUE
04921 d_lite_mon(VALUE self)
04922 {
04923     get_d1(self);
04924     return INT2FIX(m_mon(dat));
04925 }
04926 
04927 /*
04928  * call-seq:
04929  *    d.mday  ->  fixnum
04930  *    d.day   ->  fixnum
04931  *
04932  * Returns the day of the month (1-31).
04933  *
04934  *    Date.new(2001,2,3).mday           #=> 3
04935  */
04936 static VALUE
04937 d_lite_mday(VALUE self)
04938 {
04939     get_d1(self);
04940     return INT2FIX(m_mday(dat));
04941 }
04942 
04943 /*
04944  * call-seq:
04945  *    d.day_fraction  ->  rational
04946  *
04947  * Returns the fractional part of the day.
04948  *
04949  *    DateTime.new(2001,2,3,12).day_fraction    #=> (1/2)
04950  */
04951 static VALUE
04952 d_lite_day_fraction(VALUE self)
04953 {
04954     get_d1(self);
04955     if (simple_dat_p(dat))
04956         return INT2FIX(0);
04957     return m_fr(dat);
04958 }
04959 
04960 /*
04961  * call-seq:
04962  *    d.cwyear  ->  integer
04963  *
04964  * Returns the calendar week based year.
04965  *
04966  *    Date.new(2001,2,3).cwyear         #=> 2001
04967  *    Date.new(2000,1,1).cwyear         #=> 1999
04968  */
04969 static VALUE
04970 d_lite_cwyear(VALUE self)
04971 {
04972     get_d1(self);
04973     return m_real_cwyear(dat);
04974 }
04975 
04976 /*
04977  * call-seq:
04978  *    d.cweek  ->  fixnum
04979  *
04980  * Returns the calendar week number (1-53).
04981  *
04982  *    Date.new(2001,2,3).cweek          #=> 5
04983  */
04984 static VALUE
04985 d_lite_cweek(VALUE self)
04986 {
04987     get_d1(self);
04988     return INT2FIX(m_cweek(dat));
04989 }
04990 
04991 /*
04992  * call-seq:
04993  *    d.cwday  ->  fixnum
04994  *
04995  * Returns the day of calendar week (1-7, Monday is 1).
04996  *
04997  *    Date.new(2001,2,3).cwday          #=> 6
04998  */
04999 static VALUE
05000 d_lite_cwday(VALUE self)
05001 {
05002     get_d1(self);
05003     return INT2FIX(m_cwday(dat));
05004 }
05005 
05006 #ifndef NDEBUG
05007 static VALUE
05008 d_lite_wnum0(VALUE self)
05009 {
05010     get_d1(self);
05011     return INT2FIX(m_wnum0(dat));
05012 }
05013 
05014 static VALUE
05015 d_lite_wnum1(VALUE self)
05016 {
05017     get_d1(self);
05018     return INT2FIX(m_wnum1(dat));
05019 }
05020 #endif
05021 
05022 /*
05023  * call-seq:
05024  *    d.wday  ->  fixnum
05025  *
05026  * Returns the day of week (0-6, Sunday is zero).
05027  *
05028  *    Date.new(2001,2,3).wday           #=> 6
05029  */
05030 static VALUE
05031 d_lite_wday(VALUE self)
05032 {
05033     get_d1(self);
05034     return INT2FIX(m_wday(dat));
05035 }
05036 
05037 /*
05038  * call-seq:
05039  *    d.sunday?  ->  bool
05040  *
05041  * Returns true if the date is Sunday.
05042  */
05043 static VALUE
05044 d_lite_sunday_p(VALUE self)
05045 {
05046     get_d1(self);
05047     return f_boolcast(m_wday(dat) == 0);
05048 }
05049 
05050 /*
05051  * call-seq:
05052  *    d.monday?  ->  bool
05053  *
05054  * Returns true if the date is Monday.
05055  */
05056 static VALUE
05057 d_lite_monday_p(VALUE self)
05058 {
05059     get_d1(self);
05060     return f_boolcast(m_wday(dat) == 1);
05061 }
05062 
05063 /*
05064  * call-seq:
05065  *    d.tuesday?  ->  bool
05066  *
05067  * Returns true if the date is Tuesday.
05068  */
05069 static VALUE
05070 d_lite_tuesday_p(VALUE self)
05071 {
05072     get_d1(self);
05073     return f_boolcast(m_wday(dat) == 2);
05074 }
05075 
05076 /*
05077  * call-seq:
05078  *    d.wednesday?  ->  bool
05079  *
05080  * Returns true if the date is Wednesday.
05081  */
05082 static VALUE
05083 d_lite_wednesday_p(VALUE self)
05084 {
05085     get_d1(self);
05086     return f_boolcast(m_wday(dat) == 3);
05087 }
05088 
05089 /*
05090  * call-seq:
05091  *    d.thursday?  ->  bool
05092  *
05093  * Returns true if the date is Thursday.
05094  */
05095 static VALUE
05096 d_lite_thursday_p(VALUE self)
05097 {
05098     get_d1(self);
05099     return f_boolcast(m_wday(dat) == 4);
05100 }
05101 
05102 /*
05103  * call-seq:
05104  *    d.friday?  ->  bool
05105  *
05106  * Returns true if the date is Friday.
05107  */
05108 static VALUE
05109 d_lite_friday_p(VALUE self)
05110 {
05111     get_d1(self);
05112     return f_boolcast(m_wday(dat) == 5);
05113 }
05114 
05115 /*
05116  * call-seq:
05117  *    d.saturday?  ->  bool
05118  *
05119  * Returns true if the date is Saturday.
05120  */
05121 static VALUE
05122 d_lite_saturday_p(VALUE self)
05123 {
05124     get_d1(self);
05125     return f_boolcast(m_wday(dat) == 6);
05126 }
05127 
05128 #ifndef NDEBUG
05129 static VALUE
05130 d_lite_nth_kday_p(VALUE self, VALUE n, VALUE k)
05131 {
05132     int rjd, ns;
05133 
05134     get_d1(self);
05135 
05136     if (NUM2INT(k) != m_wday(dat))
05137         return Qfalse;
05138 
05139     c_nth_kday_to_jd(m_year(dat), m_mon(dat),
05140                      NUM2INT(n), NUM2INT(k), m_virtual_sg(dat), /* !=m_sg() */
05141                      &rjd, &ns);
05142     if (m_local_jd(dat) != rjd)
05143         return Qfalse;
05144     return Qtrue;
05145 }
05146 #endif
05147 
05148 /*
05149  * call-seq:
05150  *    d.hour  ->  fixnum
05151  *
05152  * Returns the hour (0-23).
05153  *
05154  *    DateTime.new(2001,2,3,4,5,6).hour         #=> 4
05155  */
05156 static VALUE
05157 d_lite_hour(VALUE self)
05158 {
05159     get_d1(self);
05160     return INT2FIX(m_hour(dat));
05161 }
05162 
05163 /*
05164  * call-seq:
05165  *    d.min     ->  fixnum
05166  *    d.minute  ->  fixnum
05167  *
05168  * Returns the minute (0-59).
05169  *
05170  *    DateTime.new(2001,2,3,4,5,6).min          #=> 5
05171  */
05172 static VALUE
05173 d_lite_min(VALUE self)
05174 {
05175     get_d1(self);
05176     return INT2FIX(m_min(dat));
05177 }
05178 
05179 /*
05180  * call-seq:
05181  *    d.sec     ->  fixnum
05182  *    d.second  ->  fixnum
05183  *
05184  * Returns the second (0-59).
05185  *
05186  *    DateTime.new(2001,2,3,4,5,6).sec          #=> 6
05187  */
05188 static VALUE
05189 d_lite_sec(VALUE self)
05190 {
05191     get_d1(self);
05192     return INT2FIX(m_sec(dat));
05193 }
05194 
05195 /*
05196  * call-seq:
05197  *    d.sec_fraction     ->  rational
05198  *    d.second_fraction  ->  rational
05199  *
05200  * Returns the fractional part of the second.
05201  *
05202  *    DateTime.new(2001,2,3,4,5,6.5).sec_fraction       #=> (1/2)
05203  */
05204 static VALUE
05205 d_lite_sec_fraction(VALUE self)
05206 {
05207     get_d1(self);
05208     return m_sf_in_sec(dat);
05209 }
05210 
05211 /*
05212  * call-seq:
05213  *    d.offset  ->  rational
05214  *
05215  * Returns the offset.
05216  *
05217  *    DateTime.parse('04pm+0730').offset        #=> (5/16)
05218  */
05219 static VALUE
05220 d_lite_offset(VALUE self)
05221 {
05222     get_d1(self);
05223     return m_of_in_day(dat);
05224 }
05225 
05226 /*
05227  * call-seq:
05228  *    d.zone  ->  string
05229  *
05230  * Returns the timezone.
05231  *
05232  *    DateTime.parse('04pm+0730').zone          #=> "+07:30"
05233  */
05234 static VALUE
05235 d_lite_zone(VALUE self)
05236 {
05237     get_d1(self);
05238     return m_zone(dat);
05239 }
05240 
05241 /*
05242  * call-seq:
05243  *    d.julian?  ->  bool
05244  *
05245  * Retruns true if the date is before the day of calendar reform.
05246  *
05247  *     Date.new(1582,10,15).julian?             #=> false
05248  *     (Date.new(1582,10,15) - 1).julian?       #=> true
05249  */
05250 static VALUE
05251 d_lite_julian_p(VALUE self)
05252 {
05253     get_d1(self);
05254     return f_boolcast(m_julian_p(dat));
05255 }
05256 
05257 /*
05258  * call-seq:
05259  *    d.gregorian?  ->  bool
05260  *
05261  * Retunrs true if the date is on or after the day of calendar reform.
05262  *
05263  *     Date.new(1582,10,15).gregorian?          #=> true
05264  *     (Date.new(1582,10,15) - 1).gregorian?    #=> false
05265  */
05266 static VALUE
05267 d_lite_gregorian_p(VALUE self)
05268 {
05269     get_d1(self);
05270     return f_boolcast(m_gregorian_p(dat));
05271 }
05272 
05273 /*
05274  * call-seq:
05275  *    d.leap?  ->  bool
05276  *
05277  * Returns true if the year is a leap year.
05278  *
05279  *    Date.new(2000).leap?      #=> true
05280  *    Date.new(2001).leap?      #=> false
05281  */
05282 static VALUE
05283 d_lite_leap_p(VALUE self)
05284 {
05285     int rjd, ns, ry, rm, rd;
05286 
05287     get_d1(self);
05288     if (m_gregorian_p(dat))
05289         return f_boolcast(c_gregorian_leap_p(m_year(dat)));
05290 
05291     c_civil_to_jd(m_year(dat), 3, 1, m_virtual_sg(dat),
05292                   &rjd, &ns);
05293     c_jd_to_civil(rjd - 1, m_virtual_sg(dat), &ry, &rm, &rd);
05294     return f_boolcast(rd == 29);
05295 }
05296 
05297 /*
05298  * call-seq:
05299  *    d.start  ->  float
05300  *
05301  * Returns the Julian day number denoting the day of calendar reform.
05302  *
05303  *    Date.new(2001,2,3).start                  #=> 2299161.0
05304  *    Date.new(2001,2,3,Date::GREGORIAN).start  #=> -Infinity
05305  */
05306 static VALUE
05307 d_lite_start(VALUE self)
05308 {
05309     get_d1(self);
05310     return DBL2NUM(m_sg(dat));
05311 }
05312 
05313 static void
05314 clear_civil(union DateData *x)
05315 {
05316     if (simple_dat_p(x)) {
05317         x->s.year = 0;
05318 #ifndef USE_PACK
05319         x->s.mon = 0;
05320         x->s.mday = 0;
05321 #else
05322         x->s.pc = 0;
05323 #endif
05324         x->s.flags &= ~HAVE_CIVIL;
05325     }
05326     else {
05327         x->c.year = 0;
05328 #ifndef USE_PACK
05329         x->c.mon = 0;
05330         x->c.mday = 0;
05331         x->c.hour = 0;
05332         x->c.min = 0;
05333         x->c.sec = 0;
05334 #else
05335         x->c.pc = 0;
05336 #endif
05337         x->c.flags &= ~(HAVE_CIVIL | HAVE_TIME);
05338     }
05339 }
05340 
05341 static void
05342 set_sg(union DateData *x, double sg)
05343 {
05344     if (simple_dat_p(x)) {
05345         get_s_jd(x);
05346         clear_civil(x);
05347         x->s.sg = (date_sg_t)sg;
05348     } else {
05349         get_c_jd(x);
05350         get_c_df(x);
05351         clear_civil(x);
05352         x->c.sg = (date_sg_t)sg;
05353     }
05354 }
05355 
05356 static VALUE
05357 dup_obj_with_new_start(VALUE obj, double sg)
05358 {
05359     volatile VALUE dup = dup_obj(obj);
05360     {
05361         get_d1(dup);
05362         set_sg(dat, sg);
05363     }
05364     return dup;
05365 }
05366 
05367 /*
05368  * call-seq:
05369  *    d.new_start([start=Date::ITALY])  ->  date
05370  *
05371  * Duplicates self and resets its the day of calendar reform.
05372  *
05373  *    d = Date.new(1582,10,15)
05374  *    d.new_start(Date::JULIAN)         #=> #<Date: 1582-10-05 ...>
05375  */
05376 static VALUE
05377 d_lite_new_start(int argc, VALUE *argv, VALUE self)
05378 {
05379     VALUE vsg;
05380     double sg;
05381 
05382     rb_scan_args(argc, argv, "01", &vsg);
05383 
05384     sg = DEFAULT_SG;
05385     if (argc >= 1)
05386         val2sg(vsg, sg);
05387 
05388     return dup_obj_with_new_start(self, sg);
05389 }
05390 
05391 /*
05392  * call-seq:
05393  *    d.italy  ->  date
05394  *
05395  * This method is equivalent to new_start(Date::ITALY).
05396  */
05397 static VALUE
05398 d_lite_italy(VALUE self)
05399 {
05400     return dup_obj_with_new_start(self, ITALY);
05401 }
05402 
05403 /*
05404  * call-seq:
05405  *    d.england  ->  date
05406  *
05407  * This method is equivalent to new_start(Date::ENGLAND).
05408  */
05409 static VALUE
05410 d_lite_england(VALUE self)
05411 {
05412     return dup_obj_with_new_start(self, ENGLAND);
05413 }
05414 
05415 /*
05416  * call-seq:
05417  *    d.julian  ->  date
05418  *
05419  * This method is equivalent to new_start(Date::JULIAN).
05420  */
05421 static VALUE
05422 d_lite_julian(VALUE self)
05423 {
05424     return dup_obj_with_new_start(self, JULIAN);
05425 }
05426 
05427 /*
05428  * call-seq:
05429  *    d.gregorian  ->  date
05430  *
05431  * This method is equivalent to new_start(Date::GREGORIAN).
05432  */
05433 static VALUE
05434 d_lite_gregorian(VALUE self)
05435 {
05436     return dup_obj_with_new_start(self, GREGORIAN);
05437 }
05438 
05439 static void
05440 set_of(union DateData *x, int of)
05441 {
05442     assert(complex_dat_p(x));
05443     get_c_jd(x);
05444     get_c_df(x);
05445     clear_civil(x);
05446     x->c.of = of;
05447 }
05448 
05449 static VALUE
05450 dup_obj_with_new_offset(VALUE obj, int of)
05451 {
05452     volatile VALUE dup = dup_obj_as_complex(obj);
05453     {
05454         get_d1(dup);
05455         set_of(dat, of);
05456     }
05457     return dup;
05458 }
05459 
05460 /*
05461  * call-seq:
05462  *    d.new_offset([offset=0])  ->  date
05463  *
05464  * Duplicates self and resets its offset.
05465  *
05466  *    d = DateTime.new(2001,2,3,4,5,6,'-02:00')
05467  *                              #=> #<DateTime: 2001-02-03T04:05:06-02:00 ...>
05468  *    d.new_offset('+09:00')    #=> #<DateTime: 2001-02-03T15:05:06+09:00 ...>
05469  */
05470 static VALUE
05471 d_lite_new_offset(int argc, VALUE *argv, VALUE self)
05472 {
05473     VALUE vof;
05474     int rof;
05475 
05476     rb_scan_args(argc, argv, "01", &vof);
05477 
05478     rof = 0;
05479     if (argc >= 1)
05480         val2off(vof, rof);
05481 
05482     return dup_obj_with_new_offset(self, rof);
05483 }
05484 
05485 /*
05486  * call-seq:
05487  *    d + other  ->  date
05488  *
05489  * Returns a date object pointing other days after self.  The other
05490  * should be a numeric value.  If the other is flonum, assumes its
05491  * precision is at most nanosecond.
05492  *
05493  *    Date.new(2001,2,3) + 1    #=> #<Date: 2001-02-04 ...>
05494  *    DateTime.new(2001,2,3) + Rational(1,2)
05495  *                              #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...>
05496  *    DateTime.new(2001,2,3) + Rational(-1,2)
05497  *                              #=> #<DateTime: 2001-02-02T12:00:00+00:00 ...>
05498  *    DateTime.jd(0,12) + DateTime.new(2001,2,3).ajd
05499  *                              #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
05500  */
05501 static VALUE
05502 d_lite_plus(VALUE self, VALUE other)
05503 {
05504     get_d1(self);
05505 
05506     switch (TYPE(other)) {
05507       case T_FIXNUM:
05508         {
05509             VALUE nth;
05510             long t;
05511             int jd;
05512 
05513             nth = m_nth(dat);
05514             t = FIX2LONG(other);
05515             if (DIV(t, CM_PERIOD)) {
05516                 nth = f_add(nth, INT2FIX(DIV(t, CM_PERIOD)));
05517                 t = MOD(t, CM_PERIOD);
05518             }
05519 
05520             if (!t)
05521                 jd = m_jd(dat);
05522             else {
05523                 jd = m_jd(dat) + (int)t;
05524                 canonicalize_jd(nth, jd);
05525             }
05526 
05527             if (simple_dat_p(dat))
05528                 return d_simple_new_internal(rb_obj_class(self),
05529                                              nth, jd,
05530                                              dat->s.sg,
05531                                              0, 0, 0,
05532                                              (dat->s.flags | HAVE_JD) &
05533                                              ~HAVE_CIVIL);
05534             else
05535                 return d_complex_new_internal(rb_obj_class(self),
05536                                               nth, jd,
05537                                               dat->c.df, dat->c.sf,
05538                                               dat->c.of, dat->c.sg,
05539                                               0, 0, 0,
05540 #ifndef USE_PACK
05541                                               dat->c.hour,
05542                                               dat->c.min,
05543                                               dat->c.sec,
05544 #else
05545                                               EX_HOUR(dat->c.pc),
05546                                               EX_MIN(dat->c.pc),
05547                                               EX_SEC(dat->c.pc),
05548 #endif
05549                                               (dat->c.flags | HAVE_JD) &
05550                                               ~HAVE_CIVIL);
05551         }
05552         break;
05553       case T_BIGNUM:
05554         {
05555             VALUE nth;
05556             int jd, s;
05557 
05558             if (f_positive_p(other))
05559                 s = +1;
05560             else {
05561                 s = -1;
05562                 other = f_negate(other);
05563             }
05564 
05565             nth = f_idiv(other, INT2FIX(CM_PERIOD));
05566             jd = FIX2INT(f_mod(other, INT2FIX(CM_PERIOD)));
05567 
05568             if (s < 0) {
05569                 nth = f_negate(nth);
05570                 jd = -jd;
05571             }
05572 
05573             if (!jd)
05574                 jd = m_jd(dat);
05575             else {
05576                 jd = m_jd(dat) + jd;
05577                 canonicalize_jd(nth, jd);
05578             }
05579 
05580             if (f_zero_p(nth))
05581                 nth = m_nth(dat);
05582             else
05583                 nth = f_add(m_nth(dat), nth);
05584 
05585             if (simple_dat_p(dat))
05586                 return d_simple_new_internal(rb_obj_class(self),
05587                                              nth, jd,
05588                                              dat->s.sg,
05589                                              0, 0, 0,
05590                                              (dat->s.flags | HAVE_JD) &
05591                                              ~HAVE_CIVIL);
05592             else
05593                 return d_complex_new_internal(rb_obj_class(self),
05594                                               nth, jd,
05595                                               dat->c.df, dat->c.sf,
05596                                               dat->c.of, dat->c.sg,
05597                                               0, 0, 0,
05598 #ifndef USE_PACK
05599                                               dat->c.hour,
05600                                               dat->c.min,
05601                                               dat->c.sec,
05602 #else
05603                                               EX_HOUR(dat->c.pc),
05604                                               EX_MIN(dat->c.pc),
05605                                               EX_SEC(dat->c.pc),
05606 #endif
05607                                               (dat->c.flags | HAVE_JD) &
05608                                               ~HAVE_CIVIL);
05609         }
05610         break;
05611       case T_FLOAT:
05612         {
05613             double jd, o, tmp;
05614             int s, df;
05615             VALUE nth, sf;
05616 
05617             o = RFLOAT_VALUE(other);
05618 
05619             if (o > 0)
05620                 s = +1;
05621             else {
05622                 s = -1;
05623                 o = -o;
05624             }
05625 
05626             o = modf(o, &tmp);
05627 
05628             if (!floor(tmp / CM_PERIOD)) {
05629                 nth = INT2FIX(0);
05630                 jd = (int)tmp;
05631             }
05632             else {
05633                 double i, f;
05634 
05635                 f = modf(tmp / CM_PERIOD, &i);
05636                 nth = f_floor(DBL2NUM(i));
05637                 jd = (int)(f * CM_PERIOD);
05638             }
05639 
05640             o *= DAY_IN_SECONDS;
05641             o = modf(o, &tmp);
05642             df = (int)tmp;
05643             o *= SECOND_IN_NANOSECONDS;
05644             sf = INT2FIX((int)round(o));
05645 
05646             if (s < 0) {
05647                 jd = -jd;
05648                 df = -df;
05649                 sf = f_negate(sf);
05650             }
05651 
05652             if (f_zero_p(sf))
05653                 sf = m_sf(dat);
05654             else {
05655                 sf = f_add(m_sf(dat), sf);
05656                 if (f_lt_p(sf, INT2FIX(0))) {
05657                     df -= 1;
05658                     sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05659                 }
05660                 else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) {
05661                     df += 1;
05662                     sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05663                 }
05664             }
05665 
05666             if (!df)
05667                 df = m_df(dat);
05668             else {
05669                 df = m_df(dat) + df;
05670                 if (df < 0) {
05671                     jd -= 1;
05672                     df += DAY_IN_SECONDS;
05673                 }
05674                 else if (df >= DAY_IN_SECONDS) {
05675                     jd += 1;
05676                     df -= DAY_IN_SECONDS;
05677                 }
05678             }
05679 
05680             if (!jd)
05681                 jd = m_jd(dat);
05682             else {
05683                 jd = m_jd(dat) + jd;
05684                 canonicalize_jd(nth, jd);
05685             }
05686 
05687             if (f_zero_p(nth))
05688                 nth = m_nth(dat);
05689             else
05690                 nth = f_add(m_nth(dat), nth);
05691 
05692             if (!df && f_zero_p(sf) && !m_of(dat))
05693                 return d_simple_new_internal(rb_obj_class(self),
05694                                              nth, (int)jd,
05695                                              m_sg(dat),
05696                                              0, 0, 0,
05697                                              (dat->s.flags | HAVE_JD) &
05698                                              ~(HAVE_CIVIL | HAVE_TIME |
05699                                                COMPLEX_DAT));
05700             else
05701                 return d_complex_new_internal(rb_obj_class(self),
05702                                               nth, (int)jd,
05703                                               df, sf,
05704                                               m_of(dat), m_sg(dat),
05705                                               0, 0, 0,
05706                                               0, 0, 0,
05707                                               (dat->c.flags |
05708                                                HAVE_JD | HAVE_DF) &
05709                                               ~(HAVE_CIVIL | HAVE_TIME));
05710         }
05711         break;
05712       default:
05713         if (!k_numeric_p(other))
05714             rb_raise(rb_eTypeError, "expected numeric");
05715         other = f_to_r(other);
05716 #ifdef CANONICALIZATION_FOR_MATHN
05717         if (!k_rational_p(other))
05718             return d_lite_plus(self, other);
05719 #endif
05720         /* fall through */
05721       case T_RATIONAL:
05722         {
05723             VALUE nth, sf, t;
05724             int jd, df, s;
05725 
05726             if (wholenum_p(other))
05727                 return d_lite_plus(self, RRATIONAL(other)->num);
05728 
05729             if (f_positive_p(other))
05730                 s = +1;
05731             else {
05732                 s = -1;
05733                 other = f_negate(other);
05734             }
05735 
05736             nth = f_idiv(other, INT2FIX(CM_PERIOD));
05737             t = f_mod(other, INT2FIX(CM_PERIOD));
05738 
05739             jd = FIX2INT(f_idiv(t, INT2FIX(1)));
05740             t = f_mod(t, INT2FIX(1));
05741 
05742             t = f_mul(t, INT2FIX(DAY_IN_SECONDS));
05743             df = FIX2INT(f_idiv(t, INT2FIX(1)));
05744             t = f_mod(t, INT2FIX(1));
05745 
05746             sf = f_mul(t, INT2FIX(SECOND_IN_NANOSECONDS));
05747 
05748             if (s < 0) {
05749                 nth = f_negate(nth);
05750                 jd = -jd;
05751                 df = -df;
05752                 sf = f_negate(sf);
05753             }
05754 
05755             if (f_zero_p(sf))
05756                 sf = m_sf(dat);
05757             else {
05758                 sf = f_add(m_sf(dat), sf);
05759                 if (f_lt_p(sf, INT2FIX(0))) {
05760                     df -= 1;
05761                     sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05762                 }
05763                 else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) {
05764                     df += 1;
05765                     sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05766                 }
05767             }
05768 
05769             if (!df)
05770                 df = m_df(dat);
05771             else {
05772                 df = m_df(dat) + df;
05773                 if (df < 0) {
05774                     jd -= 1;
05775                     df += DAY_IN_SECONDS;
05776                 }
05777                 else if (df >= DAY_IN_SECONDS) {
05778                     jd += 1;
05779                     df -= DAY_IN_SECONDS;
05780                 }
05781             }
05782 
05783             if (!jd)
05784                 jd = m_jd(dat);
05785             else {
05786                 jd = m_jd(dat) + jd;
05787                 canonicalize_jd(nth, jd);
05788             }
05789 
05790             if (f_zero_p(nth))
05791                 nth = m_nth(dat);
05792             else
05793                 nth = f_add(m_nth(dat), nth);
05794 
05795             if (!df && f_zero_p(sf) && !m_of(dat))
05796                 return d_simple_new_internal(rb_obj_class(self),
05797                                              nth, jd,
05798                                              m_sg(dat),
05799                                              0, 0, 0,
05800                                              (dat->s.flags | HAVE_JD) &
05801                                              ~(HAVE_CIVIL | HAVE_TIME |
05802                                                COMPLEX_DAT));
05803             else
05804                 return d_complex_new_internal(rb_obj_class(self),
05805                                               nth, jd,
05806                                               df, sf,
05807                                               m_of(dat), m_sg(dat),
05808                                               0, 0, 0,
05809                                               0, 0, 0,
05810                                               (dat->c.flags |
05811                                                HAVE_JD | HAVE_DF) &
05812                                               ~(HAVE_CIVIL | HAVE_TIME));
05813         }
05814         break;
05815     }
05816 }
05817 
05818 static VALUE
05819 minus_dd(VALUE self, VALUE other)
05820 {
05821     get_d2(self, other);
05822 
05823     {
05824         int d, df;
05825         VALUE n, sf, r;
05826 
05827         n = f_sub(m_nth(adat), m_nth(bdat));
05828         d = m_jd(adat) - m_jd(bdat);
05829         df = m_df(adat) - m_df(bdat);
05830         sf = f_sub(m_sf(adat), m_sf(bdat));
05831         canonicalize_jd(n, d);
05832 
05833         if (df < 0) {
05834             d -= 1;
05835             df += DAY_IN_SECONDS;
05836         }
05837         else if (df >= DAY_IN_SECONDS) {
05838             d += 1;
05839             df -= DAY_IN_SECONDS;
05840         }
05841 
05842         if (f_lt_p(sf, INT2FIX(0))) {
05843             df -= 1;
05844             sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05845         }
05846         else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) {
05847             df += 1;
05848             sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS));
05849         }
05850 
05851         if (f_zero_p(n))
05852             r = INT2FIX(0);
05853         else
05854             r = f_mul(n, INT2FIX(CM_PERIOD));
05855 
05856         if (d)
05857             r = f_add(r, rb_rational_new1(INT2FIX(d)));
05858         if (df)
05859             r = f_add(r, isec_to_day(df));
05860         if (f_nonzero_p(sf))
05861             r = f_add(r, ns_to_day(sf));
05862 
05863         if (TYPE(r) == T_RATIONAL)
05864             return r;
05865         return rb_rational_new1(r);
05866     }
05867 }
05868 
05869 /*
05870  * call-seq:
05871  *    d - other  ->  date or rational
05872  *
05873  * Returns the difference between the two dates if the other is a date
05874  * object.  If the other is a numeric value, returns a date object
05875  * pointing other days before self.  If the other is flonum, assumes
05876  * its precision is at most nanosecond.
05877  *
05878  *     Date.new(2001,2,3) - 1   #=> #<Date: 2001-02-02 ...>
05879  *     DateTime.new(2001,2,3) - Rational(1,2)
05880  *                              #=> #<DateTime: 2001-02-02T12:00:00+00:00 ...>
05881  *     Date.new(2001,2,3) - Date.new(2001)
05882  *                              #=> (33/1)
05883  *     DateTime.new(2001,2,3) - DateTime.new(2001,2,2,12)
05884  *                              #=> (1/2)
05885  */
05886 static VALUE
05887 d_lite_minus(VALUE self, VALUE other)
05888 {
05889     if (k_date_p(other))
05890         return minus_dd(self, other);
05891 
05892     switch (TYPE(other)) {
05893       case T_FIXNUM:
05894         return d_lite_plus(self, LONG2NUM(-FIX2LONG(other)));
05895       case T_FLOAT:
05896         return d_lite_plus(self, DBL2NUM(-RFLOAT_VALUE(other)));
05897       default:
05898         if (!k_numeric_p(other))
05899             rb_raise(rb_eTypeError, "expected numeric");
05900         /* fall through */
05901       case T_BIGNUM:
05902       case T_RATIONAL:
05903         return d_lite_plus(self, f_negate(other));
05904     }
05905 }
05906 
05907 /*
05908  * call-seq:
05909  *    d.next_day([n=1])  ->  date
05910  *
05911  * This method is equivalent to d + n.
05912  */
05913 static VALUE
05914 d_lite_next_day(int argc, VALUE *argv, VALUE self)
05915 {
05916     VALUE n;
05917 
05918     rb_scan_args(argc, argv, "01", &n);
05919     if (argc < 1)
05920         n = INT2FIX(1);
05921     return d_lite_plus(self, n);
05922 }
05923 
05924 /*
05925  * call-seq:
05926  *    d.prev_day([n=1])  ->  date
05927  *
05928  * This method is equivalent to d - n.
05929  */
05930 static VALUE
05931 d_lite_prev_day(int argc, VALUE *argv, VALUE self)
05932 {
05933     VALUE n;
05934 
05935     rb_scan_args(argc, argv, "01", &n);
05936     if (argc < 1)
05937         n = INT2FIX(1);
05938     return d_lite_minus(self, n);
05939 }
05940 
05941 /*
05942  * call-seq:
05943  *    d.next  ->  date
05944  *
05945  * Returns a date object denoting the following day.
05946  */
05947 static VALUE
05948 d_lite_next(VALUE self)
05949 {
05950     return d_lite_next_day(0, (VALUE *)NULL, self);
05951 }
05952 
05953 /*
05954  * call-seq:
05955  *    d >> n  ->  date
05956  *
05957  * Returns a date object pointing n months after self.  The n should
05958  * be a numeric value.
05959  *
05960  *    Date.new(2001,2,3) >> 1   #=> #<Date: 2001-03-03 ...>
05961  *    Date.new(2001,1,31) >> 1  #=> #<Date: 2001-02-28 ...>
05962  *    Date.new(2001,2,3) >> -2  #=> #<Date: 2000-12-03 ...>
05963  */
05964 static VALUE
05965 d_lite_rshift(VALUE self, VALUE other)
05966 {
05967     VALUE t, y, nth, rjd2;
05968     int m, d, rjd;
05969     double sg;
05970 
05971     get_d1(self);
05972     t = f_add3(f_mul(m_real_year(dat), INT2FIX(12)),
05973                INT2FIX(m_mon(dat) - 1),
05974                other);
05975     if (FIXNUM_P(t)) {
05976         long it = FIX2LONG(t);
05977         y = LONG2NUM(DIV(it, 12));
05978         it = MOD(it, 12);
05979         m = (int)it + 1;
05980     }
05981     else {
05982         y = f_idiv(t, INT2FIX(12));
05983         t = f_mod(t, INT2FIX(12));
05984         m = FIX2INT(t) + 1;
05985     }
05986     d = m_mday(dat);
05987     sg = m_sg(dat);
05988 
05989     while (1) {
05990         int ry, rm, rd, ns;
05991 
05992         if (valid_civil_p(y, m, d, sg,
05993                           &nth, &ry,
05994                           &rm, &rd, &rjd, &ns))
05995             break;
05996         if (--d < 1)
05997             rb_raise(rb_eArgError, "invalid date");
05998     }
05999     encode_jd(nth, rjd, &rjd2);
06000     return d_lite_plus(self, f_sub(rjd2, m_real_local_jd(dat)));
06001 }
06002 
06003 /*
06004  * call-seq:
06005  *    d << n  ->  date
06006  *
06007  * Returns a date object pointing n months before self.  The n should
06008  * be a numeric value.
06009  *
06010  *    Date.new(2001,2,3) << 1   #=> #<Date: 2001-01-03 ...>
06011  *    Date.new(2001,1,31) << 11 #=> #<Date: 2000-02-29 ...>
06012  *    Date.new(2001,2,3) << -1  #=> #<Date: 2001-03-03 ...>
06013  */
06014 static VALUE
06015 d_lite_lshift(VALUE self, VALUE other)
06016 {
06017     return d_lite_rshift(self, f_negate(other));
06018 }
06019 
06020 /*
06021  * call-seq:
06022  *    d.next_month([n=1])  ->  date
06023  *
06024  * This method is equivalent to d >> n
06025  */
06026 static VALUE
06027 d_lite_next_month(int argc, VALUE *argv, VALUE self)
06028 {
06029     VALUE n;
06030 
06031     rb_scan_args(argc, argv, "01", &n);
06032     if (argc < 1)
06033         n = INT2FIX(1);
06034     return d_lite_rshift(self, n);
06035 }
06036 
06037 /*
06038  * call-seq:
06039  *    d.prev_month([n=1])  ->  date
06040  *
06041  * This method is equivalent to d << n
06042  */
06043 static VALUE
06044 d_lite_prev_month(int argc, VALUE *argv, VALUE self)
06045 {
06046     VALUE n;
06047 
06048     rb_scan_args(argc, argv, "01", &n);
06049     if (argc < 1)
06050         n = INT2FIX(1);
06051     return d_lite_lshift(self, n);
06052 }
06053 
06054 /*
06055  * call-seq:
06056  *    d.next_year([n=1])  ->  date
06057  *
06058  * This method is equivalent to d >> (n * 12)
06059  */
06060 static VALUE
06061 d_lite_next_year(int argc, VALUE *argv, VALUE self)
06062 {
06063     VALUE n;
06064 
06065     rb_scan_args(argc, argv, "01", &n);
06066     if (argc < 1)
06067         n = INT2FIX(1);
06068     return d_lite_rshift(self, f_mul(n, INT2FIX(12)));
06069 }
06070 
06071 /*
06072  * call-seq:
06073  *    d.prev_year([n=1])  ->  date
06074  *
06075  * This method is equivalent to d << (n * 12)
06076  */
06077 static VALUE
06078 d_lite_prev_year(int argc, VALUE *argv, VALUE self)
06079 {
06080     VALUE n;
06081 
06082     rb_scan_args(argc, argv, "01", &n);
06083     if (argc < 1)
06084         n = INT2FIX(1);
06085     return d_lite_lshift(self, f_mul(n, INT2FIX(12)));
06086 }
06087 
06088 static VALUE d_lite_cmp(VALUE, VALUE);
06089 
06090 /*
06091  * call-seq:
06092  *    d.step(limit[, step=1])              ->  enumerator
06093  *    d.step(limit[, step=1]){|date| ...}  ->  self
06094  *
06095  * Iterates evaluation of the given block, which takes a date object.
06096  * The limit should be a date object.
06097  *
06098  *    Date.new(2001).step(Date.new(2001,-1,-1)).select{|d| d.sunday?}.size
06099  *                              #=> 52
06100  */
06101 static VALUE
06102 d_lite_step(int argc, VALUE *argv, VALUE self)
06103 {
06104     VALUE limit, step, date;
06105 
06106     rb_scan_args(argc, argv, "11", &limit, &step);
06107 
06108     if (argc < 2)
06109         step = INT2FIX(1);
06110 
06111 #if 0
06112     if (f_zero_p(step))
06113         rb_raise(rb_eArgError, "step can't be 0");
06114 #endif
06115 
06116     RETURN_ENUMERATOR(self, argc, argv);
06117 
06118     date = self;
06119     switch (FIX2INT(f_cmp(step, INT2FIX(0)))) {
06120       case -1:
06121         while (FIX2INT(d_lite_cmp(date, limit)) >= 0) {
06122             rb_yield(date);
06123             date = d_lite_plus(date, step);
06124         }
06125         break;
06126       case 0:
06127         while (1)
06128             rb_yield(date);
06129         break;
06130       case 1:
06131         while (FIX2INT(d_lite_cmp(date, limit)) <= 0) {
06132             rb_yield(date);
06133             date = d_lite_plus(date, step);
06134         }
06135         break;
06136       default:
06137         abort();
06138     }
06139     return self;
06140 }
06141 
06142 /*
06143  * call-seq:
06144  *    d.upto(max)              ->  enumerator
06145  *    d.upto(max){|date| ...}  ->  self
06146  *
06147  * This method is equivalent to step(max, 1){|date| ...}.
06148  */
06149 static VALUE
06150 d_lite_upto(VALUE self, VALUE max)
06151 {
06152     VALUE date;
06153 
06154     RETURN_ENUMERATOR(self, 1, &max);
06155 
06156     date = self;
06157     while (FIX2INT(d_lite_cmp(date, max)) <= 0) {
06158         rb_yield(date);
06159         date = d_lite_plus(date, INT2FIX(1));
06160     }
06161     return self;
06162 }
06163 
06164 /*
06165  * call-seq:
06166  *    d.downto(min)              ->  enumerator
06167  *    d.downto(min){|date| ...}  ->  self
06168  *
06169  * This method is equivalent to step(min, -1){|date| ...}.
06170  */
06171 static VALUE
06172 d_lite_downto(VALUE self, VALUE min)
06173 {
06174     VALUE date;
06175 
06176     RETURN_ENUMERATOR(self, 1, &min);
06177 
06178     date = self;
06179     while (FIX2INT(d_lite_cmp(date, min)) >= 0) {
06180         rb_yield(date);
06181         date = d_lite_plus(date, INT2FIX(-1));
06182     }
06183     return self;
06184 }
06185 
06186 static VALUE
06187 cmp_gen(VALUE self, VALUE other)
06188 {
06189     get_d1(self);
06190 
06191     if (k_numeric_p(other))
06192         return f_cmp(m_ajd(dat), other);
06193     else if (k_date_p(other))
06194         return f_cmp(m_ajd(dat), f_ajd(other));
06195     return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
06196 }
06197 
06198 static VALUE
06199 cmp_dd(VALUE self, VALUE other)
06200 {
06201     get_d2(self, other);
06202 
06203     {
06204         VALUE a_nth, b_nth,
06205             a_sf, b_sf;
06206         int a_jd, b_jd,
06207             a_df, b_df;
06208 
06209         m_canonicalize_jd(adat);
06210         m_canonicalize_jd(bdat);
06211         a_nth = m_nth(adat);
06212         b_nth = m_nth(bdat);
06213         if (f_eqeq_p(a_nth, b_nth)) {
06214             a_jd = m_jd(adat);
06215             b_jd = m_jd(bdat);
06216             if (a_jd == b_jd) {
06217                 a_df = m_df(adat);
06218                 b_df = m_df(bdat);
06219                 if (a_df == b_df) {
06220                     a_sf = m_sf(adat);
06221                     b_sf = m_sf(bdat);
06222                     if (f_eqeq_p(a_sf, b_sf)) {
06223                         return INT2FIX(0);
06224                     }
06225                     else if (f_lt_p(a_sf, b_sf)) {
06226                         return INT2FIX(-1);
06227                     }
06228                     else {
06229                         return INT2FIX(1);
06230                     }
06231                 }
06232                 else if (a_df < b_df) {
06233                     return INT2FIX(-1);
06234                 }
06235                 else {
06236                     return INT2FIX(1);
06237                 }
06238             }
06239             else if (a_jd < b_jd) {
06240                 return INT2FIX(-1);
06241             }
06242             else {
06243                 return INT2FIX(1);
06244             }
06245         }
06246         else if (f_lt_p(a_nth, b_nth)) {
06247             return INT2FIX(-1);
06248         }
06249         else {
06250             return INT2FIX(1);
06251         }
06252     }
06253 }
06254 
06255 /*
06256  * call-seq:
06257  *    d <=> other  -> -1, 0, +1 or nil
06258  *
06259  * Compares the two dates and returns -1, zero, 1 or nil.  The other
06260  * should be a date object or a numeric value as an astronomical
06261  * Julian day number.
06262  *
06263  *    Date.new(2001,2,3) <=> Date.new(2001,2,4) #=> -1
06264  *    Date.new(2001,2,3) <=> Date.new(2001,2,3) #=> 0
06265  *    Date.new(2001,2,3) <=> Date.new(2001,2,2) #=> 1
06266  *    Date.new(2001,2,3) <=> Object.new         #=> nil
06267  *    Date.new(2001,2,3) <=> Rational(4903887,2)#=> 0
06268  *
06269  * See also Comparable.
06270  */
06271 static VALUE
06272 d_lite_cmp(VALUE self, VALUE other)
06273 {
06274     if (!k_date_p(other))
06275         return cmp_gen(self, other);
06276 
06277     {
06278         get_d2(self, other);
06279 
06280         if (!(simple_dat_p(adat) && simple_dat_p(bdat) &&
06281               m_gregorian_p(adat) == m_gregorian_p(bdat)))
06282             return cmp_dd(self, other);
06283 
06284         if (have_jd_p(adat) &&
06285             have_jd_p(bdat)) {
06286             VALUE a_nth, b_nth;
06287             int a_jd, b_jd;
06288 
06289             m_canonicalize_jd(adat);
06290             m_canonicalize_jd(bdat);
06291             a_nth = m_nth(adat);
06292             b_nth = m_nth(bdat);
06293             if (f_eqeq_p(a_nth, b_nth)) {
06294                 a_jd = m_jd(adat);
06295                 b_jd = m_jd(bdat);
06296                 if (a_jd == b_jd) {
06297                     return INT2FIX(0);
06298                 }
06299                 else if (a_jd < b_jd) {
06300                     return INT2FIX(-1);
06301                 }
06302                 else {
06303                     return INT2FIX(1);
06304                 }
06305             }
06306             else if (a_nth < b_nth) {
06307                 return INT2FIX(-1);
06308             }
06309             else {
06310                 return INT2FIX(1);
06311             }
06312         }
06313         else {
06314 #ifndef USE_PACK
06315             VALUE a_nth, b_nth;
06316             int a_year, b_year,
06317                 a_mon, b_mon,
06318                 a_mday, b_mday;
06319 #else
06320             VALUE a_nth, b_nth;
06321             int a_year, b_year,
06322                 a_pd, b_pd;
06323 #endif
06324 
06325             m_canonicalize_jd(adat);
06326             m_canonicalize_jd(bdat);
06327             a_nth = m_nth(adat);
06328             b_nth = m_nth(bdat);
06329             if (f_eqeq_p(a_nth, b_nth)) {
06330                 a_year = m_year(adat);
06331                 b_year = m_year(bdat);
06332                 if (a_year == b_year) {
06333 #ifndef USE_PACK
06334                     a_mon = m_mon(adat);
06335                     b_mon = m_mon(bdat);
06336                     if (a_mon == b_mon) {
06337                         a_mday = m_mday(adat);
06338                         b_mday = m_mday(bdat);
06339                         if (a_mday == b_mday) {
06340                             return INT2FIX(0);
06341                         }
06342                         else if (a_mday < b_mday) {
06343                             return INT2FIX(-1);
06344                         }
06345                         else {
06346                             return INT2FIX(1);
06347                         }
06348                     }
06349                     else if (a_mon < b_mon) {
06350                         return INT2FIX(-1);
06351                     }
06352                     else {
06353                         return INT2FIX(1);
06354                     }
06355 #else
06356                     a_pd = m_pc(adat);
06357                     b_pd = m_pc(bdat);
06358                     if (a_pd == b_pd) {
06359                         return INT2FIX(0);
06360                     }
06361                     else if (a_pd < b_pd) {
06362                         return INT2FIX(-1);
06363                     }
06364                     else {
06365                         return INT2FIX(1);
06366                     }
06367 #endif
06368                 }
06369                 else if (a_year < b_year) {
06370                     return INT2FIX(-1);
06371                 }
06372                 else {
06373                     return INT2FIX(1);
06374                 }
06375             }
06376             else if (f_lt_p(a_nth, b_nth)) {
06377                 return INT2FIX(-1);
06378             }
06379             else {
06380                 return INT2FIX(1);
06381             }
06382         }
06383     }
06384 }
06385 
06386 static VALUE
06387 equal_gen(VALUE self, VALUE other)
06388 {
06389     get_d1(self);
06390 
06391     if (k_numeric_p(other))
06392         return f_eqeq_p(m_real_local_jd(dat), other);
06393     else if (k_date_p(other))
06394         return f_eqeq_p(m_real_local_jd(dat), f_jd(other));
06395     return rb_num_coerce_cmp(self, other, rb_intern("=="));
06396 }
06397 
06398 /*
06399  * call-seq:
06400  *    d === other  ->  bool
06401  *
06402  * Returns true if they are the same day.
06403  *
06404  *    Date.new(2001,2,3) === Date.new(2001,2,3)
06405  *                                      #=> true
06406  *    Date.new(2001,2,3) === Date.new(2001,2,4)
06407  *                                      #=> false
06408  *    DateTime.new(2001,2,3) === DateTime.new(2001,2,3,12)
06409  *                                      #=> true
06410  *    DateTime.new(2001,2,3) === DateTime.new(2001,2,3,0,0,0,'+24:00')
06411  *                                      #=> true
06412  *    DateTime.new(2001,2,3) === DateTime.new(2001,2,4,0,0,0,'+24:00')
06413  *                                      #=> false
06414  */
06415 static VALUE
06416 d_lite_equal(VALUE self, VALUE other)
06417 {
06418     if (!k_date_p(other))
06419         return equal_gen(self, other);
06420 
06421     {
06422         get_d2(self, other);
06423 
06424         if (!(m_gregorian_p(adat) == m_gregorian_p(bdat)))
06425             return equal_gen(self, other);
06426 
06427         if (have_jd_p(adat) &&
06428             have_jd_p(bdat)) {
06429             VALUE a_nth, b_nth;
06430             int a_jd, b_jd;
06431 
06432             m_canonicalize_jd(adat);
06433             m_canonicalize_jd(bdat);
06434             a_nth = m_nth(adat);
06435             b_nth = m_nth(bdat);
06436             a_jd = m_local_jd(adat);
06437             b_jd = m_local_jd(bdat);
06438             if (f_eqeq_p(a_nth, b_nth) &&
06439                 a_jd == b_jd)
06440                 return Qtrue;
06441             return Qfalse;
06442         }
06443         else {
06444 #ifndef USE_PACK
06445             VALUE a_nth, b_nth;
06446             int a_year, b_year,
06447                 a_mon, b_mon,
06448                 a_mday, b_mday;
06449 #else
06450             VALUE a_nth, b_nth;
06451             int a_year, b_year,
06452                 a_pd, b_pd;
06453 #endif
06454 
06455             m_canonicalize_jd(adat);
06456             m_canonicalize_jd(bdat);
06457             a_nth = m_nth(adat);
06458             b_nth = m_nth(bdat);
06459             if (f_eqeq_p(a_nth, b_nth)) {
06460                 a_year = m_year(adat);
06461                 b_year = m_year(bdat);
06462                 if (a_year == b_year) {
06463 #ifndef USE_PACK
06464                     a_mon = m_mon(adat);
06465                     b_mon = m_mon(bdat);
06466                     if (a_mon == b_mon) {
06467                         a_mday = m_mday(adat);
06468                         b_mday = m_mday(bdat);
06469                         if (a_mday == b_mday)
06470                             return Qtrue;
06471                     }
06472 #else
06473                     /* mon and mday only */
06474                     a_pd = (m_pc(adat) >> MDAY_SHIFT);
06475                     b_pd = (m_pc(bdat) >> MDAY_SHIFT);
06476                     if (a_pd == b_pd) {
06477                         return Qtrue;
06478                     }
06479 #endif
06480                 }
06481             }
06482             return Qfalse;
06483         }
06484     }
06485 }
06486 
06487 /* :nodoc: */
06488 static VALUE
06489 d_lite_eql_p(VALUE self, VALUE other)
06490 {
06491     if (!k_date_p(other))
06492         return Qfalse;
06493     return f_zero_p(d_lite_cmp(self, other));
06494 }
06495 
06496 /* :nodoc: */
06497 static VALUE
06498 d_lite_hash(VALUE self)
06499 {
06500     st_index_t v, h[4];
06501 
06502     get_d1(self);
06503     h[0] = m_nth(dat);
06504     h[1] = m_jd(dat);
06505     h[2] = m_df(dat);
06506     h[3] = m_sf(dat);
06507     v = rb_memhash(h, sizeof(h));
06508     return LONG2FIX(v);
06509 }
06510 
06511 #include "date_tmx.h"
06512 static void set_tmx(VALUE, struct tmx *);
06513 static VALUE strftimev(const char *, VALUE,
06514                        void (*)(VALUE, struct tmx *));
06515 
06516 /*
06517  * call-seq:
06518  *    d.to_s  ->  string
06519  *
06520  * Returns a string in an ISO 8601 format (This method doesn't use the
06521  * expanded representations).
06522  *
06523  *     Date.new(2001,2,3).to_s  #=> "2001-02-03"
06524  */
06525 static VALUE
06526 d_lite_to_s(VALUE self)
06527 {
06528     return strftimev("%Y-%m-%d", self, set_tmx);
06529 }
06530 
06531 #ifndef NDEBUG
06532 static VALUE
06533 mk_inspect_flags(union DateData *x)
06534 {
06535     return rb_enc_sprintf(rb_usascii_encoding(),
06536                           "%c%c%c%c%c",
06537                           (x->flags & COMPLEX_DAT) ? 'C' : 'S',
06538                           (x->flags & HAVE_JD)     ? 'j' : '-',
06539                           (x->flags & HAVE_DF)     ? 'd' : '-',
06540                           (x->flags & HAVE_CIVIL)  ? 'c' : '-',
06541                           (x->flags & HAVE_TIME)   ? 't' : '-');
06542 }
06543 
06544 static VALUE
06545 mk_inspect_raw(union DateData *x, const char *klass)
06546 {
06547     if (simple_dat_p(x)) {
06548         VALUE nth, flags;
06549 
06550         RB_GC_GUARD(nth) = f_inspect(x->s.nth);
06551         RB_GC_GUARD(flags) = mk_inspect_flags(x);
06552 
06553         return rb_enc_sprintf(rb_usascii_encoding(),
06554                               "#<%s: "
06555                               "(%sth,%dj),+0s,%.0fj; "
06556                               "%dy%dm%dd; %s>",
06557                               klass ? klass : "?",
06558                               RSTRING_PTR(nth), x->s.jd, x->s.sg,
06559 #ifndef USE_PACK
06560                               x->s.year, x->s.mon, x->s.mday,
06561 #else
06562                               x->s.year,
06563                               EX_MON(x->s.pc), EX_MDAY(x->s.pc),
06564 #endif
06565                               RSTRING_PTR(flags));
06566     }
06567     else {
06568         VALUE nth, sf, flags;
06569 
06570         RB_GC_GUARD(nth) = f_inspect(x->c.nth);
06571         RB_GC_GUARD(sf) = f_inspect(x->c.sf);
06572         RB_GC_GUARD(flags) = mk_inspect_flags(x);
06573 
06574         return rb_enc_sprintf(rb_usascii_encoding(),
06575                               "#<%s: "
06576                               "(%sth,%dj,%ds,%sn),%+ds,%.0fj; "
06577                               "%dy%dm%dd %dh%dm%ds; %s>",
06578                               klass ? klass : "?",
06579                               RSTRING_PTR(nth), x->c.jd, x->c.df,
06580                               RSTRING_PTR(sf),
06581                               x->c.of, x->c.sg,
06582 #ifndef USE_PACK
06583                               x->c.year, x->c.mon, x->c.mday,
06584                               x->c.hour, x->c.min, x->c.sec,
06585 #else
06586                               x->c.year,
06587                               EX_MON(x->c.pc), EX_MDAY(x->c.pc),
06588                               EX_HOUR(x->c.pc), EX_MIN(x->c.pc),
06589                               EX_SEC(x->c.pc),
06590 #endif
06591                               RSTRING_PTR(flags));
06592     }
06593 }
06594 
06595 static VALUE
06596 d_lite_inspect_raw(VALUE self)
06597 {
06598     get_d1(self);
06599     return mk_inspect_raw(dat, rb_obj_classname(self));
06600 }
06601 #endif
06602 
06603 static VALUE
06604 mk_inspect(union DateData *x, const char *klass, const char *to_s)
06605 {
06606     VALUE jd, sf;
06607 
06608     RB_GC_GUARD(jd) = f_inspect(m_real_jd(x));
06609     RB_GC_GUARD(sf) = f_inspect(m_sf(x));
06610 
06611     return rb_enc_sprintf(rb_usascii_encoding(),
06612                           "#<%s: %s ((%sj,%ds,%sn),%+ds,%.0fj)>",
06613                           klass ? klass : "?",
06614                           to_s ? to_s : "?",
06615                           RSTRING_PTR(jd), m_df(x), RSTRING_PTR(sf),
06616                           m_of(x), m_sg(x));
06617 }
06618 
06619 /*
06620  * call-seq:
06621  *    d.inspect  ->  string
06622  *
06623  * Returns the value as a string for inspection.
06624  *
06625  *    Date.new(2001,2,3).inspect
06626  *              #=> "#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>"
06627  *    DateTime.new(2001,2,3,4,5,6,'-7').inspect
06628  *              #=> "#<DateTime: 2001-02-03T04:05:06-07:00 ((2451944j,39906s,0n),-25200s,2299161j)>"
06629  */
06630 static VALUE
06631 d_lite_inspect(VALUE self)
06632 {
06633     get_d1(self);
06634     {
06635         VALUE to_s;
06636 
06637         RB_GC_GUARD(to_s) = f_to_s(self);
06638         return mk_inspect(dat, rb_obj_classname(self), RSTRING_PTR(to_s));
06639     }
06640 }
06641 
06642 #include <errno.h>
06643 #include "date_tmx.h"
06644 
06645 size_t date_strftime(char *s, size_t maxsize, const char *format,
06646                      const struct tmx *tmx);
06647 
06648 #define SMALLBUF 100
06649 static size_t
06650 date_strftime_alloc(char **buf, const char *format,
06651                     struct tmx *tmx)
06652 {
06653     size_t size, len, flen;
06654 
06655     (*buf)[0] = '\0';
06656     flen = strlen(format);
06657     if (flen == 0) {
06658         return 0;
06659     }
06660     errno = 0;
06661     len = date_strftime(*buf, SMALLBUF, format, tmx);
06662     if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
06663     for (size=1024; ; size*=2) {
06664         *buf = xmalloc(size);
06665         (*buf)[0] = '\0';
06666         len = date_strftime(*buf, size, format, tmx);
06667         /*
06668          * buflen can be zero EITHER because there's not enough
06669          * room in the string, or because the control command
06670          * goes to the empty string. Make a reasonable guess that
06671          * if the buffer is 1024 times bigger than the length of the
06672          * format string, it's not failing for lack of room.
06673          */
06674         if (len > 0) break;
06675         xfree(*buf);
06676         if (size >= 1024 * flen) {
06677             rb_sys_fail(format);
06678             break;
06679         }
06680     }
06681     return len;
06682 }
06683 
06684 static VALUE
06685 tmx_m_secs(union DateData *x)
06686 {
06687     VALUE s;
06688     int df;
06689 
06690     s = day_to_sec(f_sub(m_real_jd(x),
06691                          UNIX_EPOCH_IN_CJD));
06692     if (simple_dat_p(x))
06693         return s;
06694     df = m_df(x);
06695     if (df)
06696         s = f_add(s, INT2FIX(df));
06697     return s;
06698 }
06699 
06700 #define MILLISECOND_IN_NANOSECONDS 1000000
06701 
06702 static VALUE
06703 tmx_m_msecs(union DateData *x)
06704 {
06705     VALUE s, sf;
06706 
06707     s = sec_to_ms(tmx_m_secs(x));
06708     if (simple_dat_p(x))
06709         return s;
06710     sf = m_sf(x);
06711     if (f_nonzero_p(sf))
06712         s = f_add(s, f_div(sf, INT2FIX(MILLISECOND_IN_NANOSECONDS)));
06713     return s;
06714 }
06715 
06716 static int
06717 tmx_m_of(union DateData *x)
06718 {
06719     return m_of(x);
06720 }
06721 
06722 static char *
06723 tmx_m_zone(union DateData *x)
06724 {
06725     return RSTRING_PTR(m_zone(x));
06726 }
06727 
06728 static struct tmx_funcs tmx_funcs = {
06729     (VALUE (*)(void *))m_real_year,
06730     (int (*)(void *))m_yday,
06731     (int (*)(void *))m_mon,
06732     (int (*)(void *))m_mday,
06733     (VALUE (*)(void *))m_real_cwyear,
06734     (int (*)(void *))m_cweek,
06735     (int (*)(void *))m_cwday,
06736     (int (*)(void *))m_wnum0,
06737     (int (*)(void *))m_wnum1,
06738     (int (*)(void *))m_wday,
06739     (int (*)(void *))m_hour,
06740     (int (*)(void *))m_min,
06741     (int (*)(void *))m_sec,
06742     (VALUE (*)(void *))m_sf_in_sec,
06743     (VALUE (*)(void *))tmx_m_secs,
06744     (VALUE (*)(void *))tmx_m_msecs,
06745     (int (*)(void *))tmx_m_of,
06746     (char *(*)(void *))tmx_m_zone
06747 };
06748 
06749 static void
06750 set_tmx(VALUE self, struct tmx *tmx)
06751 {
06752     get_d1(self);
06753     tmx->dat = (void *)dat;
06754     tmx->funcs = &tmx_funcs;
06755 }
06756 
06757 static VALUE
06758 date_strftime_internal(int argc, VALUE *argv, VALUE self,
06759                        const char *default_fmt,
06760                        void (*func)(VALUE, struct tmx *))
06761 {
06762     VALUE vfmt;
06763     const char *fmt;
06764     long len;
06765     char buffer[SMALLBUF], *buf = buffer;
06766     struct tmx tmx;
06767     VALUE str;
06768 
06769     rb_scan_args(argc, argv, "01", &vfmt);
06770 
06771     if (argc < 1)
06772         vfmt = rb_usascii_str_new2(default_fmt);
06773     else {
06774         StringValue(vfmt);
06775         if (!rb_enc_str_asciicompat_p(vfmt)) {
06776             rb_raise(rb_eArgError,
06777                      "format should have ASCII compatible encoding");
06778         }
06779     }
06780     fmt = RSTRING_PTR(vfmt);
06781     len = RSTRING_LEN(vfmt);
06782     (*func)(self, &tmx);
06783     if (memchr(fmt, '\0', len)) {
06784         /* Ruby string may contain \0's. */
06785         const char *p = fmt, *pe = fmt + len;
06786 
06787         str = rb_str_new(0, 0);
06788         while (p < pe) {
06789             len = date_strftime_alloc(&buf, p, &tmx);
06790             rb_str_cat(str, buf, len);
06791             p += strlen(p);
06792             if (buf != buffer) {
06793                 xfree(buf);
06794                 buf = buffer;
06795             }
06796             for (fmt = p; p < pe && !*p; ++p);
06797             if (p > fmt) rb_str_cat(str, fmt, p - fmt);
06798         }
06799         rb_enc_copy(str, vfmt);
06800         OBJ_INFECT(str, vfmt);
06801         return str;
06802     }
06803     else
06804         len = date_strftime_alloc(&buf, fmt, &tmx);
06805 
06806     str = rb_str_new(buf, len);
06807     if (buf != buffer) xfree(buf);
06808     rb_enc_copy(str, vfmt);
06809     OBJ_INFECT(str, vfmt);
06810     return str;
06811 }
06812 
06813 /*
06814  * call-seq:
06815  *    d.strftime([format='%F'])  ->  string
06816  *
06817  *  Formats date according to the directives in the given format
06818  *  string.
06819  *  The directives begins with a percent (%) character.
06820  *  Any text not listed as a directive will be passed through to the
06821  *  output string.
06822  *
06823  *  The directive consists of a percent (%) character,
06824  *  zero or more flags, optional minimum field width,
06825  *  optional modifier and a conversion specifier
06826  *  as follows.
06827  *
06828  *    %<flags><width><modifier><conversion>
06829  *
06830  *  Flags:
06831  *    -  don't pad a numerical output.
06832  *    _  use spaces for padding.
06833  *    0  use zeros for padding.
06834  *    ^  upcase the result string.
06835  *    #  change case.
06836  *
06837  *  The minimum field width specifies the minimum width.
06838  *
06839  *  The modifiers are "E", "O", ":", "::" and ":::".
06840  *  "E" and "O" are ignored.  No effect to result currently.
06841  *
06842  *  Format directives:
06843  *
06844  *    Date (Year, Month, Day):
06845  *      %Y - Year with century (can be negative, 4 digits at least)
06846  *              -0001, 0000, 1995, 2009, 14292, etc.
06847  *      %C - year / 100 (round down.  20 in 2009)
06848  *      %y - year % 100 (00..99)
06849  *
06850  *      %m - Month of the year, zero-padded (01..12)
06851  *              %_m  blank-padded ( 1..12)
06852  *              %-m  no-padded (1..12)
06853  *      %B - The full month name (``January'')
06854  *              %^B  uppercased (``JANUARY'')
06855  *      %b - The abbreviated month name (``Jan'')
06856  *              %^b  uppercased (``JAN'')
06857  *      %h - Equivalent to %b
06858  *
06859  *      %d - Day of the month, zero-padded (01..31)
06860  *              %-d  no-padded (1..31)
06861  *      %e - Day of the month, blank-padded ( 1..31)
06862  *
06863  *      %j - Day of the year (001..366)
06864  *
06865  *    Time (Hour, Minute, Second, Subsecond):
06866  *      %H - Hour of the day, 24-hour clock, zero-padded (00..23)
06867  *      %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
06868  *      %I - Hour of the day, 12-hour clock, zero-padded (01..12)
06869  *      %l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
06870  *      %P - Meridian indicator, lowercase (``am'' or ``pm'')
06871  *      %p - Meridian indicator, uppercase (``AM'' or ``PM'')
06872  *
06873  *      %M - Minute of the hour (00..59)
06874  *
06875  *      %S - Second of the minute (00..59)
06876  *
06877  *      %L - Millisecond of the second (000..999)
06878  *      %N - Fractional seconds digits, default is 9 digits (nanosecond)
06879  *              %3N  millisecond (3 digits)   %15N femtosecond (15 digits)
06880  *              %6N  microsecond (6 digits)   %18N attosecond  (18 digits)
06881  *              %9N  nanosecond  (9 digits)   %21N zeptosecond (21 digits)
06882  *              %12N picosecond (12 digits)   %24N yoctosecond (24 digits)
06883  *
06884  *    Time zone:
06885  *      %z - Time zone as hour and minute offset from UTC (e.g. +0900)
06886  *              %:z - hour and minute offset from UTC with a colon (e.g. +09:00)
06887  *              %::z - hour, minute and second offset from UTC (e.g. +09:00:00)
06888  *              %:::z - hour, minute and second offset from UTC
06889  *                                                (e.g. +09, +09:30, +09:30:30)
06890  *      %Z - Time zone abbreviation name or something similar information.
06891  *
06892  *    Weekday:
06893  *      %A - The full weekday name (``Sunday'')
06894  *              %^A  uppercased (``SUNDAY'')
06895  *      %a - The abbreviated name (``Sun'')
06896  *              %^a  uppercased (``SUN'')
06897  *      %u - Day of the week (Monday is 1, 1..7)
06898  *      %w - Day of the week (Sunday is 0, 0..6)
06899  *
06900  *    ISO 8601 week-based year and week number:
06901  *    The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
06902  *    The days in the year before the first week are in the last week of
06903  *    the previous year.
06904  *      %G - The week-based year
06905  *      %g - The last 2 digits of the week-based year (00..99)
06906  *      %V - Week number of the week-based year (01..53)
06907  *
06908  *    Week number:
06909  *    The week 1 of YYYY starts with a Sunday or Monday (according to %U
06910  *    or %W).  The days in the year before the first week are in week 0.
06911  *      %U - Week number of the year.  The week starts with Sunday.  (00..53)
06912  *      %W - Week number of the year.  The week starts with Monday.  (00..53)
06913  *
06914  *    Seconds since the Unix Epoch:
06915  *      %s - Number of seconds since 1970-01-01 00:00:00 UTC.
06916  *      %Q - Number of milliseconds since 1970-01-01 00:00:00 UTC.
06917  *
06918  *    Literal string:
06919  *      %n - Newline character (\n)
06920  *      %t - Tab character (\t)
06921  *      %% - Literal ``%'' character
06922  *
06923  *    Combination:
06924  *      %c - date and time (%a %b %e %T %Y)
06925  *      %D - Date (%m/%d/%y)
06926  *      %F - The ISO 8601 date format (%Y-%m-%d)
06927  *      %v - VMS date (%e-%b-%Y)
06928  *      %x - Same as %D
06929  *      %X - Same as %T
06930  *      %r - 12-hour time (%I:%M:%S %p)
06931  *      %R - 24-hour time (%H:%M)
06932  *      %T - 24-hour time (%H:%M:%S)
06933  *      %+ - date(1) (%a %b %e %H:%M:%S %Z %Y)
06934  *
06935  *  This method is similar to strftime() function defined in ISO C and POSIX.
06936  *  Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z)
06937  *  are locale dependent in the function.
06938  *  However this method is locale independent.
06939  *  So, the result may differ even if a same format string is used in other
06940  *  systems such as C.
06941  *  It is good practice to avoid %x and %X because there are corresponding
06942  *  locale independent representations, %D and %T.
06943  *
06944  *  Examples:
06945  *
06946  *    d = DateTime.new(2007,11,19,8,37,48,"-06:00")
06947  *                              #=> #<DateTime: 2007-11-19T08:37:48-0600 ...>
06948  *    d.strftime("Printed on %m/%d/%Y")   #=> "Printed on 11/19/2007"
06949  *    d.strftime("at %I:%M%p")            #=> "at 08:37AM"
06950  *
06951  *  Various ISO 8601 formats:
06952  *    %Y%m%d           => 20071119                  Calendar date (basic)
06953  *    %F               => 2007-11-19                Calendar date (extended)
06954  *    %Y-%m            => 2007-11                   Calendar date, reduced accuracy, specific month
06955  *    %Y               => 2007                      Calendar date, reduced accuracy, specific year
06956  *    %C               => 20                        Calendar date, reduced accuracy, specific century
06957  *    %Y%j             => 2007323                   Ordinal date (basic)
06958  *    %Y-%j            => 2007-323                  Ordinal date (extended)
06959  *    %GW%V%u          => 2007W471                  Week date (basic)
06960  *    %G-W%V-%u        => 2007-W47-1                Week date (extended)
06961  *    %GW%V            => 2007W47                   Week date, reduced accuracy, specific week (basic)
06962  *    %G-W%V           => 2007-W47                  Week date, reduced accuracy, specific week (extended)
06963  *    %H%M%S           => 083748                    Local time (basic)
06964  *    %T               => 08:37:48                  Local time (extended)
06965  *    %H%M             => 0837                      Local time, reduced accuracy, specific minute (basic)
06966  *    %H:%M            => 08:37                     Local time, reduced accuracy, specific minute (extended)
06967  *    %H               => 08                        Local time, reduced accuracy, specific hour
06968  *    %H%M%S,%L        => 083748,000                Local time with decimal fraction, comma as decimal sign (basic)
06969  *    %T,%L            => 08:37:48,000              Local time with decimal fraction, comma as decimal sign (extended)
06970  *    %H%M%S.%L        => 083748.000                Local time with decimal fraction, full stop as decimal sign (basic)
06971  *    %T.%L            => 08:37:48.000              Local time with decimal fraction, full stop as decimal sign (extended)
06972  *    %H%M%S%z         => 083748-0600               Local time and the difference from UTC (basic)
06973  *    %T%:z            => 08:37:48-06:00            Local time and the difference from UTC (extended)
06974  *    %Y%m%dT%H%M%S%z  => 20071119T083748-0600      Date and time of day for calendar date (basic)
06975  *    %FT%T%:z         => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended)
06976  *    %Y%jT%H%M%S%z    => 2007323T083748-0600       Date and time of day for ordinal date (basic)
06977  *    %Y-%jT%T%:z      => 2007-323T08:37:48-06:00   Date and time of day for ordinal date (extended)
06978  *    %GW%V%uT%H%M%S%z => 2007W471T083748-0600      Date and time of day for week date (basic)
06979  *    %G-W%V-%uT%T%:z  => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended)
06980  *    %Y%m%dT%H%M      => 20071119T0837             Calendar date and local time (basic)
06981  *    %FT%R            => 2007-11-19T08:37          Calendar date and local time (extended)
06982  *    %Y%jT%H%MZ       => 2007323T0837Z             Ordinal date and UTC of day (basic)
06983  *    %Y-%jT%RZ        => 2007-323T08:37Z           Ordinal date and UTC of day (extended)
06984  *    %GW%V%uT%H%M%z   => 2007W471T0837-0600        Week date and local time and difference from UTC (basic)
06985  *    %G-W%V-%uT%R%:z  => 2007-W47-1T08:37-06:00    Week date and local time and difference from UTC (extended)
06986  *
06987  * See also strftime(3) and strptime.
06988  */
06989 static VALUE
06990 d_lite_strftime(int argc, VALUE *argv, VALUE self)
06991 {
06992     return date_strftime_internal(argc, argv, self,
06993                                   "%Y-%m-%d", set_tmx);
06994 }
06995 
06996 static VALUE
06997 strftimev(const char *fmt, VALUE self,
06998           void (*func)(VALUE, struct tmx *))
06999 {
07000     char buffer[SMALLBUF], *buf = buffer;
07001     struct tmx tmx;
07002     long len;
07003     VALUE str;
07004 
07005     (*func)(self, &tmx);
07006     len = date_strftime_alloc(&buf, fmt, &tmx);
07007     str = rb_usascii_str_new(buf, len);
07008     if (buf != buffer) xfree(buf);
07009     return str;
07010 }
07011 
07012 /*
07013  * call-seq:
07014  *    d.asctime  ->  string
07015  *    d.ctime    ->  string
07016  *
07017  * Returns a string in asctime(3) format (but without "\n\0" at the
07018  * end).  This method is equivalent to strftime('%c').
07019  *
07020  * See also asctime(3) or ctime(3).
07021  */
07022 static VALUE
07023 d_lite_asctime(VALUE self)
07024 {
07025     return strftimev("%a %b %e %H:%M:%S %Y", self, set_tmx);
07026 }
07027 
07028 /*
07029  * call-seq:
07030  *    d.iso8601    ->  string
07031  *    d.xmlschema  ->  string
07032  *
07033  * This method is equivalent to strftime('%F').
07034  */
07035 static VALUE
07036 d_lite_iso8601(VALUE self)
07037 {
07038     return strftimev("%Y-%m-%d", self, set_tmx);
07039 }
07040 
07041 /*
07042  * call-seq:
07043  *    d.rfc3339  ->  string
07044  *
07045  * This method is equivalent to strftime('%FT%T%:z').
07046  */
07047 static VALUE
07048 d_lite_rfc3339(VALUE self)
07049 {
07050     return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx);
07051 }
07052 
07053 /*
07054  * call-seq:
07055  *    d.rfc2822  ->  string
07056  *    d.rfc822   ->  string
07057  *
07058  * This method is equivalent to strftime('%a, %-d %b %Y %T %z').
07059  */
07060 static VALUE
07061 d_lite_rfc2822(VALUE self)
07062 {
07063     return strftimev("%a, %-d %b %Y %T %z", self, set_tmx);
07064 }
07065 
07066 /*
07067  * call-seq:
07068  *    d.httpdate  ->  string
07069  *
07070  * This method is equivalent to strftime('%a, %d %b %Y %T GMT').
07071  * See also RFC 2616.
07072  */
07073 static VALUE
07074 d_lite_httpdate(VALUE self)
07075 {
07076     volatile VALUE dup = dup_obj_with_new_offset(self, 0);
07077     return strftimev("%a, %d %b %Y %T GMT", dup, set_tmx);
07078 }
07079 
07080 static VALUE
07081 jisx0301_date(VALUE jd, VALUE y)
07082 {
07083     VALUE a[2];
07084 
07085     if (f_lt_p(jd, INT2FIX(2405160)))
07086         return rb_usascii_str_new2("%Y-%m-%d");
07087     if (f_lt_p(jd, INT2FIX(2419614))) {
07088         a[0] = rb_usascii_str_new2("M%02d" ".%%m.%%d");
07089         a[1] = f_sub(y, INT2FIX(1867));
07090     }
07091     else if (f_lt_p(jd, INT2FIX(2424875))) {
07092         a[0] = rb_usascii_str_new2("T%02d" ".%%m.%%d");
07093         a[1] = f_sub(y, INT2FIX(1911));
07094     }
07095     else if (f_lt_p(jd, INT2FIX(2447535))) {
07096         a[0] = rb_usascii_str_new2("S%02d" ".%%m.%%d");
07097         a[1] = f_sub(y, INT2FIX(1925));
07098     }
07099     else {
07100         a[0] = rb_usascii_str_new2("H%02d" ".%%m.%%d");
07101         a[1] = f_sub(y, INT2FIX(1988));
07102     }
07103     return rb_f_sprintf(2, a);
07104 }
07105 
07106 /*
07107  * call-seq:
07108  *    d.jisx0301  ->  string
07109  *
07110  * Returns a string in a JIS X 0301 format.
07111  *
07112  *    Date.new(2001,2,3).jisx0301       #=> "H13.02.03"
07113  */
07114 static VALUE
07115 d_lite_jisx0301(VALUE self)
07116 {
07117     VALUE s;
07118 
07119     get_d1(self);
07120     s = jisx0301_date(m_real_local_jd(dat),
07121                       m_real_year(dat));
07122     return strftimev(RSTRING_PTR(s), self, set_tmx);
07123 }
07124 
07125 #ifndef NDEBUG
07126 static VALUE
07127 d_lite_marshal_dump_old(VALUE self)
07128 {
07129     VALUE a;
07130 
07131     get_d1(self);
07132 
07133     a = rb_ary_new3(3,
07134                     m_ajd(dat),
07135                     m_of_in_day(dat),
07136                     DBL2NUM(m_sg(dat)));
07137 
07138     if (FL_TEST(self, FL_EXIVAR)) {
07139         rb_copy_generic_ivar(a, self);
07140         FL_SET(a, FL_EXIVAR);
07141     }
07142 
07143     return a;
07144 }
07145 #endif
07146 
07147 /* :nodoc: */
07148 static VALUE
07149 d_lite_marshal_dump(VALUE self)
07150 {
07151     VALUE a;
07152 
07153     get_d1(self);
07154 
07155     a = rb_ary_new3(6,
07156                     m_nth(dat),
07157                     INT2FIX(m_jd(dat)),
07158                     INT2FIX(m_df(dat)),
07159                     m_sf(dat),
07160                     INT2FIX(m_of(dat)),
07161                     DBL2NUM(m_sg(dat)));
07162 
07163     if (FL_TEST(self, FL_EXIVAR)) {
07164         rb_copy_generic_ivar(a, self);
07165         FL_SET(a, FL_EXIVAR);
07166     }
07167 
07168     return a;
07169 }
07170 
07171 /* :nodoc: */
07172 static VALUE
07173 d_lite_marshal_load(VALUE self, VALUE a)
07174 {
07175     get_d1(self);
07176 
07177     rb_check_frozen(self);
07178     rb_check_trusted(self);
07179 
07180     if (TYPE(a) != T_ARRAY)
07181         rb_raise(rb_eTypeError, "expected an array");
07182 
07183     switch (RARRAY_LEN(a)) {
07184       case 2: /* 1.6.x */
07185       case 3: /* 1.8.x, 1.9.2 */
07186         {
07187             VALUE ajd, of, sg, nth, sf;
07188             int jd, df, rof;
07189             double rsg;
07190 
07191 
07192             if  (RARRAY_LEN(a) == 2) {
07193                 ajd = f_sub(RARRAY_PTR(a)[0], half_days_in_day);
07194                 of = INT2FIX(0);
07195                 sg = RARRAY_PTR(a)[1];
07196                 if (!k_numeric_p(sg))
07197                     sg = DBL2NUM(RTEST(sg) ? GREGORIAN : JULIAN);
07198             }
07199             else {
07200                 ajd = RARRAY_PTR(a)[0];
07201                 of = RARRAY_PTR(a)[1];
07202                 sg = RARRAY_PTR(a)[2];
07203             }
07204 
07205             old_to_new(ajd, of, sg,
07206                        &nth, &jd, &df, &sf, &rof, &rsg);
07207 
07208             if (!df && f_zero_p(sf) && !rof) {
07209                 set_to_simple(&dat->s, nth, jd, rsg, 0, 0, 0, HAVE_JD);
07210             } else {
07211                 if (!complex_dat_p(dat))
07212                     rb_raise(rb_eArgError,
07213                              "cannot load complex into simple");
07214 
07215                 set_to_complex(&dat->c, nth, jd, df, sf, rof, rsg,
07216                                0, 0, 0, 0, 0, 0,
07217                                HAVE_JD | HAVE_DF | COMPLEX_DAT);
07218             }
07219         }
07220         break;
07221       case 6:
07222         {
07223             VALUE nth, sf;
07224             int jd, df, of;
07225             double sg;
07226 
07227             nth = RARRAY_PTR(a)[0];
07228             jd = NUM2INT(RARRAY_PTR(a)[1]);
07229             df = NUM2INT(RARRAY_PTR(a)[2]);
07230             sf = RARRAY_PTR(a)[3];
07231             of = NUM2INT(RARRAY_PTR(a)[4]);
07232             sg = NUM2DBL(RARRAY_PTR(a)[5]);
07233             if (!df && f_zero_p(sf) && !of) {
07234                 set_to_simple(&dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD);
07235             } else {
07236                 if (!complex_dat_p(dat))
07237                     rb_raise(rb_eArgError,
07238                              "cannot load complex into simple");
07239 
07240                 set_to_complex(&dat->c, nth, jd, df, sf, of, sg,
07241                                0, 0, 0, 0, 0, 0,
07242                                HAVE_JD | HAVE_DF | COMPLEX_DAT);
07243             }
07244         }
07245         break;
07246       default:
07247         rb_raise(rb_eTypeError, "invalid size");
07248         break;
07249     }
07250 
07251     if (FL_TEST(a, FL_EXIVAR)) {
07252         rb_copy_generic_ivar(self, a);
07253         FL_SET(self, FL_EXIVAR);
07254     }
07255 
07256     return self;
07257 }
07258 
07259 /* :nodoc: */
07260 static VALUE
07261 date_s__load(VALUE klass, VALUE s)
07262 {
07263     VALUE a, obj;
07264 
07265     a = rb_marshal_load(s);
07266     obj = d_lite_s_alloc(klass);
07267     return d_lite_marshal_load(obj, a);
07268 }
07269 
07270 /* datetime */
07271 
07272 /*
07273  * call-seq:
07274  *    DateTime.jd([jd=0[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]])  ->  datetime
07275  *
07276  * Creates a datetime object denoting the given chronological Julian
07277  * day number.
07278  *
07279  *    DateTime.jd(2451944)      #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
07280  *    DateTime.jd(2451945)      #=> #<DateTime: 2001-02-04T00:00:00+00:00 ...>
07281  *    DateTime.jd(Rational('0.5'))
07282  *                              #=> #<DateTime: -4712-01-01T12:00:00+00:00 ...>
07283  */
07284 static VALUE
07285 datetime_s_jd(int argc, VALUE *argv, VALUE klass)
07286 {
07287     VALUE vjd, vh, vmin, vs, vof, vsg, jd, fr, fr2, ret;
07288     int h, min, s, rof;
07289     double sg;
07290 
07291     rb_scan_args(argc, argv, "06", &vjd, &vh, &vmin, &vs, &vof, &vsg);
07292 
07293     jd = INT2FIX(0);
07294 
07295     h = min = s = 0;
07296     fr2 = INT2FIX(0);
07297     rof = 0;
07298     sg = DEFAULT_SG;
07299 
07300     switch (argc) {
07301       case 6:
07302         val2sg(vsg, sg);
07303       case 5:
07304         val2off(vof, rof);
07305       case 4:
07306         num2int_with_frac(s, positive_inf);
07307       case 3:
07308         num2int_with_frac(min, 3);
07309       case 2:
07310         num2int_with_frac(h, 2);
07311       case 1:
07312         num2num_with_frac(jd, 1);
07313     }
07314 
07315     {
07316         VALUE nth;
07317         int rh, rmin, rs, rjd, rjd2;
07318 
07319         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07320             rb_raise(rb_eArgError, "invalid date");
07321         canon24oc();
07322 
07323         decode_jd(jd, &nth, &rjd);
07324         rjd2 = jd_local_to_utc(rjd,
07325                                time_to_df(rh, rmin, rs),
07326                                rof);
07327 
07328         ret = d_complex_new_internal(klass,
07329                                      nth, rjd2,
07330                                      0, INT2FIX(0),
07331                                      rof, sg,
07332                                      0, 0, 0,
07333                                      rh, rmin, rs,
07334                                      HAVE_JD | HAVE_TIME);
07335     }
07336     add_frac();
07337     return ret;
07338 }
07339 
07340 /*
07341  * call-seq:
07342  *    DateTime.ordinal([year=-4712[, yday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]])  ->  datetime
07343  *
07344  * Creates a date-time object denoting the given ordinal date.
07345  *
07346  *    DateTime.ordinal(2001,34) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
07347  *    DateTime.ordinal(2001,34,4,5,6,'+7')
07348  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07349  *    DateTime.ordinal(2001,-332,-20,-55,-54,'+7')
07350  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07351  */
07352 static VALUE
07353 datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
07354 {
07355     VALUE vy, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
07356     int d, h, min, s, rof;
07357     double sg;
07358 
07359     rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg);
07360 
07361     y = INT2FIX(-4712);
07362     d = 1;
07363 
07364     h = min = s = 0;
07365     fr2 = INT2FIX(0);
07366     rof = 0;
07367     sg = DEFAULT_SG;
07368 
07369     switch (argc) {
07370       case 7:
07371         val2sg(vsg, sg);
07372       case 6:
07373         val2off(vof, rof);
07374       case 5:
07375         num2int_with_frac(s, positive_inf);
07376       case 4:
07377         num2int_with_frac(min, 4);
07378       case 3:
07379         num2int_with_frac(h, 3);
07380       case 2:
07381         num2int_with_frac(d, 2);
07382       case 1:
07383         y = vy;
07384     }
07385 
07386     {
07387         VALUE nth;
07388         int ry, rd, rh, rmin, rs, rjd, rjd2, ns;
07389 
07390         if (!valid_ordinal_p(y, d, sg,
07391                              &nth, &ry,
07392                              &rd, &rjd,
07393                              &ns))
07394             rb_raise(rb_eArgError, "invalid date");
07395         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07396             rb_raise(rb_eArgError, "invalid date");
07397         canon24oc();
07398 
07399         rjd2 = jd_local_to_utc(rjd,
07400                                time_to_df(rh, rmin, rs),
07401                                rof);
07402 
07403         ret = d_complex_new_internal(klass,
07404                                      nth, rjd2,
07405                                      0, INT2FIX(0),
07406                                      rof, sg,
07407                                      0, 0, 0,
07408                                      rh, rmin, rs,
07409                                      HAVE_JD | HAVE_TIME);
07410     }
07411     add_frac();
07412     return ret;
07413 }
07414 
07415 /*
07416  * call-seq:
07417  *    DateTime.civil([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]])  ->  datetime
07418  *    DateTime.new([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]])    ->  datetime
07419  *
07420  * Creates a date-time object denoting the given calendar date.
07421  *
07422  *    DateTime.new(2001,2,3)    #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...>
07423  *    DateTime.new(2001,2,3,4,5,6,'+7')
07424  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07425  *    DateTime.new(2001,-11,-26,-20,-55,-54,'+7')
07426  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07427  */
07428 static VALUE
07429 datetime_s_civil(int argc, VALUE *argv, VALUE klass)
07430 {
07431     VALUE vy, vm, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
07432     int m, d, h, min, s, rof;
07433     double sg;
07434 
07435     rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg);
07436 
07437     y = INT2FIX(-4712);
07438     m = 1;
07439     d = 1;
07440 
07441     h = min = s = 0;
07442     fr2 = INT2FIX(0);
07443     rof = 0;
07444     sg = DEFAULT_SG;
07445 
07446     switch (argc) {
07447       case 8:
07448         val2sg(vsg, sg);
07449       case 7:
07450         val2off(vof, rof);
07451       case 6:
07452         num2int_with_frac(s, positive_inf);
07453       case 5:
07454         num2int_with_frac(min, 5);
07455       case 4:
07456         num2int_with_frac(h, 4);
07457       case 3:
07458         num2int_with_frac(d, 3);
07459       case 2:
07460         m = NUM2INT(vm);
07461       case 1:
07462         y = vy;
07463     }
07464 
07465     if (guess_style(y, sg) < 0) {
07466         VALUE nth;
07467         int ry, rm, rd, rh, rmin, rs;
07468 
07469         if (!valid_gregorian_p(y, m, d,
07470                                &nth, &ry,
07471                                &rm, &rd))
07472             rb_raise(rb_eArgError, "invalid date");
07473         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07474             rb_raise(rb_eArgError, "invalid date");
07475         canon24oc();
07476 
07477         ret = d_complex_new_internal(klass,
07478                                      nth, 0,
07479                                      0, INT2FIX(0),
07480                                      rof, sg,
07481                                      ry, rm, rd,
07482                                      rh, rmin, rs,
07483                                      HAVE_CIVIL | HAVE_TIME);
07484     }
07485     else {
07486         VALUE nth;
07487         int ry, rm, rd, rh, rmin, rs, rjd, rjd2, ns;
07488 
07489         if (!valid_civil_p(y, m, d, sg,
07490                            &nth, &ry,
07491                            &rm, &rd, &rjd,
07492                            &ns))
07493             rb_raise(rb_eArgError, "invalid date");
07494         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07495             rb_raise(rb_eArgError, "invalid date");
07496         canon24oc();
07497 
07498         rjd2 = jd_local_to_utc(rjd,
07499                                time_to_df(rh, rmin, rs),
07500                                rof);
07501 
07502         ret = d_complex_new_internal(klass,
07503                                      nth, rjd2,
07504                                      0, INT2FIX(0),
07505                                      rof, sg,
07506                                      ry, rm, rd,
07507                                      rh, rmin, rs,
07508                                      HAVE_JD | HAVE_CIVIL | HAVE_TIME);
07509     }
07510     add_frac();
07511     return ret;
07512 }
07513 
07514 /*
07515  * call-seq:
07516  *    DateTime.commercial([cwyear=-4712[, cweek=1[, cwday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]])  ->  datetime
07517  *
07518  * Creates a date-time object denoting the given week date.
07519  *
07520  *    DateTime.commercial(2001) #=> #<DateTime: 2001-01-01T00:00:00+00:00 ...>
07521  *    DateTime.commercial(2002) #=> #<DateTime: 2001-12-31T00:00:00+00:00 ...>
07522  *    DateTime.commercial(2001,5,6,4,5,6,'+7')
07523  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07524  */
07525 static VALUE
07526 datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
07527 {
07528     VALUE vy, vw, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
07529     int w, d, h, min, s, rof;
07530     double sg;
07531 
07532     rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg);
07533 
07534     y = INT2FIX(-4712);
07535     w = 1;
07536     d = 1;
07537 
07538     h = min = s = 0;
07539     fr2 = INT2FIX(0);
07540     rof = 0;
07541     sg = DEFAULT_SG;
07542 
07543     switch (argc) {
07544       case 8:
07545         val2sg(vsg, sg);
07546       case 7:
07547         val2off(vof, rof);
07548       case 6:
07549         num2int_with_frac(s, positive_inf);
07550       case 5:
07551         num2int_with_frac(min, 5);
07552       case 4:
07553         num2int_with_frac(h, 4);
07554       case 3:
07555         num2int_with_frac(d, 3);
07556       case 2:
07557         w = NUM2INT(vw);
07558       case 1:
07559         y = vy;
07560     }
07561 
07562     {
07563         VALUE nth;
07564         int ry, rw, rd, rh, rmin, rs, rjd, rjd2, ns;
07565 
07566         if (!valid_commercial_p(y, w, d, sg,
07567                                 &nth, &ry,
07568                                 &rw, &rd, &rjd,
07569                                 &ns))
07570             rb_raise(rb_eArgError, "invalid date");
07571         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07572             rb_raise(rb_eArgError, "invalid date");
07573         canon24oc();
07574 
07575         rjd2 = jd_local_to_utc(rjd,
07576                                time_to_df(rh, rmin, rs),
07577                                rof);
07578 
07579         ret = d_complex_new_internal(klass,
07580                                      nth, rjd2,
07581                                      0, INT2FIX(0),
07582                                      rof, sg,
07583                                      0, 0, 0,
07584                                      rh, rmin, rs,
07585                                      HAVE_JD | HAVE_TIME);
07586     }
07587     add_frac();
07588     return ret;
07589 }
07590 
07591 #ifndef NDEBUG
07592 static VALUE
07593 datetime_s_weeknum(int argc, VALUE *argv, VALUE klass)
07594 {
07595     VALUE vy, vw, vd, vf, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
07596     int w, d, f, h, min, s, rof;
07597     double sg;
07598 
07599     rb_scan_args(argc, argv, "09", &vy, &vw, &vd, &vf,
07600                  &vh, &vmin, &vs, &vof, &vsg);
07601 
07602     y = INT2FIX(-4712);
07603     w = 0;
07604     d = 1;
07605     f = 0;
07606 
07607     h = min = s = 0;
07608     fr2 = INT2FIX(0);
07609     rof = 0;
07610     sg = DEFAULT_SG;
07611 
07612     switch (argc) {
07613       case 9:
07614         val2sg(vsg, sg);
07615       case 8:
07616         val2off(vof, rof);
07617       case 7:
07618         num2int_with_frac(s, positive_inf);
07619       case 6:
07620         num2int_with_frac(min, 6);
07621       case 5:
07622         num2int_with_frac(h, 5);
07623       case 4:
07624         f = NUM2INT(vf);
07625       case 3:
07626         num2int_with_frac(d, 4);
07627       case 2:
07628         w = NUM2INT(vw);
07629       case 1:
07630         y = vy;
07631     }
07632 
07633     {
07634         VALUE nth;
07635         int ry, rw, rd, rh, rmin, rs, rjd, rjd2, ns;
07636 
07637         if (!valid_weeknum_p(y, w, d, f, sg,
07638                              &nth, &ry,
07639                              &rw, &rd, &rjd,
07640                              &ns))
07641             rb_raise(rb_eArgError, "invalid date");
07642         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07643             rb_raise(rb_eArgError, "invalid date");
07644         canon24oc();
07645 
07646         rjd2 = jd_local_to_utc(rjd,
07647                                time_to_df(rh, rmin, rs),
07648                                rof);
07649         ret = d_complex_new_internal(klass,
07650                                      nth, rjd2,
07651                                      0, INT2FIX(0),
07652                                      rof, sg,
07653                                      0, 0, 0,
07654                                      rh, rmin, rs,
07655                                      HAVE_JD | HAVE_TIME);
07656     }
07657     add_frac();
07658     return ret;
07659 }
07660 
07661 static VALUE
07662 datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass)
07663 {
07664     VALUE vy, vm, vn, vk, vh, vmin, vs, vof, vsg, y, fr, fr2, ret;
07665     int m, n, k, h, min, s, rof;
07666     double sg;
07667 
07668     rb_scan_args(argc, argv, "09", &vy, &vm, &vn, &vk,
07669                  &vh, &vmin, &vs, &vof, &vsg);
07670 
07671     y = INT2FIX(-4712);
07672     m = 1;
07673     n = 1;
07674     k = 1;
07675 
07676     h = min = s = 0;
07677     fr2 = INT2FIX(0);
07678     rof = 0;
07679     sg = DEFAULT_SG;
07680 
07681     switch (argc) {
07682       case 9:
07683         val2sg(vsg, sg);
07684       case 8:
07685         val2off(vof, rof);
07686       case 7:
07687         num2int_with_frac(s, positive_inf);
07688       case 6:
07689         num2int_with_frac(min, 6);
07690       case 5:
07691         num2int_with_frac(h, 5);
07692       case 4:
07693         num2int_with_frac(k, 4);
07694       case 3:
07695         n = NUM2INT(vn);
07696       case 2:
07697         m = NUM2INT(vm);
07698       case 1:
07699         y = vy;
07700     }
07701 
07702     {
07703         VALUE nth;
07704         int ry, rm, rn, rk, rh, rmin, rs, rjd, rjd2, ns;
07705 
07706         if (!valid_nth_kday_p(y, m, n, k, sg,
07707                               &nth, &ry,
07708                               &rm, &rn, &rk, &rjd,
07709                               &ns))
07710             rb_raise(rb_eArgError, "invalid date");
07711         if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs))
07712             rb_raise(rb_eArgError, "invalid date");
07713         canon24oc();
07714 
07715         rjd2 = jd_local_to_utc(rjd,
07716                                time_to_df(rh, rmin, rs),
07717                                rof);
07718         ret = d_complex_new_internal(klass,
07719                                      nth, rjd2,
07720                                      0, INT2FIX(0),
07721                                      rof, sg,
07722                                      0, 0, 0,
07723                                      rh, rmin, rs,
07724                                      HAVE_JD | HAVE_TIME);
07725     }
07726     add_frac();
07727     return ret;
07728 }
07729 #endif
07730 
07731 /*
07732  * call-seq:
07733  *    DateTime.now([start=Date::ITALY])  ->  datetime
07734  *
07735  * Creates a date-time object denoting the present time.
07736  *
07737  *    DateTime.now              #=> #<DateTime: 2011-06-11T21:20:44+09:00 ...>
07738  */
07739 static VALUE
07740 datetime_s_now(int argc, VALUE *argv, VALUE klass)
07741 {
07742     VALUE vsg, nth, ret;
07743     double sg;
07744 #ifdef HAVE_CLOCK_GETTIME
07745     struct timespec ts;
07746 #else
07747     struct timeval tv;
07748 #endif
07749     time_t sec;
07750     struct tm tm;
07751     long sf, of;
07752     int y, ry, m, d, h, min, s;
07753 
07754     rb_scan_args(argc, argv, "01", &vsg);
07755 
07756     if (argc < 1)
07757         sg = DEFAULT_SG;
07758     else
07759         sg = NUM2DBL(vsg);
07760 
07761 #ifdef HAVE_CLOCK_GETTIME
07762     if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
07763         rb_sys_fail("clock_gettime");
07764     sec = ts.tv_sec;
07765 #else
07766     if (gettimeofday(&tv, NULL) == -1)
07767         rb_sys_fail("gettimeofday");
07768     sec = tv.tv_sec;
07769 #endif
07770     tzset();
07771     if (!localtime_r(&sec, &tm))
07772         rb_sys_fail("localtime");
07773 
07774     y = tm.tm_year + 1900;
07775     m = tm.tm_mon + 1;
07776     d = tm.tm_mday;
07777     h = tm.tm_hour;
07778     min = tm.tm_min;
07779     s = tm.tm_sec;
07780     if (s == 60)
07781         s = 59;
07782 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
07783     of = tm.tm_gmtoff;
07784 #elif defined(HAVE_VAR_TIMEZONE)
07785 #ifdef HAVE_VAR_ALTZONE
07786     of = (long)-((tm.tm_isdst > 0) ? altzone : timezone);
07787 #else
07788     of = (long)-timezone;
07789     if (tm.tm_isdst) {
07790         time_t sec2;
07791 
07792         tm.tm_isdst = 0;
07793         sec2 = mktime(&tm);
07794         of += (long)difftime(sec2, sec);
07795     }
07796 #endif
07797 #elif defined(HAVE_TIMEGM)
07798     {
07799         time_t sec2;
07800 
07801         sec2 = timegm(&tm);
07802         of = (long)difftime(sec2, sec);
07803     }
07804 #else
07805     {
07806         struct tm tm2;
07807         time_t sec2;
07808 
07809         if (!gmtime_r(&sec, &tm2))
07810             rb_sys_fail("gmtime");
07811         tm2.tm_isdst = tm.tm_isdst;
07812         sec2 = mktime(&tm2);
07813         of = (long)difftime(sec, sec2);
07814     }
07815 #endif
07816 #ifdef HAVE_CLOCK_GETTIME
07817     sf = ts.tv_nsec;
07818 #else
07819     sf = tv.tv_usec * 1000;
07820 #endif
07821 
07822     if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS) {
07823         of = 0;
07824         rb_warning("invalid offset is ignored");
07825     }
07826 
07827     decode_year(INT2FIX(y), -1, &nth, &ry);
07828 
07829     ret = d_complex_new_internal(klass,
07830                                  nth, 0,
07831                                  0, LONG2NUM(sf),
07832                                  (int)of, GREGORIAN,
07833                                  ry, m, d,
07834                                  h, min, s,
07835                                  HAVE_CIVIL | HAVE_TIME);
07836     {
07837         get_d1(ret);
07838         set_sg(dat, sg);
07839     }
07840     return ret;
07841 }
07842 
07843 static VALUE
07844 dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg)
07845 {
07846     VALUE jd, sf, t;
07847     int df, of;
07848 
07849     if (!c_valid_start_p(NUM2DBL(sg))) {
07850         sg = INT2FIX(DEFAULT_SG);
07851         rb_warning("invalid start is ignored");
07852     }
07853 
07854     if (NIL_P(hash))
07855         rb_raise(rb_eArgError, "invalid date");
07856 
07857     if (NIL_P(ref_hash("jd")) &&
07858         NIL_P(ref_hash("yday")) &&
07859         !NIL_P(ref_hash("year")) &&
07860         !NIL_P(ref_hash("mon")) &&
07861         !NIL_P(ref_hash("mday"))) {
07862         jd = rt__valid_civil_p(ref_hash("year"),
07863                                ref_hash("mon"),
07864                                ref_hash("mday"), sg);
07865 
07866         if (NIL_P(ref_hash("hour")))
07867             set_hash("hour", INT2FIX(0));
07868         if (NIL_P(ref_hash("min")))
07869             set_hash("min", INT2FIX(0));
07870         if (NIL_P(ref_hash("sec")))
07871             set_hash("sec", INT2FIX(0));
07872         else if (f_eqeq_p(ref_hash("sec"), INT2FIX(60)))
07873             set_hash("sec", INT2FIX(59));
07874     }
07875     else {
07876         hash = rt_rewrite_frags(hash);
07877         hash = rt_complete_frags(klass, hash);
07878         jd = rt__valid_date_frags_p(hash, sg);
07879     }
07880 
07881     if (NIL_P(jd))
07882         rb_raise(rb_eArgError, "invalid date");
07883 
07884     {
07885         int rh, rmin, rs;
07886 
07887         if (!c_valid_time_p(NUM2INT(ref_hash("hour")),
07888                             NUM2INT(ref_hash("min")),
07889                             NUM2INT(ref_hash("sec")),
07890                             &rh, &rmin, &rs))
07891             rb_raise(rb_eArgError, "invalid date");
07892 
07893         df = time_to_df(rh, rmin, rs);
07894     }
07895 
07896     t = ref_hash("sec_fraction");
07897     if (NIL_P(t))
07898         sf = INT2FIX(0);
07899     else
07900         sf = sec_to_ns(t);
07901 
07902     t = ref_hash("offset");
07903     if (NIL_P(t))
07904         of = 0;
07905     else {
07906         of = NUM2INT(t);
07907         if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS) {
07908             of = 0;
07909             rb_warning("invalid offset is ignored");
07910         }
07911     }
07912     {
07913         VALUE nth;
07914         int rjd, rjd2;
07915 
07916         decode_jd(jd, &nth, &rjd);
07917         rjd2 = jd_local_to_utc(rjd, df, of);
07918         df = df_local_to_utc(df, of);
07919 
07920         return d_complex_new_internal(klass,
07921                                       nth, rjd2,
07922                                       df, sf,
07923                                       of, NUM2DBL(sg),
07924                                       0, 0, 0,
07925                                       0, 0, 0,
07926                                       HAVE_JD | HAVE_DF);
07927     }
07928 }
07929 
07930 /*
07931  * call-seq:
07932  *    DateTime._strptime(string[, format='%FT%T%z'])  ->  hash
07933  *
07934  * Parses the given representation of date and time with the given
07935  * template, and returns a hash of parsed elements.  _strptime does
07936  * not support specification of flags and width unlike strftime.
07937  *
07938  *  See also strptime(3) and strftime.
07939  */
07940 static VALUE
07941 datetime_s__strptime(int argc, VALUE *argv, VALUE klass)
07942 {
07943     return date_s__strptime_internal(argc, argv, klass, "%FT%T%z");
07944 }
07945 
07946 /*
07947  * call-seq:
07948  *    DateTime.strptime([string='-4712-01-01T00:00:00+00:00'[, format='%FT%T%z'[ ,start=ITALY]]])  ->  datetime
07949  *
07950  * Parses the given representation of date and time with the given
07951  * template, and creates a date object.  strptime does not support
07952  * specification of flags and width unlike strftime.
07953  *
07954  *    DateTime.strptime('2001-02-03T04:05:06+07:00', '%Y-%m-%dT%H:%M:%S%z')
07955  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07956  *    DateTime.strptime('03-02-2001 04:05:06 PM', '%d-%m-%Y %I:%M:%S %p')
07957  *                              #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
07958  *    DateTime.strptime('2001-W05-6T04:05:06+07:00', '%G-W%V-%uT%H:%M:%S%z')
07959  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07960  *    DateTime.strptime('2001 04 6 04 05 06 +7', '%Y %U %w %H %M %S %z')
07961  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07962  *    DateTime.strptime('2001 05 6 04 05 06 +7', '%Y %W %u %H %M %S %z')
07963  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
07964  *    DateTime.strptime('-1', '%s')
07965  *                              #=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
07966  *    DateTime.strptime('-1000', '%Q')
07967  *                              #=> #<DateTime: 1969-12-31T23:59:59+00:00 ...>
07968  *    DateTime.strptime('sat3feb014pm+7', '%a%d%b%y%H%p%z')
07969  *                              #=> #<DateTime: 2001-02-03T16:00:00+07:00 ...>
07970  *
07971  * See also strptime(3) and strftime.
07972  */
07973 static VALUE
07974 datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
07975 {
07976     VALUE str, fmt, sg;
07977 
07978     rb_scan_args(argc, argv, "03", &str, &fmt, &sg);
07979 
07980     switch (argc) {
07981       case 0:
07982         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
07983       case 1:
07984         fmt = rb_str_new2("%FT%T%z");
07985       case 2:
07986         sg = INT2FIX(DEFAULT_SG);
07987     }
07988 
07989     {
07990         VALUE argv2[2], hash;
07991 
07992         argv2[0] = str;
07993         argv2[1] = fmt;
07994         hash = date_s__strptime(2, argv2, klass);
07995         return dt_new_by_frags(klass, hash, sg);
07996     }
07997 }
07998 
07999 /*
08000  * call-seq:
08001  *    DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=ITALY]])  ->  datetime
08002  *
08003  * Parses the given representation of date and time, and creates a
08004  * date object.  This method does not function as a validator.
08005  *
08006  * If the optional second argument is true and the detected year is in
08007  * the range "00" to "99", makes it full.
08008  *
08009  *    DateTime.parse('2001-02-03T04:05:06+07:00')
08010  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08011  *    DateTime.parse('20010203T040506+0700')
08012  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08013  *    DateTime.parse('3rd Feb 2001 04:05:06 PM')
08014  *                              #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
08015  */
08016 static VALUE
08017 datetime_s_parse(int argc, VALUE *argv, VALUE klass)
08018 {
08019     VALUE str, comp, sg;
08020 
08021     rb_scan_args(argc, argv, "03", &str, &comp, &sg);
08022 
08023     switch (argc) {
08024       case 0:
08025         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
08026       case 1:
08027         comp = Qtrue;
08028       case 2:
08029         sg = INT2FIX(DEFAULT_SG);
08030     }
08031 
08032     {
08033         VALUE argv2[2], hash;
08034 
08035         argv2[0] = str;
08036         argv2[1] = comp;
08037         hash = date_s__parse(2, argv2, klass);
08038         return dt_new_by_frags(klass, hash, sg);
08039     }
08040 }
08041 
08042 /*
08043  * call-seq:
08044  *    DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=ITALY])  ->  datetime
08045  *
08046  * Creates a new Date object by parsing from a string according to
08047  * some typical ISO 8601 formats.
08048  *
08049  *    DateTime.iso8601('2001-02-03T04:05:06+07:00')
08050  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08051  *    DateTime.iso8601('20010203T040506+0700')
08052  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08053  *    DateTime.iso8601('2001-W05-6T04:05:06+07:00')
08054  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08055  */
08056 static VALUE
08057 datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
08058 {
08059     VALUE str, sg;
08060 
08061     rb_scan_args(argc, argv, "02", &str, &sg);
08062 
08063     switch (argc) {
08064       case 0:
08065         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
08066       case 1:
08067         sg = INT2FIX(DEFAULT_SG);
08068     }
08069 
08070     {
08071         VALUE hash = date_s__iso8601(klass, str);
08072         return dt_new_by_frags(klass, hash, sg);
08073     }
08074 }
08075 
08076 /*
08077  * call-seq:
08078  *    DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY])  ->  datetime
08079  *
08080  * Creates a new Date object by parsing from a string according to
08081  * some typical RFC 3339 formats.
08082  *
08083  *    DateTime.rfc3339('2001-02-03T04:05:06+07:00')
08084  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08085  */
08086 static VALUE
08087 datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
08088 {
08089     VALUE str, sg;
08090 
08091     rb_scan_args(argc, argv, "02", &str, &sg);
08092 
08093     switch (argc) {
08094       case 0:
08095         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
08096       case 1:
08097         sg = INT2FIX(DEFAULT_SG);
08098     }
08099 
08100     {
08101         VALUE hash = date_s__rfc3339(klass, str);
08102         return dt_new_by_frags(klass, hash, sg);
08103     }
08104 }
08105 
08106 /*
08107  * call-seq:
08108  *    DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=ITALY])  ->  datetime
08109  *
08110  * Creates a new Date object by parsing from a string according to
08111  * some typical XML Schema formats.
08112  *
08113  *    DateTime.xmlschema('2001-02-03T04:05:06+07:00')
08114  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08115  */
08116 static VALUE
08117 datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
08118 {
08119     VALUE str, sg;
08120 
08121     rb_scan_args(argc, argv, "02", &str, &sg);
08122 
08123     switch (argc) {
08124       case 0:
08125         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
08126       case 1:
08127         sg = INT2FIX(DEFAULT_SG);
08128     }
08129 
08130     {
08131         VALUE hash = date_s__xmlschema(klass, str);
08132         return dt_new_by_frags(klass, hash, sg);
08133     }
08134 }
08135 
08136 /*
08137  * call-seq:
08138  *    DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY])  ->  datetime
08139  *    DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY])   ->  datetime
08140  *
08141  * Creates a new Date object by parsing from a string according to
08142  * some typical RFC 2822 formats.
08143  *
08144  *     DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700')
08145  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08146  */
08147 static VALUE
08148 datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
08149 {
08150     VALUE str, sg;
08151 
08152     rb_scan_args(argc, argv, "02", &str, &sg);
08153 
08154     switch (argc) {
08155       case 0:
08156         str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
08157       case 1:
08158         sg = INT2FIX(DEFAULT_SG);
08159     }
08160 
08161     {
08162         VALUE hash = date_s__rfc2822(klass, str);
08163         return dt_new_by_frags(klass, hash, sg);
08164     }
08165 }
08166 
08167 /*
08168  * call-seq:
08169  *    DateTime.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY])  ->  datetime
08170  *
08171  * Creates a new Date object by parsing from a string according to
08172  * some RFC 2616 format.
08173  *
08174  *    DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT')
08175  *                              #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
08176  */
08177 static VALUE
08178 datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
08179 {
08180     VALUE str, sg;
08181 
08182     rb_scan_args(argc, argv, "02", &str, &sg);
08183 
08184     switch (argc) {
08185       case 0:
08186         str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
08187       case 1:
08188         sg = INT2FIX(DEFAULT_SG);
08189     }
08190 
08191     {
08192         VALUE hash = date_s__httpdate(klass, str);
08193         return dt_new_by_frags(klass, hash, sg);
08194     }
08195 }
08196 
08197 /*
08198  * call-seq:
08199  *    DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=ITALY])  ->  datetime
08200  *
08201  * Creates a new Date object by parsing from a string according to
08202  * some typical JIS X 0301 formats.
08203  *
08204  *    DateTime.jisx0301('H13.02.03T04:05:06+07:00')
08205  *                              #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
08206  */
08207 static VALUE
08208 datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
08209 {
08210     VALUE str, sg;
08211 
08212     rb_scan_args(argc, argv, "02", &str, &sg);
08213 
08214     switch (argc) {
08215       case 0:
08216         str = rb_str_new2("-4712-01-01T00:00:00+00:00");
08217       case 1:
08218         sg = INT2FIX(DEFAULT_SG);
08219     }
08220 
08221     {
08222         VALUE hash = date_s__jisx0301(klass, str);
08223         return dt_new_by_frags(klass, hash, sg);
08224     }
08225 }
08226 
08227 /*
08228  * call-seq:
08229  *    dt.to_s  ->  string
08230  *
08231  * Returns a string in an ISO 8601 format (This method doesn't use the
08232  * expanded representations).
08233  *
08234  *     DateTime.new(2001,2,3,4,5,6,'-7').to_s
08235  *                              #=> "2001-02-03T04:05:06-07:00"
08236  */
08237 static VALUE
08238 dt_lite_to_s(VALUE self)
08239 {
08240     return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx);
08241 }
08242 
08243 /*
08244  * call-seq:
08245  *    dt.strftime([format='%FT%T%:z'])  ->  string
08246  *
08247  *  Formats date according to the directives in the given format
08248  *  string.
08249  *  The directives begins with a percent (%) character.
08250  *  Any text not listed as a directive will be passed through to the
08251  *  output string.
08252  *
08253  *  The directive consists of a percent (%) character,
08254  *  zero or more flags, optional minimum field width,
08255  *  optional modifier and a conversion specifier
08256  *  as follows.
08257  *
08258  *    %<flags><width><modifier><conversion>
08259  *
08260  *  Flags:
08261  *    -  don't pad a numerical output.
08262  *    _  use spaces for padding.
08263  *    0  use zeros for padding.
08264  *    ^  upcase the result string.
08265  *    #  change case.
08266  *    :  use colons for %z.
08267  *
08268  *  The minimum field width specifies the minimum width.
08269  *
08270  *  The modifier is "E" and "O".
08271  *  They are ignored.
08272  *
08273  *  Format directives:
08274  *
08275  *    Date (Year, Month, Day):
08276  *      %Y - Year with century (can be negative, 4 digits at least)
08277  *              -0001, 0000, 1995, 2009, 14292, etc.
08278  *      %C - year / 100 (round down.  20 in 2009)
08279  *      %y - year % 100 (00..99)
08280  *
08281  *      %m - Month of the year, zero-padded (01..12)
08282  *              %_m  blank-padded ( 1..12)
08283  *              %-m  no-padded (1..12)
08284  *      %B - The full month name (``January'')
08285  *              %^B  uppercased (``JANUARY'')
08286  *      %b - The abbreviated month name (``Jan'')
08287  *              %^b  uppercased (``JAN'')
08288  *      %h - Equivalent to %b
08289  *
08290  *      %d - Day of the month, zero-padded (01..31)
08291  *              %-d  no-padded (1..31)
08292  *      %e - Day of the month, blank-padded ( 1..31)
08293  *
08294  *      %j - Day of the year (001..366)
08295  *
08296  *    Time (Hour, Minute, Second, Subsecond):
08297  *      %H - Hour of the day, 24-hour clock, zero-padded (00..23)
08298  *      %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
08299  *      %I - Hour of the day, 12-hour clock, zero-padded (01..12)
08300  *      %l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
08301  *      %P - Meridian indicator, lowercase (``am'' or ``pm'')
08302  *      %p - Meridian indicator, uppercase (``AM'' or ``PM'')
08303  *
08304  *      %M - Minute of the hour (00..59)
08305  *
08306  *      %S - Second of the minute (00..59)
08307  *
08308  *      %L - Millisecond of the second (000..999)
08309  *      %N - Fractional seconds digits, default is 9 digits (nanosecond)
08310  *              %3N  millisecond (3 digits)   %15N femtosecond (15 digits)
08311  *              %6N  microsecond (6 digits)   %18N attosecond  (18 digits)
08312  *              %9N  nanosecond  (9 digits)   %21N zeptosecond (21 digits)
08313  *              %12N picosecond (12 digits)   %24N yoctosecond (24 digits)
08314  *
08315  *    Time zone:
08316  *      %z - Time zone as hour and minute offset from UTC (e.g. +0900)
08317  *              %:z - hour and minute offset from UTC with a colon (e.g. +09:00)
08318  *              %::z - hour, minute and second offset from UTC (e.g. +09:00:00)
08319  *              %:::z - hour, minute and second offset from UTC
08320  *                                                (e.g. +09, +09:30, +09:30:30)
08321  *      %Z - Time zone abbreviation name or something similar information.
08322  *
08323  *    Weekday:
08324  *      %A - The full weekday name (``Sunday'')
08325  *              %^A  uppercased (``SUNDAY'')
08326  *      %a - The abbreviated name (``Sun'')
08327  *              %^a  uppercased (``SUN'')
08328  *      %u - Day of the week (Monday is 1, 1..7)
08329  *      %w - Day of the week (Sunday is 0, 0..6)
08330  *
08331  *    ISO 8601 week-based year and week number:
08332  *    The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
08333  *    The days in the year before the first week are in the last week of
08334  *    the previous year.
08335  *      %G - The week-based year
08336  *      %g - The last 2 digits of the week-based year (00..99)
08337  *      %V - Week number of the week-based year (01..53)
08338  *
08339  *    Week number:
08340  *    The week 1 of YYYY starts with a Sunday or Monday (according to %U
08341  *    or %W).  The days in the year before the first week are in week 0.
08342  *      %U - Week number of the year.  The week starts with Sunday.  (00..53)
08343  *      %W - Week number of the year.  The week starts with Monday.  (00..53)
08344  *
08345  *    Seconds since the Unix Epoch:
08346  *      %s - Number of seconds since 1970-01-01 00:00:00 UTC.
08347  *      %Q - Number of milliseconds since 1970-01-01 00:00:00 UTC.
08348  *
08349  *    Literal string:
08350  *      %n - Newline character (\n)
08351  *      %t - Tab character (\t)
08352  *      %% - Literal ``%'' character
08353  *
08354  *    Combination:
08355  *      %c - date and time (%a %b %e %T %Y)
08356  *      %D - Date (%m/%d/%y)
08357  *      %F - The ISO 8601 date format (%Y-%m-%d)
08358  *      %v - VMS date (%e-%b-%Y)
08359  *      %x - Same as %D
08360  *      %X - Same as %T
08361  *      %r - 12-hour time (%I:%M:%S %p)
08362  *      %R - 24-hour time (%H:%M)
08363  *      %T - 24-hour time (%H:%M:%S)
08364  *      %+ - date(1) (%a %b %e %H:%M:%S %Z %Y)
08365  *
08366  *  This method is similar to strftime() function defined in ISO C and POSIX.
08367  *  Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z)
08368  *  are locale dependent in the function.
08369  *  However this method is locale independent.
08370  *  So, the result may differ even if a same format string is used in other
08371  *  systems such as C.
08372  *  It is good practice to avoid %x and %X because there are corresponding
08373  *  locale independent representations, %D and %T.
08374  *
08375  *  Examples:
08376  *
08377  *    d = DateTime.new(2007,11,19,8,37,48,"-06:00")
08378  *                              #=> #<DateTime: 2007-11-19T08:37:48-0600 ...>
08379  *    d.strftime("Printed on %m/%d/%Y")   #=> "Printed on 11/19/2007"
08380  *    d.strftime("at %I:%M%p")            #=> "at 08:37AM"
08381  *
08382  *  Various ISO 8601 formats:
08383  *    %Y%m%d           => 20071119                  Calendar date (basic)
08384  *    %F               => 2007-11-19                Calendar date (extended)
08385  *    %Y-%m            => 2007-11                   Calendar date, reduced accuracy, specific month
08386  *    %Y               => 2007                      Calendar date, reduced accuracy, specific year
08387  *    %C               => 20                        Calendar date, reduced accuracy, specific century
08388  *    %Y%j             => 2007323                   Ordinal date (basic)
08389  *    %Y-%j            => 2007-323                  Ordinal date (extended)
08390  *    %GW%V%u          => 2007W471                  Week date (basic)
08391  *    %G-W%V-%u        => 2007-W47-1                Week date (extended)
08392  *    %GW%V            => 2007W47                   Week date, reduced accuracy, specific week (basic)
08393  *    %G-W%V           => 2007-W47                  Week date, reduced accuracy, specific week (extended)
08394  *    %H%M%S           => 083748                    Local time (basic)
08395  *    %T               => 08:37:48                  Local time (extended)
08396  *    %H%M             => 0837                      Local time, reduced accuracy, specific minute (basic)
08397  *    %H:%M            => 08:37                     Local time, reduced accuracy, specific minute (extended)
08398  *    %H               => 08                        Local time, reduced accuracy, specific hour
08399  *    %H%M%S,%L        => 083748,000                Local time with decimal fraction, comma as decimal sign (basic)
08400  *    %T,%L            => 08:37:48,000              Local time with decimal fraction, comma as decimal sign (extended)
08401  *    %H%M%S.%L        => 083748.000                Local time with decimal fraction, full stop as decimal sign (basic)
08402  *    %T.%L            => 08:37:48.000              Local time with decimal fraction, full stop as decimal sign (extended)
08403  *    %H%M%S%z         => 083748-0600               Local time and the difference from UTC (basic)
08404  *    %T%:z            => 08:37:48-06:00            Local time and the difference from UTC (extended)
08405  *    %Y%m%dT%H%M%S%z  => 20071119T083748-0600      Date and time of day for calendar date (basic)
08406  *    %FT%T%:z         => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended)
08407  *    %Y%jT%H%M%S%z    => 2007323T083748-0600       Date and time of day for ordinal date (basic)
08408  *    %Y-%jT%T%:z      => 2007-323T08:37:48-06:00   Date and time of day for ordinal date (extended)
08409  *    %GW%V%uT%H%M%S%z => 2007W471T083748-0600      Date and time of day for week date (basic)
08410  *    %G-W%V-%uT%T%:z  => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended)
08411  *    %Y%m%dT%H%M      => 20071119T0837             Calendar date and local time (basic)
08412  *    %FT%R            => 2007-11-19T08:37          Calendar date and local time (extended)
08413  *    %Y%jT%H%MZ       => 2007323T0837Z             Ordinal date and UTC of day (basic)
08414  *    %Y-%jT%RZ        => 2007-323T08:37Z           Ordinal date and UTC of day (extended)
08415  *    %GW%V%uT%H%M%z   => 2007W471T0837-0600        Week date and local time and difference from UTC (basic)
08416  *    %G-W%V-%uT%R%:z  => 2007-W47-1T08:37-06:00    Week date and local time and difference from UTC (extended)
08417  *
08418  * See also strftime(3) and strptime.
08419  */
08420 static VALUE
08421 dt_lite_strftime(int argc, VALUE *argv, VALUE self)
08422 {
08423     return date_strftime_internal(argc, argv, self,
08424                                   "%Y-%m-%dT%H:%M:%S%:z", set_tmx);
08425 }
08426 
08427 static VALUE
08428 iso8601_timediv(VALUE self, VALUE n)
08429 {
08430     VALUE fmt;
08431 
08432     n = to_integer(n);
08433     fmt = rb_usascii_str_new2("T%H:%M:%S");
08434     if (f_gt_p(n, INT2FIX(0))) {
08435         VALUE argv[3];
08436 
08437         get_d1(self);
08438 
08439         argv[0] = rb_usascii_str_new2(".%0*d");
08440         argv[1] = n;
08441         argv[2] = f_round(f_quo(m_sf_in_sec(dat),
08442                                 f_quo(INT2FIX(1),
08443                                       f_expt(INT2FIX(10), n))));
08444         rb_str_append(fmt, rb_f_sprintf(3, argv));
08445     }
08446     rb_str_append(fmt, rb_usascii_str_new2("%:z"));
08447     return strftimev(RSTRING_PTR(fmt), self, set_tmx);
08448 }
08449 
08450 /*
08451  * call-seq:
08452  *    dt.iso8601([n=0])    ->  string
08453  *    dt.xmlschema([n=0])  ->  string
08454  *
08455  * This method is equivalent to strftime('%FT%T').  The optional
08456  * argument n is length of fractional seconds.
08457  *
08458  *    DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9)
08459  *                              #=> "2001-02-03T04:05:06.123456789+07:00"
08460  */
08461 static VALUE
08462 dt_lite_iso8601(int argc, VALUE *argv, VALUE self)
08463 {
08464     VALUE n;
08465 
08466     rb_scan_args(argc, argv, "01", &n);
08467 
08468     if (argc < 1)
08469         n = INT2FIX(0);
08470 
08471     return f_add(strftimev("%Y-%m-%d", self, set_tmx),
08472                  iso8601_timediv(self, n));
08473 }
08474 
08475 /*
08476  * call-seq:
08477  *    dt.rfc3339([n=0])  ->  string
08478  *
08479  * This method is equivalent to strftime('%FT%T').  The optional
08480  * argument n is length of fractional seconds.
08481  *
08482  *    DateTime.parse('2001-02-03T04:05:06.123456789+07:00').rfc3339(9)
08483  *                              #=> "2001-02-03T04:05:06.123456789+07:00"
08484  */
08485 static VALUE
08486 dt_lite_rfc3339(int argc, VALUE *argv, VALUE self)
08487 {
08488     return dt_lite_iso8601(argc, argv, self);
08489 }
08490 
08491 /*
08492  * call-seq:
08493  *    dt.jisx0301([n=0])  ->  string
08494  *
08495  * Returns a string in a JIS X 0301 format.  The optional argument n
08496  * is length of fractional seconds.
08497  *
08498  *    DateTime.parse('2001-02-03T04:05:06.123456789+07:00').jisx0301(9)
08499  *                              #=> "H13.02.03T04:05:06.123456789+07:00"
08500  */
08501 static VALUE
08502 dt_lite_jisx0301(int argc, VALUE *argv, VALUE self)
08503 {
08504     VALUE n, s;
08505 
08506     rb_scan_args(argc, argv, "01", &n);
08507 
08508     if (argc < 1)
08509         n = INT2FIX(0);
08510 
08511     {
08512         get_d1(self);
08513         s = jisx0301_date(m_real_local_jd(dat),
08514                           m_real_year(dat));
08515         return rb_str_append(strftimev(RSTRING_PTR(s), self, set_tmx),
08516                              iso8601_timediv(self, n));
08517     }
08518 }
08519 
08520 /* conversions */
08521 
08522 #define f_getlocal(x) rb_funcall(x, rb_intern("getlocal"), 0)
08523 #define f_subsec(x) rb_funcall(x, rb_intern("subsec"), 0)
08524 #define f_utc_offset(x) rb_funcall(x, rb_intern("utc_offset"), 0)
08525 #define f_local3(x,y,m,d) rb_funcall(x, rb_intern("local"), 3, y, m, d)
08526 #define f_utc6(x,y,m,d,h,min,s) rb_funcall(x, rb_intern("utc"), 6,\
08527                                            y, m, d, h, min, s)
08528 
08529 /*
08530  * call-seq:
08531  *    t.to_time  ->  time
08532  *
08533  * Returns a copy of self as local mode.
08534  */
08535 static VALUE
08536 time_to_time(VALUE self)
08537 {
08538     return f_getlocal(self);
08539 }
08540 
08541 /*
08542  * call-seq:
08543  *    t.to_date  ->  date
08544  *
08545  * Returns a Date object which denotes self.
08546  */
08547 static VALUE
08548 time_to_date(VALUE self)
08549 {
08550     VALUE y, nth, ret;
08551     int ry, m, d;
08552 
08553     y = f_year(self);
08554     m = FIX2INT(f_mon(self));
08555     d = FIX2INT(f_mday(self));
08556 
08557     decode_year(y, -1, &nth, &ry);
08558 
08559     ret = d_simple_new_internal(cDate,
08560                                 nth, 0,
08561                                 GREGORIAN,
08562                                 ry, m, d,
08563                                 HAVE_CIVIL);
08564     {
08565         get_d1(ret);
08566         set_sg(dat, DEFAULT_SG);
08567     }
08568     return ret;
08569 }
08570 
08571 /*
08572  * call-seq:
08573  *    t.to_datetime  ->  datetime
08574  *
08575  * Returns a DateTime object which denotes self.
08576  */
08577 static VALUE
08578 time_to_datetime(VALUE self)
08579 {
08580     VALUE y, sf, nth, ret;
08581     int ry, m, d, h, min, s, of;
08582 
08583     y = f_year(self);
08584     m = FIX2INT(f_mon(self));
08585     d = FIX2INT(f_mday(self));
08586 
08587     h = FIX2INT(f_hour(self));
08588     min = FIX2INT(f_min(self));
08589     s = FIX2INT(f_sec(self));
08590     if (s == 60)
08591         s = 59;
08592 
08593     sf = sec_to_ns(f_subsec(self));
08594     of = FIX2INT(f_utc_offset(self));
08595 
08596     decode_year(y, -1, &nth, &ry);
08597 
08598     ret = d_complex_new_internal(cDateTime,
08599                                  nth, 0,
08600                                  0, sf,
08601                                  of, DEFAULT_SG,
08602                                  ry, m, d,
08603                                  h, min, s,
08604                                  HAVE_CIVIL | HAVE_TIME);
08605     {
08606         get_d1(ret);
08607         set_sg(dat, DEFAULT_SG);
08608     }
08609     return ret;
08610 }
08611 
08612 /*
08613  * call-seq:
08614  *    d.to_time  ->  time
08615  *
08616  * Returns a Time object which denotes self.
08617  */
08618 static VALUE
08619 date_to_time(VALUE self)
08620 {
08621     get_d1(self);
08622 
08623     return f_local3(rb_cTime,
08624                     m_real_year(dat),
08625                     INT2FIX(m_mon(dat)),
08626                     INT2FIX(m_mday(dat)));
08627 }
08628 
08629 /*
08630  * call-seq:
08631  *    d.to_date  ->  self
08632  *
08633  * Returns self;
08634  */
08635 static VALUE
08636 date_to_date(VALUE self)
08637 {
08638     return self;
08639 }
08640 
08641 /*
08642  * call-seq:
08643  *    d.to_datetime  -> datetime
08644  *
08645  * Returns a DateTime object which denotes self.
08646  */
08647 static VALUE
08648 date_to_datetime(VALUE self)
08649 {
08650     get_d1a(self);
08651 
08652     if (simple_dat_p(adat)) {
08653         VALUE new = d_lite_s_alloc_simple(cDateTime);
08654         {
08655             get_d1b(new);
08656             bdat->s = adat->s;
08657             return new;
08658         }
08659     }
08660     else {
08661         VALUE new = d_lite_s_alloc_complex(cDateTime);
08662         {
08663             get_d1b(new);
08664             bdat->c = adat->c;
08665             bdat->c.df = 0;
08666             bdat->c.sf = INT2FIX(0);
08667 #ifndef USE_PACK
08668             bdat->c.hour = 0;
08669             bdat->c.min = 0;
08670             bdat->c.sec = 0;
08671 #else
08672             bdat->c.pc = PACK5(EX_MON(adat->c.pc), EX_MDAY(adat->c.pc),
08673                                0, 0, 0);
08674             bdat->c.flags |= HAVE_DF | HAVE_TIME;
08675 #endif
08676             return new;
08677         }
08678     }
08679 }
08680 
08681 /*
08682  * call-seq:
08683  *    dt.to_time  ->  time
08684  *
08685  * Returns a Time object which denotes self.
08686  */
08687 static VALUE
08688 datetime_to_time(VALUE self)
08689 {
08690     volatile VALUE dup = dup_obj_with_new_offset(self, 0);
08691     {
08692         VALUE t;
08693 
08694         get_d1(dup);
08695 
08696         t = f_utc6(rb_cTime,
08697                    m_real_year(dat),
08698                    INT2FIX(m_mon(dat)),
08699                    INT2FIX(m_mday(dat)),
08700                    INT2FIX(m_hour(dat)),
08701                    INT2FIX(m_min(dat)),
08702                    f_add(INT2FIX(m_sec(dat)),
08703                          m_sf_in_sec(dat)));
08704         return f_getlocal(t);
08705     }
08706 }
08707 
08708 /*
08709  * call-seq:
08710  *    dt.to_date  ->  date
08711  *
08712  * Returns a Date object which denotes self.
08713  */
08714 static VALUE
08715 datetime_to_date(VALUE self)
08716 {
08717     get_d1a(self);
08718 
08719     if (simple_dat_p(adat)) {
08720         VALUE new = d_lite_s_alloc_simple(cDate);
08721         {
08722             get_d1b(new);
08723             bdat->s = adat->s;
08724             bdat->s.jd = m_local_jd(adat);
08725             return new;
08726         }
08727     }
08728     else {
08729         VALUE new = d_lite_s_alloc_simple(cDate);
08730         {
08731             get_d1b(new);
08732             copy_complex_to_simple(&bdat->s, &adat->c)
08733             bdat->s.jd = m_local_jd(adat);
08734             bdat->s.flags &= ~(HAVE_DF | HAVE_TIME | COMPLEX_DAT);
08735             return new;
08736         }
08737     }
08738 }
08739 
08740 /*
08741  * call-seq:
08742  *    dt.to_datetime  ->  self
08743  *
08744  * Returns self.
08745  */
08746 static VALUE
08747 datetime_to_datetime(VALUE self)
08748 {
08749     return self;
08750 }
08751 
08752 #ifndef NDEBUG
08753 /* tests */
08754 
08755 #define MIN_YEAR -4713
08756 #define MAX_YEAR 1000000
08757 #define MIN_JD -327
08758 #define MAX_JD 366963925
08759 
08760 static int
08761 test_civil(int from, int to, double sg)
08762 {
08763     int j;
08764 
08765     fprintf(stderr, "test_civil: %d...%d (%d) - %.0f\n",
08766             from, to, to - from, sg);
08767     for (j = from; j <= to; j++) {
08768         int y, m, d, rj, ns;
08769 
08770         c_jd_to_civil(j, sg, &y, &m, &d);
08771         c_civil_to_jd(y, m, d, sg, &rj, &ns);
08772         if (j != rj) {
08773             fprintf(stderr, "%d != %d\n", j, rj);
08774             return 0;
08775         }
08776     }
08777     return 1;
08778 }
08779 
08780 static VALUE
08781 date_s_test_civil(VALUE klass)
08782 {
08783     if (!test_civil(MIN_JD, MIN_JD + 366, GREGORIAN))
08784         return Qfalse;
08785     if (!test_civil(2305814, 2598007, GREGORIAN))
08786         return Qfalse;
08787     if (!test_civil(MAX_JD - 366, MAX_JD, GREGORIAN))
08788         return Qfalse;
08789 
08790     if (!test_civil(MIN_JD, MIN_JD + 366, ITALY))
08791         return Qfalse;
08792     if (!test_civil(2305814, 2598007, ITALY))
08793         return Qfalse;
08794     if (!test_civil(MAX_JD - 366, MAX_JD, ITALY))
08795         return Qfalse;
08796 
08797     return Qtrue;
08798 }
08799 
08800 static int
08801 test_ordinal(int from, int to, double sg)
08802 {
08803     int j;
08804 
08805     fprintf(stderr, "test_ordinal: %d...%d (%d) - %.0f\n",
08806             from, to, to - from, sg);
08807     for (j = from; j <= to; j++) {
08808         int y, d, rj, ns;
08809 
08810         c_jd_to_ordinal(j, sg, &y, &d);
08811         c_ordinal_to_jd(y, d, sg, &rj, &ns);
08812         if (j != rj) {
08813             fprintf(stderr, "%d != %d\n", j, rj);
08814             return 0;
08815         }
08816     }
08817     return 1;
08818 }
08819 
08820 static VALUE
08821 date_s_test_ordinal(VALUE klass)
08822 {
08823     if (!test_ordinal(MIN_JD, MIN_JD + 366, GREGORIAN))
08824         return Qfalse;
08825     if (!test_ordinal(2305814, 2598007, GREGORIAN))
08826         return Qfalse;
08827     if (!test_ordinal(MAX_JD - 366, MAX_JD, GREGORIAN))
08828         return Qfalse;
08829 
08830     if (!test_ordinal(MIN_JD, MIN_JD + 366, ITALY))
08831         return Qfalse;
08832     if (!test_ordinal(2305814, 2598007, ITALY))
08833         return Qfalse;
08834     if (!test_ordinal(MAX_JD - 366, MAX_JD, ITALY))
08835         return Qfalse;
08836 
08837     return Qtrue;
08838 }
08839 
08840 static int
08841 test_commercial(int from, int to, double sg)
08842 {
08843     int j;
08844 
08845     fprintf(stderr, "test_commercial: %d...%d (%d) - %.0f\n",
08846             from, to, to - from, sg);
08847     for (j = from; j <= to; j++) {
08848         int y, w, d, rj, ns;
08849 
08850         c_jd_to_commercial(j, sg, &y, &w, &d);
08851         c_commercial_to_jd(y, w, d, sg, &rj, &ns);
08852         if (j != rj) {
08853             fprintf(stderr, "%d != %d\n", j, rj);
08854             return 0;
08855         }
08856     }
08857     return 1;
08858 }
08859 
08860 static VALUE
08861 date_s_test_commercial(VALUE klass)
08862 {
08863     if (!test_commercial(MIN_JD, MIN_JD + 366, GREGORIAN))
08864         return Qfalse;
08865     if (!test_commercial(2305814, 2598007, GREGORIAN))
08866         return Qfalse;
08867     if (!test_commercial(MAX_JD - 366, MAX_JD, GREGORIAN))
08868         return Qfalse;
08869 
08870     if (!test_commercial(MIN_JD, MIN_JD + 366, ITALY))
08871         return Qfalse;
08872     if (!test_commercial(2305814, 2598007, ITALY))
08873         return Qfalse;
08874     if (!test_commercial(MAX_JD - 366, MAX_JD, ITALY))
08875         return Qfalse;
08876 
08877     return Qtrue;
08878 }
08879 
08880 static int
08881 test_weeknum(int from, int to, int f, double sg)
08882 {
08883     int j;
08884 
08885     fprintf(stderr, "test_weeknum: %d...%d (%d) - %.0f\n",
08886             from, to, to - from, sg);
08887     for (j = from; j <= to; j++) {
08888         int y, w, d, rj, ns;
08889 
08890         c_jd_to_weeknum(j, f, sg, &y, &w, &d);
08891         c_weeknum_to_jd(y, w, d, f, sg, &rj, &ns);
08892         if (j != rj) {
08893             fprintf(stderr, "%d != %d\n", j, rj);
08894             return 0;
08895         }
08896     }
08897     return 1;
08898 }
08899 
08900 static VALUE
08901 date_s_test_weeknum(VALUE klass)
08902 {
08903     int f;
08904 
08905     for (f = 0; f <= 1; f++) {
08906         if (!test_weeknum(MIN_JD, MIN_JD + 366, f, GREGORIAN))
08907             return Qfalse;
08908         if (!test_weeknum(2305814, 2598007, f, GREGORIAN))
08909             return Qfalse;
08910         if (!test_weeknum(MAX_JD - 366, MAX_JD, f, GREGORIAN))
08911             return Qfalse;
08912 
08913         if (!test_weeknum(MIN_JD, MIN_JD + 366, f, ITALY))
08914             return Qfalse;
08915         if (!test_weeknum(2305814, 2598007, f, ITALY))
08916             return Qfalse;
08917         if (!test_weeknum(MAX_JD - 366, MAX_JD, f, ITALY))
08918             return Qfalse;
08919     }
08920 
08921     return Qtrue;
08922 }
08923 
08924 static int
08925 test_nth_kday(int from, int to, double sg)
08926 {
08927     int j;
08928 
08929     fprintf(stderr, "test_nth_kday: %d...%d (%d) - %.0f\n",
08930             from, to, to - from, sg);
08931     for (j = from; j <= to; j++) {
08932         int y, m, n, k, rj, ns;
08933 
08934         c_jd_to_nth_kday(j, sg, &y, &m, &n, &k);
08935         c_nth_kday_to_jd(y, m, n, k, sg, &rj, &ns);
08936         if (j != rj) {
08937             fprintf(stderr, "%d != %d\n", j, rj);
08938             return 0;
08939         }
08940     }
08941     return 1;
08942 }
08943 
08944 static VALUE
08945 date_s_test_nth_kday(VALUE klass)
08946 {
08947     if (!test_nth_kday(MIN_JD, MIN_JD + 366, GREGORIAN))
08948         return Qfalse;
08949     if (!test_nth_kday(2305814, 2598007, GREGORIAN))
08950         return Qfalse;
08951     if (!test_nth_kday(MAX_JD - 366, MAX_JD, GREGORIAN))
08952         return Qfalse;
08953 
08954     if (!test_nth_kday(MIN_JD, MIN_JD + 366, ITALY))
08955         return Qfalse;
08956     if (!test_nth_kday(2305814, 2598007, ITALY))
08957         return Qfalse;
08958     if (!test_nth_kday(MAX_JD - 366, MAX_JD, ITALY))
08959         return Qfalse;
08960 
08961     return Qtrue;
08962 }
08963 
08964 static int
08965 test_unit_v2v(VALUE i,
08966               VALUE (* conv1)(VALUE),
08967               VALUE (* conv2)(VALUE))
08968 {
08969     VALUE c, o;
08970     c = (*conv1)(i);
08971     o = (*conv2)(c);
08972     return f_eqeq_p(o, i);
08973 }
08974 
08975 static int
08976 test_unit_v2v_iter2(VALUE (* conv1)(VALUE),
08977                     VALUE (* conv2)(VALUE))
08978 {
08979     if (!test_unit_v2v(INT2FIX(0), conv1, conv2))
08980         return 0;
08981     if (!test_unit_v2v(INT2FIX(1), conv1, conv2))
08982         return 0;
08983     if (!test_unit_v2v(INT2FIX(2), conv1, conv2))
08984         return 0;
08985     if (!test_unit_v2v(INT2FIX(3), conv1, conv2))
08986         return 0;
08987     if (!test_unit_v2v(INT2FIX(11), conv1, conv2))
08988         return 0;
08989     if (!test_unit_v2v(INT2FIX(65535), conv1, conv2))
08990         return 0;
08991     if (!test_unit_v2v(INT2FIX(1073741823), conv1, conv2))
08992         return 0;
08993     if (!test_unit_v2v(INT2NUM(1073741824), conv1, conv2))
08994         return 0;
08995     if (!test_unit_v2v(rb_rational_new2(INT2FIX(0), INT2FIX(1)), conv1, conv2))
08996         return 0;
08997     if (!test_unit_v2v(rb_rational_new2(INT2FIX(1), INT2FIX(1)), conv1, conv2))
08998         return 0;
08999     if (!test_unit_v2v(rb_rational_new2(INT2FIX(1), INT2FIX(2)), conv1, conv2))
09000         return 0;
09001     if (!test_unit_v2v(rb_rational_new2(INT2FIX(2), INT2FIX(3)), conv1, conv2))
09002         return 0;
09003     return 1;
09004 }
09005 
09006 static int
09007 test_unit_v2v_iter(VALUE (* conv1)(VALUE),
09008                    VALUE (* conv2)(VALUE))
09009 {
09010     if (!test_unit_v2v_iter2(conv1, conv2))
09011         return 0;
09012     if (!test_unit_v2v_iter2(conv2, conv1))
09013         return 0;
09014     return 1;
09015 }
09016 
09017 static VALUE
09018 date_s_test_unit_conv(VALUE klass)
09019 {
09020     if (!test_unit_v2v_iter(sec_to_day, day_to_sec))
09021         return Qfalse;
09022     if (!test_unit_v2v_iter(ms_to_sec, sec_to_ms))
09023         return Qfalse;
09024     if (!test_unit_v2v_iter(ns_to_day, day_to_ns))
09025         return Qfalse;
09026     if (!test_unit_v2v_iter(ns_to_sec, sec_to_ns))
09027         return Qfalse;
09028     return Qtrue;
09029 }
09030 
09031 static VALUE
09032 date_s_test_all(VALUE klass)
09033 {
09034     if (date_s_test_civil(klass) == Qfalse)
09035         return Qfalse;
09036     if (date_s_test_ordinal(klass) == Qfalse)
09037         return Qfalse;
09038     if (date_s_test_commercial(klass) == Qfalse)
09039         return Qfalse;
09040     if (date_s_test_weeknum(klass) == Qfalse)
09041         return Qfalse;
09042     if (date_s_test_nth_kday(klass) == Qfalse)
09043         return Qfalse;
09044     if (date_s_test_unit_conv(klass) == Qfalse)
09045         return Qfalse;
09046     return Qtrue;
09047 }
09048 #endif
09049 
09050 static const char *monthnames[] = {
09051     NULL,
09052     "January", "February", "March",
09053     "April", "May", "June",
09054     "July", "August", "September",
09055     "October", "November", "December"
09056 };
09057 
09058 static const char *abbr_monthnames[] = {
09059     NULL,
09060     "Jan", "Feb", "Mar", "Apr",
09061     "May", "Jun", "Jul", "Aug",
09062     "Sep", "Oct", "Nov", "Dec"
09063 };
09064 
09065 static const char *daynames[] = {
09066     "Sunday", "Monday", "Tuesday", "Wednesday",
09067     "Thursday", "Friday", "Saturday"
09068 };
09069 
09070 static const char *abbr_daynames[] = {
09071     "Sun", "Mon", "Tue", "Wed",
09072     "Thu", "Fri", "Sat"
09073 };
09074 
09075 static VALUE
09076 mk_ary_of_str(long len, const char *a[])
09077 {
09078     VALUE o;
09079     long i;
09080 
09081     o = rb_ary_new2(len);
09082     for (i = 0; i < len; i++) {
09083         VALUE e;
09084 
09085         if (!a[i])
09086             e = Qnil;
09087         else {
09088             e = rb_usascii_str_new2(a[i]);
09089             rb_obj_freeze(e);
09090         }
09091         rb_ary_push(o, e);
09092     }
09093     rb_obj_freeze(o);
09094     return o;
09095 }
09096 
09097 void
09098 Init_date_core(void)
09099 {
09100 #undef rb_intern
09101 #define rb_intern(str) rb_intern_const(str)
09102 
09103     assert(fprintf(stderr, "assert() is now active\n"));
09104 
09105     id_cmp = rb_intern("<=>");
09106     id_le_p = rb_intern("<=");
09107     id_ge_p = rb_intern(">=");
09108     id_eqeq_p = rb_intern("==");
09109 
09110     half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
09111 
09112 #if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
09113     day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS *
09114                                   SECOND_IN_NANOSECONDS);
09115 #elif defined HAVE_LONG_LONG
09116     day_in_nanoseconds = LL2NUM((LONG_LONG)DAY_IN_SECONDS *
09117                                 SECOND_IN_NANOSECONDS);
09118 #else
09119     day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS),
09120                                INT2FIX(SECOND_IN_NANOSECONDS));
09121 #endif
09122 
09123     rb_gc_register_mark_object(half_days_in_day);
09124     rb_gc_register_mark_object(day_in_nanoseconds);
09125 
09126     positive_inf = +INFINITY;
09127     negative_inf = -INFINITY;
09128 
09129     /*
09130      * date and datetime class - Tadayoshi Funaba 1998-2011
09131      *
09132      * 'date' provides two classes Date and DateTime.
09133      *
09134      * == Terms and definitions
09135      *
09136      * Some terms and definitions are based on ISO 8601 and JIS X 0301.
09137      *
09138      * === calendar date
09139      *
09140      * The calendar date is a particular day of a calendar year,
09141      * identified by its ordinal number within a calendar month within
09142      * that year.
09143      *
09144      * In those classes, this is so-called "civil".
09145      *
09146      * === ordinal date
09147      *
09148      * The ordinal date is a particular day of a calendar year identified
09149      * by its ordinal number within the year.
09150      *
09151      * In those classes, this is so-called "ordinal".
09152      *
09153      * === week date
09154      *
09155      * The week date is a date identified by calendar week and day numbers.
09156      *
09157      * The calendar week is a seven day period within a calendar year,
09158      * starting on a Monday and identified by its ordinal number within
09159      * the year; the first calendar week of the year is the one that
09160      * includes the first Thursday of that year.  In the Gregorian
09161      * calendar, this is equivalent to the week which includes January 4.
09162      *
09163      * In those classes, this so-called "commercial".
09164      *
09165      * === julian day number
09166      *
09167      * The Julian day number is in elapsed days since noon (Greenwich mean
09168      * time) on January 1, 4713 BCE (in the Julian calendar).
09169      *
09170      * In this document, the astronomical Julian day number is same as the
09171      * original Julian day number.  And the chronological Julian day
09172      * number is a variation of the Julian day number.  Its days begin at
09173      * midnight on local time.
09174      *
09175      * In this document, when the term "Julian day number" simply appears,
09176      * it just refers to "chronological Julian day number", not the
09177      * original.
09178      *
09179      * In those classes, those are so-called "ajd" and "jd".
09180      *
09181      * === modified julian day number
09182      *
09183      * The modified Julian day number is in elapsed days since midnight
09184      * (Coordinated universal time) on November 17, 1858 CE (in the
09185      * Gregorian calendar).
09186      *
09187      * In this document, the astronomical modified Julian day number is
09188      * same as the original modified Julian day number.  And the
09189      * chronological modified Julian day number is a variation of the
09190      * modified Julian day number.  Its days begin at midnight on local
09191      * time.
09192      *
09193      * In this document, when the term "modified Julian day number" simply
09194      * appears, it just refers to "chronological modified Julian day
09195      * number", not the original.
09196      *
09197      * In those classes, this is so-called "mjd".
09198      *
09199      *
09200      * == Date
09201      *
09202      * A subclass of Object includes Comparable module, easily handles
09203      * date.
09204      *
09205      * Date object is created with Date::new, Date::jd, Date::ordinal,
09206      * Date::commercial, Date::parse, Date::strptime, Date::today,
09207      * Time#to_date or etc.
09208      *
09209      *     require 'date'
09210      *
09211      *     Date.new(2001,2,3)           #=> #<Date: 2001-02-03 ...>
09212      *     Date.jd(2451944)             #=> #<Date: 2001-02-03 ...>
09213      *     Date.ordinal(2001,34)        #=> #<Date: 2001-02-03 ...>
09214      *     Date.commercial(2001,5,6)    #=> #<Date: 2001-02-03 ...>
09215      *     Date.parse('2001-02-03')     #=> #<Date: 2001-02-03 ...>
09216      *     Date.strptime('03-02-2001', '%d-%m-%Y')
09217      *                                  #=> #<Date: 2001-02-03 ...>
09218      *     Time.new(2001,2,3).to_date   #=> #<Date: 2001-02-03 ...>
09219      *
09220      * All date objects are immutable; hence cannot modify themselves.
09221      *
09222      * The concept of this date object can be represented as a tuple
09223      * of the day count, the offset and the day of calendar reform.
09224      *
09225      * The day count denotes the absolute position of a temporal
09226      * dimension.  The offset is relative adjustment, which determines
09227      * decoded local time with the day count.  The day of calendar
09228      * reform denotes the start day of the new style.  The old style
09229      * of the West is the Julian calendar which was adopted by
09230      * Caersar.  The new style is the Gregorian calendar, which is the
09231      * current civil calendar of many countries.
09232      *
09233      * The day count is virtually the astronomical Julian day number.
09234      * The offset in this class is usually zero, and cannot be
09235      * specified directly.
09236      *
09237      * An optional argument the day of calendar reform (start) as a
09238      * Julian day number, which should be 2298874 to 2426355 or -/+oo.
09239      * The default value is Date::ITALY (2299161=1582-10-15).  See
09240      * also sample/cal.rb.
09241      *
09242      *     $ ruby sample/cal.rb -c it 10 1582
09243      *         October 1582
09244      *      S  M Tu  W Th  F  S
09245      *         1  2  3  4 15 16
09246      *     17 18 19 20 21 22 23
09247      *     24 25 26 27 28 29 30
09248      *     31
09249      *
09250      *     $ ruby sample/cal.rb -c gb  9 1752
09251      *        September 1752
09252      *      S  M Tu  W Th  F  S
09253      *            1  2 14 15 16
09254      *     17 18 19 20 21 22 23
09255      *     24 25 26 27 28 29 30
09256      *
09257      * Date object has various methods. See each reference.
09258      *
09259      *     d = Date.parse('3rd Feb 2001')
09260      *                                  #=> #<Date: 2001-02-03 ...>
09261      *     d.year                       #=> 2001
09262      *     d.mon                        #=> 2
09263      *     d.mday                       #=> 3
09264      *     d.wday                       #=> 6
09265      *     d += 1                       #=> #<Date: 2001-02-04 ...>
09266      *     d.strftime('%a %d %b %Y')    #=> "Sun 04 Feb 2001"
09267      *
09268      *
09269      * == DateTime
09270      *
09271      * A subclass of Date easily handles date, hour, minute, second and
09272      * offset.
09273      *
09274      * DateTime does not consider any leapseconds, does not track
09275      * any summer time rules.
09276      *
09277      * DateTime object is created with DateTime::new, DateTime::jd,
09278      * DateTime::ordinal, DateTime::commercial, DateTime::parse,
09279      * DateTime::strptime, DateTime::now, Time#to_datetime or etc.
09280      *
09281      *     require 'date'
09282      *
09283      *     DateTime.new(2001,2,3,4,5,6)
09284      *                          #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...>
09285      *
09286      * The last element of day, hour, minute or senond can be
09287      * fractional number. The fractional number's precision is assumed
09288      * at most nanosecond.
09289      *
09290      *     DateTime.new(2001,2,3.5)
09291      *                          #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...>
09292      *
09293      * An optional argument the offset indicates the difference
09294      * between the local time and UTC.  For example, Rational(3,24)
09295      * represents ahead of 3 hours of UTC, Rational(-5,24) represents
09296      * behind of 5 hours of UTC.  The offset should be -1 to +1, and
09297      * its precision is assumed at most second.  The default value is
09298      * zero (equals to UTC).
09299      *
09300      *     DateTime.new(2001,2,3,4,5,6,Rational(3,24))
09301      *                          #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
09302      * also accepts string form.
09303      *
09304      *     DateTime.new(2001,2,3,4,5,6,'+03:00')
09305      *                          #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...>
09306      *
09307      * An optional argument the day of calendar reform (start) denotes
09308      * a Julian day number, which should be 2298874 to 2426355 or
09309      * -/+oo.  The default value is Date::ITALY (2299161=1582-10-15).
09310      *
09311      * DateTime object has various methods. See each reference.
09312      *
09313      *     d = DateTime.parse('3rd Feb 2001 04:05:06+03:30')
09314      *                          #=> #<DateTime: 2001-02-03T04:05:06+03:30 ...>
09315      *     d.hour               #=> 4
09316      *     d.min                #=> 5
09317      *     d.sec                #=> 6
09318      *     d.offset             #=> (7/48)
09319      *     d.zone               #=> "+03:30"
09320      *     d += Rational('1.5')
09321      *                          #=> #<DateTime: 2001-02-04%16:05:06+03:30 ...>
09322      *     d = d.new_offset('+09:00')
09323      *                          #=> #<DateTime: 2001-02-04%21:35:06+09:00 ...>
09324      *     d.strftime('%I:%M:%S %p')
09325      *                          #=> "09:35:06 PM"
09326      *     d > DateTime.new(1999)
09327      *                          #=> true
09328      */
09329     cDate = rb_define_class("Date", rb_cObject);
09330 
09331     rb_include_module(cDate, rb_mComparable);
09332 
09333     /* An array of stirng of full month name in English.  The first
09334      * element is nil.
09335      */
09336     rb_define_const(cDate, "MONTHNAMES", mk_ary_of_str(13, monthnames));
09337 
09338     /* An array of string of abbreviated month name in English.  The
09339      * first element is nil.
09340      */
09341     rb_define_const(cDate, "ABBR_MONTHNAMES",
09342                     mk_ary_of_str(13, abbr_monthnames));
09343 
09344     /* An array of string of full name of days of the week in English.
09345      * The first is "Sunday".
09346      */
09347     rb_define_const(cDate, "DAYNAMES", mk_ary_of_str(7, daynames));
09348 
09349     /* An array of string of abbreviated day name in English.  The
09350      * first is "Sun".
09351      */
09352     rb_define_const(cDate, "ABBR_DAYNAMES", mk_ary_of_str(7, abbr_daynames));
09353 
09354     /* The Julian day number of the day of calendar reform for Italy
09355      * and some catholic countries.
09356      */
09357     rb_define_const(cDate, "ITALY", INT2FIX(ITALY));
09358 
09359     /* The Julian day number of the day of calendar reform for England
09360      * and her colonies.
09361      */
09362     rb_define_const(cDate, "ENGLAND", INT2FIX(ENGLAND));
09363 
09364     /* The Julian day number of the day of calendar reform for the
09365      * proleptic Julian calendar
09366      */
09367     rb_define_const(cDate, "JULIAN", DBL2NUM(JULIAN));
09368 
09369     /* The Julian day number of the day of calendar reform for the
09370      * proleptic Gregorian calendar
09371      */
09372     rb_define_const(cDate, "GREGORIAN", DBL2NUM(GREGORIAN));
09373 
09374     rb_define_alloc_func(cDate, d_lite_s_alloc);
09375 
09376 #ifndef NDEBUG
09377 #define de_define_private_method rb_define_private_method
09378     de_define_private_method(CLASS_OF(cDate), "_valid_jd?",
09379                              date_s__valid_jd_p, -1);
09380     de_define_private_method(CLASS_OF(cDate), "_valid_ordinal?",
09381                              date_s__valid_ordinal_p, -1);
09382     de_define_private_method(CLASS_OF(cDate), "_valid_civil?",
09383                              date_s__valid_civil_p, -1);
09384     de_define_private_method(CLASS_OF(cDate), "_valid_date?",
09385                              date_s__valid_civil_p, -1);
09386     de_define_private_method(CLASS_OF(cDate), "_valid_commercial?",
09387                              date_s__valid_commercial_p, -1);
09388     de_define_private_method(CLASS_OF(cDate), "_valid_weeknum?",
09389                              date_s__valid_weeknum_p, -1);
09390     de_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?",
09391                              date_s__valid_nth_kday_p, -1);
09392 #endif
09393 
09394     rb_define_singleton_method(cDate, "valid_jd?", date_s_valid_jd_p, -1);
09395     rb_define_singleton_method(cDate, "valid_ordinal?",
09396                                date_s_valid_ordinal_p, -1);
09397     rb_define_singleton_method(cDate, "valid_civil?", date_s_valid_civil_p, -1);
09398     rb_define_singleton_method(cDate, "valid_date?", date_s_valid_civil_p, -1);
09399     rb_define_singleton_method(cDate, "valid_commercial?",
09400                                date_s_valid_commercial_p, -1);
09401 
09402 #ifndef NDEBUG
09403     de_define_private_method(CLASS_OF(cDate), "valid_weeknum?",
09404                              date_s_valid_weeknum_p, -1);
09405     de_define_private_method(CLASS_OF(cDate), "valid_nth_kday?",
09406                              date_s_valid_nth_kday_p, -1);
09407     de_define_private_method(CLASS_OF(cDate), "zone_to_diff",
09408                              date_s_zone_to_diff, 1);
09409 #endif
09410 
09411     rb_define_singleton_method(cDate, "julian_leap?", date_s_julian_leap_p, 1);
09412     rb_define_singleton_method(cDate, "gregorian_leap?",
09413                                date_s_gregorian_leap_p, 1);
09414     rb_define_singleton_method(cDate, "leap?",
09415                                date_s_gregorian_leap_p, 1);
09416 
09417 #ifndef NDEBUG
09418 #define de_define_singleton_method rb_define_singleton_method
09419 #define de_define_alias rb_define_alias
09420     de_define_singleton_method(cDate, "new!", date_s_new_bang, -1);
09421     de_define_alias(rb_singleton_class(cDate), "new_l!", "new");
09422 #endif
09423 
09424     rb_define_singleton_method(cDate, "jd", date_s_jd, -1);
09425     rb_define_singleton_method(cDate, "ordinal", date_s_ordinal, -1);
09426     rb_define_singleton_method(cDate, "civil", date_s_civil, -1);
09427     rb_define_singleton_method(cDate, "new", date_s_civil, -1);
09428     rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1);
09429 
09430 #ifndef NDEBUG
09431     de_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1);
09432     de_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1);
09433 #endif
09434 
09435     rb_define_singleton_method(cDate, "today", date_s_today, -1);
09436     rb_define_singleton_method(cDate, "_strptime", date_s__strptime, -1);
09437     rb_define_singleton_method(cDate, "strptime", date_s_strptime, -1);
09438     rb_define_singleton_method(cDate, "_parse", date_s__parse, -1);
09439     rb_define_singleton_method(cDate, "parse", date_s_parse, -1);
09440     rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, 1);
09441     rb_define_singleton_method(cDate, "iso8601", date_s_iso8601, -1);
09442     rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, 1);
09443     rb_define_singleton_method(cDate, "rfc3339", date_s_rfc3339, -1);
09444     rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, 1);
09445     rb_define_singleton_method(cDate, "xmlschema", date_s_xmlschema, -1);
09446     rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, 1);
09447     rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, 1);
09448     rb_define_singleton_method(cDate, "rfc2822", date_s_rfc2822, -1);
09449     rb_define_singleton_method(cDate, "rfc822", date_s_rfc2822, -1);
09450     rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, 1);
09451     rb_define_singleton_method(cDate, "httpdate", date_s_httpdate, -1);
09452     rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, 1);
09453     rb_define_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1);
09454 
09455 #ifndef NDEBUG
09456 #define de_define_method rb_define_method
09457     de_define_method(cDate, "initialize", d_lite_initialize, -1);
09458 #endif
09459     rb_define_method(cDate, "initialize_copy", d_lite_initialize_copy, 1);
09460 
09461 #ifndef NDEBUG
09462     de_define_method(cDate, "fill", d_lite_fill, 0);
09463 #endif
09464 
09465     rb_define_method(cDate, "ajd", d_lite_ajd, 0);
09466     rb_define_method(cDate, "amjd", d_lite_amjd, 0);
09467     rb_define_method(cDate, "jd", d_lite_jd, 0);
09468     rb_define_method(cDate, "mjd", d_lite_mjd, 0);
09469     rb_define_method(cDate, "ld", d_lite_ld, 0);
09470 
09471     rb_define_method(cDate, "year", d_lite_year, 0);
09472     rb_define_method(cDate, "yday", d_lite_yday, 0);
09473     rb_define_method(cDate, "mon", d_lite_mon, 0);
09474     rb_define_method(cDate, "month", d_lite_mon, 0);
09475     rb_define_method(cDate, "mday", d_lite_mday, 0);
09476     rb_define_method(cDate, "day", d_lite_mday, 0);
09477     rb_define_method(cDate, "day_fraction", d_lite_day_fraction, 0);
09478 
09479     rb_define_method(cDate, "cwyear", d_lite_cwyear, 0);
09480     rb_define_method(cDate, "cweek", d_lite_cweek, 0);
09481     rb_define_method(cDate, "cwday", d_lite_cwday, 0);
09482 
09483 #ifndef NDEBUG
09484     de_define_private_method(cDate, "wnum0", d_lite_wnum0, 0);
09485     de_define_private_method(cDate, "wnum1", d_lite_wnum1, 0);
09486 #endif
09487 
09488     rb_define_method(cDate, "wday", d_lite_wday, 0);
09489 
09490     rb_define_method(cDate, "sunday?", d_lite_sunday_p, 0);
09491     rb_define_method(cDate, "monday?", d_lite_monday_p, 0);
09492     rb_define_method(cDate, "tuesday?", d_lite_tuesday_p, 0);
09493     rb_define_method(cDate, "wednesday?", d_lite_wednesday_p, 0);
09494     rb_define_method(cDate, "thursday?", d_lite_thursday_p, 0);
09495     rb_define_method(cDate, "friday?", d_lite_friday_p, 0);
09496     rb_define_method(cDate, "saturday?", d_lite_saturday_p, 0);
09497 
09498 #ifndef NDEBUG
09499     de_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2);
09500 #endif
09501 
09502     rb_define_private_method(cDate, "hour", d_lite_hour, 0);
09503     rb_define_private_method(cDate, "min", d_lite_min, 0);
09504     rb_define_private_method(cDate, "minute", d_lite_min, 0);
09505     rb_define_private_method(cDate, "sec", d_lite_sec, 0);
09506     rb_define_private_method(cDate, "second", d_lite_sec, 0);
09507     rb_define_private_method(cDate, "sec_fraction", d_lite_sec_fraction, 0);
09508     rb_define_private_method(cDate, "second_fraction", d_lite_sec_fraction, 0);
09509     rb_define_private_method(cDate, "offset", d_lite_offset, 0);
09510     rb_define_private_method(cDate, "zone", d_lite_zone, 0);
09511 
09512     rb_define_method(cDate, "julian?", d_lite_julian_p, 0);
09513     rb_define_method(cDate, "gregorian?", d_lite_gregorian_p, 0);
09514     rb_define_method(cDate, "leap?", d_lite_leap_p, 0);
09515 
09516     rb_define_method(cDate, "start", d_lite_start, 0);
09517     rb_define_method(cDate, "new_start", d_lite_new_start, -1);
09518     rb_define_method(cDate, "italy", d_lite_italy, 0);
09519     rb_define_method(cDate, "england", d_lite_england, 0);
09520     rb_define_method(cDate, "julian", d_lite_julian, 0);
09521     rb_define_method(cDate, "gregorian", d_lite_gregorian, 0);
09522 
09523     rb_define_private_method(cDate, "new_offset", d_lite_new_offset, -1);
09524 
09525     rb_define_method(cDate, "+", d_lite_plus, 1);
09526     rb_define_method(cDate, "-", d_lite_minus, 1);
09527 
09528     rb_define_method(cDate, "next_day", d_lite_next_day, -1);
09529     rb_define_method(cDate, "prev_day", d_lite_prev_day, -1);
09530     rb_define_method(cDate, "next", d_lite_next, 0);
09531     rb_define_method(cDate, "succ", d_lite_next, 0);
09532 
09533     rb_define_method(cDate, ">>", d_lite_rshift, 1);
09534     rb_define_method(cDate, "<<", d_lite_lshift, 1);
09535 
09536     rb_define_method(cDate, "next_month", d_lite_next_month, -1);
09537     rb_define_method(cDate, "prev_month", d_lite_prev_month, -1);
09538     rb_define_method(cDate, "next_year", d_lite_next_year, -1);
09539     rb_define_method(cDate, "prev_year", d_lite_prev_year, -1);
09540 
09541     rb_define_method(cDate, "step", d_lite_step, -1);
09542     rb_define_method(cDate, "upto", d_lite_upto, 1);
09543     rb_define_method(cDate, "downto", d_lite_downto, 1);
09544 
09545     rb_define_method(cDate, "<=>", d_lite_cmp, 1);
09546     rb_define_method(cDate, "===", d_lite_equal, 1);
09547     rb_define_method(cDate, "eql?", d_lite_eql_p, 1);
09548     rb_define_method(cDate, "hash", d_lite_hash, 0);
09549 
09550     rb_define_method(cDate, "to_s", d_lite_to_s, 0);
09551 #ifndef NDEBUG
09552     de_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0);
09553 #endif
09554     rb_define_method(cDate, "inspect", d_lite_inspect, 0);
09555 
09556     rb_define_method(cDate, "strftime", d_lite_strftime, -1);
09557 
09558     rb_define_method(cDate, "asctime", d_lite_asctime, 0);
09559     rb_define_method(cDate, "ctime", d_lite_asctime, 0);
09560     rb_define_method(cDate, "iso8601", d_lite_iso8601, 0);
09561     rb_define_method(cDate, "xmlschema", d_lite_iso8601, 0);
09562     rb_define_method(cDate, "rfc3339", d_lite_rfc3339, 0);
09563     rb_define_method(cDate, "rfc2822", d_lite_rfc2822, 0);
09564     rb_define_method(cDate, "rfc822", d_lite_rfc2822, 0);
09565     rb_define_method(cDate, "httpdate", d_lite_httpdate, 0);
09566     rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0);
09567 
09568 #ifndef NDEBUG
09569     de_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0);
09570 #endif
09571     rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0);
09572     rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1);
09573     rb_define_singleton_method(cDate, "_load", date_s__load, 1);
09574 
09575     /* datetime */
09576 
09577     cDateTime = rb_define_class("DateTime", cDate);
09578 
09579     rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1);
09580     rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1);
09581     rb_define_singleton_method(cDateTime, "civil", datetime_s_civil, -1);
09582     rb_define_singleton_method(cDateTime, "new", datetime_s_civil, -1);
09583     rb_define_singleton_method(cDateTime, "commercial",
09584                                datetime_s_commercial, -1);
09585 
09586 #ifndef NDEBUG
09587     de_define_singleton_method(cDateTime, "weeknum",
09588                                datetime_s_weeknum, -1);
09589     de_define_singleton_method(cDateTime, "nth_kday",
09590                                datetime_s_nth_kday, -1);
09591 #endif
09592 
09593     rb_undef_method(CLASS_OF(cDateTime), "today");
09594 
09595     rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1);
09596     rb_define_singleton_method(cDateTime, "_strptime",
09597                                datetime_s__strptime, -1);
09598     rb_define_singleton_method(cDateTime, "strptime",
09599                                datetime_s_strptime, -1);
09600     rb_define_singleton_method(cDateTime, "parse",
09601                                datetime_s_parse, -1);
09602     rb_define_singleton_method(cDateTime, "iso8601",
09603                                datetime_s_iso8601, -1);
09604     rb_define_singleton_method(cDateTime, "rfc3339",
09605                                datetime_s_rfc3339, -1);
09606     rb_define_singleton_method(cDateTime, "xmlschema",
09607                                datetime_s_xmlschema, -1);
09608     rb_define_singleton_method(cDateTime, "rfc2822",
09609                                datetime_s_rfc2822, -1);
09610     rb_define_singleton_method(cDateTime, "rfc822",
09611                                datetime_s_rfc2822, -1);
09612     rb_define_singleton_method(cDateTime, "httpdate",
09613                                datetime_s_httpdate, -1);
09614     rb_define_singleton_method(cDateTime, "jisx0301",
09615                                datetime_s_jisx0301, -1);
09616 
09617 #define f_public(m,s) rb_funcall(m, rb_intern("public"), 1,\
09618                                  ID2SYM(rb_intern(s)))
09619 
09620     f_public(cDateTime, "hour");
09621     f_public(cDateTime, "min");
09622     f_public(cDateTime, "minute");
09623     f_public(cDateTime, "sec");
09624     f_public(cDateTime, "second");
09625     f_public(cDateTime, "sec_fraction");
09626     f_public(cDateTime, "second_fraction");
09627     f_public(cDateTime, "offset");
09628     f_public(cDateTime, "zone");
09629     f_public(cDateTime, "new_offset");
09630 
09631     rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0);
09632 
09633     rb_define_method(cDateTime, "strftime", dt_lite_strftime, -1);
09634 
09635     rb_define_method(cDateTime, "iso8601", dt_lite_iso8601, -1);
09636     rb_define_method(cDateTime, "xmlschema", dt_lite_iso8601, -1);
09637     rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1);
09638     rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1);
09639 
09640     /* conversions */
09641 
09642     rb_define_method(rb_cTime, "to_time", time_to_time, 0);
09643     rb_define_method(rb_cTime, "to_date", time_to_date, 0);
09644     rb_define_method(rb_cTime, "to_datetime", time_to_datetime, 0);
09645 
09646     rb_define_method(cDate, "to_time", date_to_time, 0);
09647     rb_define_method(cDate, "to_date", date_to_date, 0);
09648     rb_define_method(cDate, "to_datetime", date_to_datetime, 0);
09649 
09650     rb_define_method(cDateTime, "to_time", datetime_to_time, 0);
09651     rb_define_method(cDateTime, "to_date", datetime_to_date, 0);
09652     rb_define_method(cDateTime, "to_datetime", datetime_to_datetime, 0);
09653 
09654 #ifndef NDEBUG
09655     /* tests */
09656 
09657     de_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0);
09658     de_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0);
09659     de_define_singleton_method(cDate, "test_commercial",
09660                                date_s_test_commercial, 0);
09661     de_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0);
09662     de_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0);
09663     de_define_singleton_method(cDate, "test_unit_conv",
09664                                date_s_test_unit_conv, 0);
09665     de_define_singleton_method(cDate, "test_all", date_s_test_all, 0);
09666 #endif
09667 }
09668 
09669 /*
09670 Local variables:
09671 c-file-style: "ruby"
09672 End:
09673 */
09674