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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7