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