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