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