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