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