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