1/* 2 date_core.c: Coded by Tadayoshi Funaba 2010-2013 3*/ 4 5#include "ruby.h" 6#include "ruby/encoding.h" 7#include <math.h> 8#include <time.h> 9 10#define NDEBUG 11#include <assert.h> 12 13#ifdef RUBY_EXTCONF_H 14#include RUBY_EXTCONF_H 15#endif 16 17#define USE_PACK 18 19static ID id_cmp, id_le_p, id_ge_p, id_eqeq_p; 20static VALUE cDate, cDateTime; 21static VALUE half_days_in_day, day_in_nanoseconds; 22static double positive_inf, negative_inf; 23 24#define f_boolcast(x) ((x) ? Qtrue : Qfalse) 25 26#define f_abs(x) rb_funcall(x, rb_intern("abs"), 0) 27#define f_negate(x) rb_funcall(x, rb_intern("-@"), 0) 28#define f_add(x,y) rb_funcall(x, '+', 1, y) 29#define f_sub(x,y) rb_funcall(x, '-', 1, y) 30#define f_mul(x,y) rb_funcall(x, '*', 1, y) 31#define f_div(x,y) rb_funcall(x, '/', 1, y) 32#define f_quo(x,y) rb_funcall(x, rb_intern("quo"), 1, y) 33#define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y) 34#define f_mod(x,y) rb_funcall(x, '%', 1, y) 35#define f_remainder(x,y) rb_funcall(x, rb_intern("remainder"), 1, y) 36#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y) 37#define f_floor(x) rb_funcall(x, rb_intern("floor"), 0) 38#define f_ceil(x) rb_funcall(x, rb_intern("ceil"), 0) 39#define f_truncate(x) rb_funcall(x, rb_intern("truncate"), 0) 40#define f_round(x) rb_funcall(x, rb_intern("round"), 0) 41 42#define f_to_i(x) rb_funcall(x, rb_intern("to_i"), 0) 43#define f_to_r(x) rb_funcall(x, rb_intern("to_r"), 0) 44#define f_to_s(x) rb_funcall(x, rb_intern("to_s"), 0) 45#define f_inspect(x) rb_funcall(x, rb_intern("inspect"), 0) 46 47#define f_add3(x,y,z) f_add(f_add(x, y), z) 48#define f_sub3(x,y,z) f_sub(f_sub(x, y), z) 49 50inline static VALUE 51f_cmp(VALUE x, VALUE y) 52{ 53 if (FIXNUM_P(x) && FIXNUM_P(y)) { 54 long c = FIX2LONG(x) - FIX2LONG(y); 55 if (c > 0) 56 c = 1; 57 else if (c < 0) 58 c = -1; 59 return INT2FIX(c); 60 } 61 return rb_funcall(x, id_cmp, 1, y); 62} 63 64inline static VALUE 65f_lt_p(VALUE x, VALUE y) 66{ 67 if (FIXNUM_P(x) && FIXNUM_P(y)) 68 return f_boolcast(FIX2LONG(x) < FIX2LONG(y)); 69 return rb_funcall(x, '<', 1, y); 70} 71 72inline static VALUE 73f_gt_p(VALUE x, VALUE y) 74{ 75 if (FIXNUM_P(x) && FIXNUM_P(y)) 76 return f_boolcast(FIX2LONG(x) > FIX2LONG(y)); 77 return rb_funcall(x, '>', 1, y); 78} 79 80inline static VALUE 81f_le_p(VALUE x, VALUE y) 82{ 83 if (FIXNUM_P(x) && FIXNUM_P(y)) 84 return f_boolcast(FIX2LONG(x) <= FIX2LONG(y)); 85 return rb_funcall(x, id_le_p, 1, y); 86} 87 88inline static VALUE 89f_ge_p(VALUE x, VALUE y) 90{ 91 if (FIXNUM_P(x) && FIXNUM_P(y)) 92 return f_boolcast(FIX2LONG(x) >= FIX2LONG(y)); 93 return rb_funcall(x, rb_intern(">="), 1, y); 94} 95 96inline static VALUE 97f_eqeq_p(VALUE x, VALUE y) 98{ 99 if (FIXNUM_P(x) && FIXNUM_P(y)) 100 return f_boolcast(FIX2LONG(x) == FIX2LONG(y)); 101 return rb_funcall(x, rb_intern("=="), 1, y); 102} 103 104inline static VALUE 105f_zero_p(VALUE x) 106{ 107 switch (TYPE(x)) { 108 case T_FIXNUM: 109 return f_boolcast(FIX2LONG(x) == 0); 110 case T_BIGNUM: 111 return Qfalse; 112 case T_RATIONAL: 113 { 114 VALUE num = RRATIONAL(x)->num; 115 return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0); 116 } 117 } 118 return rb_funcall(x, id_eqeq_p, 1, INT2FIX(0)); 119} 120 121#define f_nonzero_p(x) (!f_zero_p(x)) 122 123inline static VALUE 124f_negative_p(VALUE x) 125{ 126 if (FIXNUM_P(x)) 127 return f_boolcast(FIX2LONG(x) < 0); 128 return rb_funcall(x, '<', 1, INT2FIX(0)); 129} 130 131#define f_positive_p(x) (!f_negative_p(x)) 132 133#define f_ajd(x) rb_funcall(x, rb_intern("ajd"), 0) 134#define f_jd(x) rb_funcall(x, rb_intern("jd"), 0) 135#define f_year(x) rb_funcall(x, rb_intern("year"), 0) 136#define f_mon(x) rb_funcall(x, rb_intern("mon"), 0) 137#define f_mday(x) rb_funcall(x, rb_intern("mday"), 0) 138#define f_wday(x) rb_funcall(x, rb_intern("wday"), 0) 139#define f_hour(x) rb_funcall(x, rb_intern("hour"), 0) 140#define f_min(x) rb_funcall(x, rb_intern("min"), 0) 141#define f_sec(x) rb_funcall(x, rb_intern("sec"), 0) 142 143/* copied from time.c */ 144#define NDIV(x,y) (-(-((x)+1)/(y))-1) 145#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) 146#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) 147#define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d)) 148 149#define HAVE_JD (1 << 0) 150#define HAVE_DF (1 << 1) 151#define HAVE_CIVIL (1 << 2) 152#define HAVE_TIME (1 << 3) 153#define COMPLEX_DAT (1 << 7) 154 155#define have_jd_p(x) ((x)->flags & HAVE_JD) 156#define have_df_p(x) ((x)->flags & HAVE_DF) 157#define have_civil_p(x) ((x)->flags & HAVE_CIVIL) 158#define have_time_p(x) ((x)->flags & HAVE_TIME) 159#define complex_dat_p(x) ((x)->flags & COMPLEX_DAT) 160#define simple_dat_p(x) (!complex_dat_p(x)) 161 162#define ITALY 2299161 /* 1582-10-15 */ 163#define ENGLAND 2361222 /* 1752-09-14 */ 164#define JULIAN positive_inf 165#define GREGORIAN negative_inf 166#define DEFAULT_SG ITALY 167 168#define UNIX_EPOCH_IN_CJD INT2FIX(2440588) /* 1970-01-01 */ 169 170#define MINUTE_IN_SECONDS 60 171#define HOUR_IN_SECONDS 3600 172#define DAY_IN_SECONDS 86400 173#define SECOND_IN_MILLISECONDS 1000 174#define SECOND_IN_NANOSECONDS 1000000000 175 176#define JC_PERIOD0 1461 /* 365.25 * 4 */ 177#define GC_PERIOD0 146097 /* 365.2425 * 400 */ 178#define CM_PERIOD0 71149239 /* (lcm 7 1461 146097) */ 179#define CM_PERIOD (0xfffffff / CM_PERIOD0 * CM_PERIOD0) 180#define CM_PERIOD_JCY (CM_PERIOD / JC_PERIOD0 * 4) 181#define CM_PERIOD_GCY (CM_PERIOD / GC_PERIOD0 * 400) 182 183#define REFORM_BEGIN_YEAR 1582 184#define REFORM_END_YEAR 1930 185#define REFORM_BEGIN_JD 2298874 /* ns 1582-01-01 */ 186#define REFORM_END_JD 2426355 /* os 1930-12-31 */ 187 188#ifdef USE_PACK 189#define SEC_WIDTH 6 190#define MIN_WIDTH 6 191#define HOUR_WIDTH 5 192#define MDAY_WIDTH 5 193#define MON_WIDTH 4 194 195#define SEC_SHIFT 0 196#define MIN_SHIFT SEC_WIDTH 197#define HOUR_SHIFT (MIN_WIDTH + SEC_WIDTH) 198#define MDAY_SHIFT (HOUR_WIDTH + MIN_WIDTH + SEC_WIDTH) 199#define MON_SHIFT (MDAY_WIDTH + HOUR_WIDTH + MIN_WIDTH + SEC_WIDTH) 200 201#define PK_MASK(x) ((1 << (x)) - 1) 202 203#define EX_SEC(x) (((x) >> SEC_SHIFT) & PK_MASK(SEC_WIDTH)) 204#define EX_MIN(x) (((x) >> MIN_SHIFT) & PK_MASK(MIN_WIDTH)) 205#define EX_HOUR(x) (((x) >> HOUR_SHIFT) & PK_MASK(HOUR_WIDTH)) 206#define EX_MDAY(x) (((x) >> MDAY_SHIFT) & PK_MASK(MDAY_WIDTH)) 207#define EX_MON(x) (((x) >> MON_SHIFT) & PK_MASK(MON_WIDTH)) 208 209#define PACK5(m,d,h,min,s) \ 210 (((m) << MON_SHIFT) | ((d) << MDAY_SHIFT) |\ 211 ((h) << HOUR_SHIFT) | ((min) << MIN_SHIFT) | ((s) << SEC_SHIFT)) 212 213#define PACK2(m,d) \ 214 (((m) << MON_SHIFT) | ((d) << MDAY_SHIFT)) 215#endif 216 217#ifdef HAVE_FLOAT_H 218#include <float.h> 219#endif 220 221#if defined(FLT_RADIX) && defined(FLT_MANT_DIG) && FLT_RADIX == 2 && FLT_MANT_DIG > 22 222#define date_sg_t float 223#else 224#define date_sg_t double 225#endif 226 227/* A set of nth, jd, df and sf denote ajd + 1/2. Each ajd begin at 228 * noon of GMT (assume equal to UTC). However, this begins at 229 * midnight. 230 */ 231 232struct SimpleDateData 233{ 234 unsigned flags; 235 VALUE nth; /* not always canonicalized */ 236 int jd; /* as utc */ 237 /* df is zero */ 238 /* sf is zero */ 239 /* of is zero */ 240 date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ 241 /* decoded as utc=local */ 242 int year; /* truncated */ 243#ifndef USE_PACK 244 int mon; 245 int mday; 246 /* hour is zero */ 247 /* min is zero */ 248 /* sec is zero */ 249#else 250 /* packed civil */ 251 unsigned pc; 252#endif 253}; 254 255struct ComplexDateData 256{ 257 unsigned flags; 258 VALUE nth; /* not always canonicalized */ 259 int jd; /* as utc */ 260 int df; /* as utc, in secs */ 261 VALUE sf; /* in nano secs */ 262 int of; /* in secs */ 263 date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ 264 /* decoded as local */ 265 int year; /* truncated */ 266#ifndef USE_PACK 267 int mon; 268 int mday; 269 int hour; 270 int min; 271 int sec; 272#else 273 /* packed civil */ 274 unsigned pc; 275#endif 276}; 277 278union DateData { 279 unsigned flags; 280 struct SimpleDateData s; 281 struct ComplexDateData c; 282}; 283 284#define get_d1(x)\ 285 union DateData *dat;\ 286 Data_Get_Struct(x, union DateData, dat); 287 288#define get_d1a(x)\ 289 union DateData *adat;\ 290 Data_Get_Struct(x, union DateData, adat); 291 292#define get_d1b(x)\ 293 union DateData *bdat;\ 294 Data_Get_Struct(x, union DateData, bdat); 295 296#define get_d2(x,y)\ 297 union DateData *adat, *bdat;\ 298 Data_Get_Struct(x, union DateData, adat);\ 299 Data_Get_Struct(y, union DateData, bdat); 300 301inline static VALUE 302canon(VALUE x) 303{ 304 if (TYPE(x) == T_RATIONAL) { 305 VALUE den = RRATIONAL(x)->den; 306 if (FIXNUM_P(den) && FIX2LONG(den) == 1) 307 return RRATIONAL(x)->num; 308 } 309 return x; 310} 311 312#ifndef USE_PACK 313#define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ 314{\ 315 (x)->nth = canon(_nth);\ 316 (x)->jd = _jd;\ 317 (x)->sg = (date_sg_t)(_sg);\ 318 (x)->year = _year;\ 319 (x)->mon = _mon;\ 320 (x)->mday = _mday;\ 321 (x)->flags = _flags;\ 322} 323#else 324#define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ 325{\ 326 (x)->nth = canon(_nth);\ 327 (x)->jd = _jd;\ 328 (x)->sg = (date_sg_t)(_sg);\ 329 (x)->year = _year;\ 330 (x)->pc = PACK2(_mon, _mday);\ 331 (x)->flags = _flags;\ 332} 333#endif 334 335#ifndef USE_PACK 336#define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\ 337_year, _mon, _mday, _hour, _min, _sec, _flags) \ 338{\ 339 (x)->nth = canon(_nth);\ 340 (x)->jd = _jd;\ 341 (x)->df = _df;\ 342 (x)->sf = canon(_sf);\ 343 (x)->of = _of;\ 344 (x)->sg = (date_sg_t)(_sg);\ 345 (x)->year = _year;\ 346 (x)->mon = _mon;\ 347 (x)->mday = _mday;\ 348 (x)->hour = _hour;\ 349 (x)->min = _min;\ 350 (x)->sec = _sec;\ 351 (x)->flags = _flags;\ 352} 353#else 354#define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\ 355_year, _mon, _mday, _hour, _min, _sec, _flags) \ 356{\ 357 (x)->nth = canon(_nth);\ 358 (x)->jd = _jd;\ 359 (x)->df = _df;\ 360 (x)->sf = canon(_sf);\ 361 (x)->of = _of;\ 362 (x)->sg = (date_sg_t)(_sg);\ 363 (x)->year = _year;\ 364 (x)->pc = PACK5(_mon, _mday, _hour, _min, _sec);\ 365 (x)->flags = _flags;\ 366} 367#endif 368 369#ifndef USE_PACK 370#define copy_simple_to_complex(x, y) \ 371{\ 372 (x)->nth = (y)->nth;\ 373 (x)->jd = (y)->jd;\ 374 (x)->df = 0;\ 375 (x)->sf = INT2FIX(0);\ 376 (x)->of = 0;\ 377 (x)->sg = (date_sg_t)((y)->sg);\ 378 (x)->year = (y)->year;\ 379 (x)->mon = (y)->mon;\ 380 (x)->mday = (y)->mday;\ 381 (x)->hour = 0;\ 382 (x)->min = 0;\ 383 (x)->sec = 0;\ 384 (x)->flags = (y)->flags;\ 385} 386#else 387#define copy_simple_to_complex(x, y) \ 388{\ 389 (x)->nth = (y)->nth;\ 390 (x)->jd = (y)->jd;\ 391 (x)->df = 0;\ 392 (x)->sf = INT2FIX(0);\ 393 (x)->of = 0;\ 394 (x)->sg = (date_sg_t)((y)->sg);\ 395 (x)->year = (y)->year;\ 396 (x)->pc = PACK5(EX_MON((y)->pc), EX_MDAY((y)->pc), 0, 0, 0);\ 397 (x)->flags = (y)->flags;\ 398} 399#endif 400 401#ifndef USE_PACK 402#define copy_complex_to_simple(x, y) \ 403{\ 404 (x)->nth = (y)->nth;\ 405 (x)->jd = (y)->jd;\ 406 (x)->sg = (date_sg_t)((y)->sg);\ 407 (x)->year = (y)->year;\ 408 (x)->mon = (y)->mon;\ 409 (x)->mday = (y)->mday;\ 410 (x)->flags = (y)->flags;\ 411} 412#else 413#define copy_complex_to_simple(x, y) \ 414{\ 415 (x)->nth = (y)->nth;\ 416 (x)->jd = (y)->jd;\ 417 (x)->sg = (date_sg_t)((y)->sg);\ 418 (x)->year = (y)->year;\ 419 (x)->pc = PACK2(EX_MON((y)->pc), EX_MDAY((y)->pc));\ 420 (x)->flags = (y)->flags;\ 421} 422#endif 423 424/* base */ 425 426static int c_valid_civil_p(int, int, int, double, 427 int *, int *, int *, int *); 428 429static int 430c_find_fdoy(int y, double sg, int *rjd, int *ns) 431{ 432 int d, rm, rd; 433 434 for (d = 1; d < 31; d++) 435 if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns)) 436 return 1; 437 return 0; 438} 439 440static int 441c_find_ldoy(int y, double sg, int *rjd, int *ns) 442{ 443 int i, rm, rd; 444 445 for (i = 0; i < 30; i++) 446 if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns)) 447 return 1; 448 return 0; 449} 450 451#ifndef NDEBUG 452static int 453c_find_fdom(int y, int m, double sg, int *rjd, int *ns) 454{ 455 int d, rm, rd; 456 457 for (d = 1; d < 31; d++) 458 if (c_valid_civil_p(y, m, d, sg, &rm, &rd, rjd, ns)) 459 return 1; 460 return 0; 461} 462#endif 463 464static int 465c_find_ldom(int y, int m, double sg, int *rjd, int *ns) 466{ 467 int i, rm, rd; 468 469 for (i = 0; i < 30; i++) 470 if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns)) 471 return 1; 472 return 0; 473} 474 475static void 476c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns) 477{ 478 double a, b, jd; 479 480 if (m <= 2) { 481 y -= 1; 482 m += 12; 483 } 484 a = floor(y / 100.0); 485 b = 2 - a + floor(a / 4.0); 486 jd = floor(365.25 * (y + 4716)) + 487 floor(30.6001 * (m + 1)) + 488 d + b - 1524; 489 if (jd < sg) { 490 jd -= b; 491 *ns = 0; 492 } 493 else 494 *ns = 1; 495 496 *rjd = (int)jd; 497} 498 499static void 500c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom) 501{ 502 double x, a, b, c, d, e, y, m, dom; 503 504 if (jd < sg) 505 a = jd; 506 else { 507 x = floor((jd - 1867216.25) / 36524.25); 508 a = jd + 1 + x - floor(x / 4.0); 509 } 510 b = a + 1524; 511 c = floor((b - 122.1) / 365.25); 512 d = floor(365.25 * c); 513 e = floor((b - d) / 30.6001); 514 dom = b - d - floor(30.6001 * e); 515 if (e <= 13) { 516 m = e - 1; 517 y = c - 4716; 518 } 519 else { 520 m = e - 13; 521 y = c - 4715; 522 } 523 524 *ry = (int)y; 525 *rm = (int)m; 526 *rdom = (int)dom; 527} 528 529static void 530c_ordinal_to_jd(int y, int d, double sg, int *rjd, int *ns) 531{ 532 int ns2; 533 534 c_find_fdoy(y, sg, rjd, &ns2); 535 *rjd += d - 1; 536 *ns = (*rjd < sg) ? 0 : 1; 537} 538 539static void 540c_jd_to_ordinal(int jd, double sg, int *ry, int *rd) 541{ 542 int rm2, rd2, rjd, ns; 543 544 c_jd_to_civil(jd, sg, ry, &rm2, &rd2); 545 c_find_fdoy(*ry, sg, &rjd, &ns); 546 *rd = (jd - rjd) + 1; 547} 548 549static void 550c_commercial_to_jd(int y, int w, int d, double sg, int *rjd, int *ns) 551{ 552 int rjd2, ns2; 553 554 c_find_fdoy(y, sg, &rjd2, &ns2); 555 rjd2 += 3; 556 *rjd = 557 (rjd2 - MOD((rjd2 - 1) + 1, 7)) + 558 7 * (w - 1) + 559 (d - 1); 560 *ns = (*rjd < sg) ? 0 : 1; 561} 562 563static void 564c_jd_to_commercial(int jd, double sg, int *ry, int *rw, int *rd) 565{ 566 int ry2, rm2, rd2, a, rjd2, ns2; 567 568 c_jd_to_civil(jd - 3, sg, &ry2, &rm2, &rd2); 569 a = ry2; 570 c_commercial_to_jd(a + 1, 1, 1, sg, &rjd2, &ns2); 571 if (jd >= rjd2) 572 *ry = a + 1; 573 else { 574 c_commercial_to_jd(a, 1, 1, sg, &rjd2, &ns2); 575 *ry = a; 576 } 577 *rw = 1 + DIV(jd - rjd2, 7); 578 *rd = MOD(jd + 1, 7); 579 if (*rd == 0) 580 *rd = 7; 581} 582 583static void 584c_weeknum_to_jd(int y, int w, int d, int f, double sg, int *rjd, int *ns) 585{ 586 int rjd2, ns2; 587 588 c_find_fdoy(y, sg, &rjd2, &ns2); 589 rjd2 += 6; 590 *rjd = (rjd2 - MOD(((rjd2 - f) + 1), 7) - 7) + 7 * w + d; 591 *ns = (*rjd < sg) ? 0 : 1; 592} 593 594static void 595c_jd_to_weeknum(int jd, int f, double sg, int *ry, int *rw, int *rd) 596{ 597 int rm, rd2, rjd, ns, j; 598 599 c_jd_to_civil(jd, sg, ry, &rm, &rd2); 600 c_find_fdoy(*ry, sg, &rjd, &ns); 601 rjd += 6; 602 j = jd - (rjd - MOD((rjd - f) + 1, 7)) + 7; 603 *rw = (int)DIV(j, 7); 604 *rd = (int)MOD(j, 7); 605} 606 607#ifndef NDEBUG 608static void 609c_nth_kday_to_jd(int y, int m, int n, int k, double sg, int *rjd, int *ns) 610{ 611 int rjd2, ns2; 612 613 if (n > 0) { 614 c_find_fdom(y, m, sg, &rjd2, &ns2); 615 rjd2 -= 1; 616 } 617 else { 618 c_find_ldom(y, m, sg, &rjd2, &ns2); 619 rjd2 += 7; 620 } 621 *rjd = (rjd2 - MOD((rjd2 - k) + 1, 7)) + 7 * n; 622 *ns = (*rjd < sg) ? 0 : 1; 623} 624#endif 625 626inline static int 627c_jd_to_wday(int jd) 628{ 629 return MOD(jd + 1, 7); 630} 631 632#ifndef NDEBUG 633static void 634c_jd_to_nth_kday(int jd, double sg, int *ry, int *rm, int *rn, int *rk) 635{ 636 int rd, rjd, ns2; 637 638 c_jd_to_civil(jd, sg, ry, rm, &rd); 639 c_find_fdom(*ry, *rm, sg, &rjd, &ns2); 640 *rn = DIV(jd - rjd, 7) + 1; 641 *rk = c_jd_to_wday(jd); 642} 643#endif 644 645static int 646c_valid_ordinal_p(int y, int d, double sg, 647 int *rd, int *rjd, int *ns) 648{ 649 int ry2, rd2; 650 651 if (d < 0) { 652 int rjd2, ns2; 653 654 if (!c_find_ldoy(y, sg, &rjd2, &ns2)) 655 return 0; 656 c_jd_to_ordinal(rjd2 + d + 1, sg, &ry2, &rd2); 657 if (ry2 != y) 658 return 0; 659 d = rd2; 660 } 661 c_ordinal_to_jd(y, d, sg, rjd, ns); 662 c_jd_to_ordinal(*rjd, sg, &ry2, &rd2); 663 if (ry2 != y || rd2 != d) 664 return 0; 665 return 1; 666} 667 668static const int monthtab[2][13] = { 669 { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 670 { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 671}; 672 673inline static int 674c_julian_leap_p(int y) 675{ 676 return MOD(y, 4) == 0; 677} 678 679inline static int 680c_gregorian_leap_p(int y) 681{ 682 return MOD(y, 4) == 0 && y % 100 != 0 || MOD(y, 400) == 0; 683} 684 685static int 686c_julian_last_day_of_month(int y, int m) 687{ 688 assert(m >= 1 && m <= 12); 689 return monthtab[c_julian_leap_p(y) ? 1 : 0][m]; 690} 691 692static int 693c_gregorian_last_day_of_month(int y, int m) 694{ 695 assert(m >= 1 && m <= 12); 696 return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m]; 697} 698 699static int 700c_valid_julian_p(int y, int m, int d, int *rm, int *rd) 701{ 702 int last; 703 704 if (m < 0) 705 m += 13; 706 if (m < 1 || m > 12) 707 return 0; 708 last = c_julian_last_day_of_month(y, m); 709 if (d < 0) 710 d = last + d + 1; 711 if (d < 1 || d > last) 712 return 0; 713 *rm = m; 714 *rd = d; 715 return 1; 716} 717 718static int 719c_valid_gregorian_p(int y, int m, int d, int *rm, int *rd) 720{ 721 int last; 722 723 if (m < 0) 724 m += 13; 725 if (m < 1 || m > 12) 726 return 0; 727 last = c_gregorian_last_day_of_month(y, m); 728 if (d < 0) 729 d = last + d + 1; 730 if (d < 1 || d > last) 731 return 0; 732 *rm = m; 733 *rd = d; 734 return 1; 735} 736 737static int 738c_valid_civil_p(int y, int m, int d, double sg, 739 int *rm, int *rd, int *rjd, int *ns) 740{ 741 int ry; 742 743 if (m < 0) 744 m += 13; 745 if (d < 0) { 746 if (!c_find_ldom(y, m, sg, rjd, ns)) 747 return 0; 748 c_jd_to_civil(*rjd + d + 1, sg, &ry, rm, rd); 749 if (ry != y || *rm != m) 750 return 0; 751 d = *rd; 752 } 753 c_civil_to_jd(y, m, d, sg, rjd, ns); 754 c_jd_to_civil(*rjd, sg, &ry, rm, rd); 755 if (ry != y || *rm != m || *rd != d) 756 return 0; 757 return 1; 758} 759 760static int 761c_valid_commercial_p(int y, int w, int d, double sg, 762 int *rw, int *rd, int *rjd, int *ns) 763{ 764 int ns2, ry2, rw2, rd2; 765 766 if (d < 0) 767 d += 8; 768 if (w < 0) { 769 int rjd2; 770 771 c_commercial_to_jd(y + 1, 1, 1, sg, &rjd2, &ns2); 772 c_jd_to_commercial(rjd2 + w * 7, sg, &ry2, &rw2, &rd2); 773 if (ry2 != y) 774 return 0; 775 w = rw2; 776 } 777 c_commercial_to_jd(y, w, d, sg, rjd, ns); 778 c_jd_to_commercial(*rjd, sg, &ry2, rw, rd); 779 if (y != ry2 || w != *rw || d != *rd) 780 return 0; 781 return 1; 782} 783 784static int 785c_valid_weeknum_p(int y, int w, int d, int f, double sg, 786 int *rw, int *rd, int *rjd, int *ns) 787{ 788 int ns2, ry2, rw2, rd2; 789 790 if (d < 0) 791 d += 7; 792 if (w < 0) { 793 int rjd2; 794 795 c_weeknum_to_jd(y + 1, 1, f, f, sg, &rjd2, &ns2); 796 c_jd_to_weeknum(rjd2 + w * 7, f, sg, &ry2, &rw2, &rd2); 797 if (ry2 != y) 798 return 0; 799 w = rw2; 800 } 801 c_weeknum_to_jd(y, w, d, f, sg, rjd, ns); 802 c_jd_to_weeknum(*rjd, f, sg, &ry2, rw, rd); 803 if (y != ry2 || w != *rw || d != *rd) 804 return 0; 805 return 1; 806} 807 808#ifndef NDEBUG 809static int 810c_valid_nth_kday_p(int y, int m, int n, int k, double sg, 811 int *rm, int *rn, int *rk, int *rjd, int *ns) 812{ 813 int ns2, ry2, rm2, rn2, rk2; 814 815 if (k < 0) 816 k += 7; 817 if (n < 0) { 818 int t, ny, nm, rjd2; 819 820 t = y * 12 + m; 821 ny = DIV(t, 12); 822 nm = MOD(t, 12) + 1; 823 824 c_nth_kday_to_jd(ny, nm, 1, k, sg, &rjd2, &ns2); 825 c_jd_to_nth_kday(rjd2 + n * 7, sg, &ry2, &rm2, &rn2, &rk2); 826 if (ry2 != y || rm2 != m) 827 return 0; 828 n = rn2; 829 } 830 c_nth_kday_to_jd(y, m, n, k, sg, rjd, ns); 831 c_jd_to_nth_kday(*rjd, sg, &ry2, rm, rn, rk); 832 if (y != ry2 || m != *rm || n != *rn || k != *rk) 833 return 0; 834 return 1; 835} 836#endif 837 838static int 839c_valid_time_p(int h, int min, int s, int *rh, int *rmin, int *rs) 840{ 841 if (h < 0) 842 h += 24; 843 if (min < 0) 844 min += 60; 845 if (s < 0) 846 s += 60; 847 *rh = h; 848 *rmin = min; 849 *rs = s; 850 return !(h < 0 || h > 24 || 851 min < 0 || min > 59 || 852 s < 0 || s > 59 || 853 (h == 24 && (min > 0 || s > 0))); 854} 855 856inline static int 857c_valid_start_p(double sg) 858{ 859 if (isnan(sg)) 860 return 0; 861 if (isinf(sg)) 862 return 1; 863 if (sg < REFORM_BEGIN_JD || sg > REFORM_END_JD) 864 return 0; 865 return 1; 866} 867 868inline static int 869df_local_to_utc(int df, int of) 870{ 871 df -= of; 872 if (df < 0) 873 df += DAY_IN_SECONDS; 874 else if (df >= DAY_IN_SECONDS) 875 df -= DAY_IN_SECONDS; 876 return df; 877} 878 879inline static int 880df_utc_to_local(int df, int of) 881{ 882 df += of; 883 if (df < 0) 884 df += DAY_IN_SECONDS; 885 else if (df >= DAY_IN_SECONDS) 886 df -= DAY_IN_SECONDS; 887 return df; 888} 889 890inline static int 891jd_local_to_utc(int jd, int df, int of) 892{ 893 df -= of; 894 if (df < 0) 895 jd -= 1; 896 else if (df >= DAY_IN_SECONDS) 897 jd += 1; 898 return jd; 899} 900 901inline static int 902jd_utc_to_local(int jd, int df, int of) 903{ 904 df += of; 905 if (df < 0) 906 jd -= 1; 907 else if (df >= DAY_IN_SECONDS) 908 jd += 1; 909 return jd; 910} 911 912inline static int 913time_to_df(int h, int min, int s) 914{ 915 return h * HOUR_IN_SECONDS + min * MINUTE_IN_SECONDS + s; 916} 917 918inline static void 919df_to_time(int df, int *h, int *min, int *s) 920{ 921 *h = df / HOUR_IN_SECONDS; 922 df %= HOUR_IN_SECONDS; 923 *min = df / MINUTE_IN_SECONDS; 924 *s = df % MINUTE_IN_SECONDS; 925} 926 927static VALUE 928sec_to_day(VALUE s) 929{ 930 if (FIXNUM_P(s)) 931 return rb_rational_new2(s, INT2FIX(DAY_IN_SECONDS)); 932 return f_quo(s, INT2FIX(DAY_IN_SECONDS)); 933} 934 935inline static VALUE 936isec_to_day(int s) 937{ 938 return sec_to_day(INT2FIX(s)); 939} 940 941static VALUE 942ns_to_day(VALUE n) 943{ 944 if (FIXNUM_P(n)) 945 return rb_rational_new2(n, day_in_nanoseconds); 946 return f_quo(n, day_in_nanoseconds); 947} 948 949#ifndef NDEBUG 950static VALUE 951ms_to_sec(VALUE m) 952{ 953 if (FIXNUM_P(m)) 954 return rb_rational_new2(m, INT2FIX(SECOND_IN_MILLISECONDS)); 955 return f_quo(m, INT2FIX(SECOND_IN_MILLISECONDS)); 956} 957#endif 958 959static VALUE 960ns_to_sec(VALUE n) 961{ 962 if (FIXNUM_P(n)) 963 return rb_rational_new2(n, INT2FIX(SECOND_IN_NANOSECONDS)); 964 return f_quo(n, INT2FIX(SECOND_IN_NANOSECONDS)); 965} 966 967#ifndef NDEBUG 968inline static VALUE 969ins_to_day(int n) 970{ 971 return ns_to_day(INT2FIX(n)); 972} 973#endif 974 975static int 976safe_mul_p(VALUE x, long m) 977{ 978 long ix; 979 980 if (!FIXNUM_P(x)) 981 return 0; 982 ix = FIX2LONG(x); 983 if (ix < 0) { 984 if (ix <= (FIXNUM_MIN / m)) 985 return 0; 986 } 987 else { 988 if (ix >= (FIXNUM_MAX / m)) 989 return 0; 990 } 991 return 1; 992} 993 994static VALUE 995day_to_sec(VALUE d) 996{ 997 if (safe_mul_p(d, DAY_IN_SECONDS)) 998 return LONG2FIX(FIX2LONG(d) * DAY_IN_SECONDS); 999 return f_mul(d, INT2FIX(DAY_IN_SECONDS)); 1000} 1001 1002#ifndef NDEBUG 1003static VALUE 1004day_to_ns(VALUE d) 1005{ 1006 return f_mul(d, day_in_nanoseconds); 1007} 1008#endif 1009 1010static VALUE 1011sec_to_ms(VALUE s) 1012{ 1013 if (safe_mul_p(s, SECOND_IN_MILLISECONDS)) 1014 return LONG2FIX(FIX2LONG(s) * SECOND_IN_MILLISECONDS); 1015 return f_mul(s, INT2FIX(SECOND_IN_MILLISECONDS)); 1016} 1017 1018static VALUE 1019sec_to_ns(VALUE s) 1020{ 1021 if (safe_mul_p(s, SECOND_IN_NANOSECONDS)) 1022 return LONG2FIX(FIX2LONG(s) * SECOND_IN_NANOSECONDS); 1023 return f_mul(s, INT2FIX(SECOND_IN_NANOSECONDS)); 1024} 1025 1026#ifndef NDEBUG 1027static VALUE 1028isec_to_ns(int s) 1029{ 1030 return sec_to_ns(INT2FIX(s)); 1031} 1032#endif 1033 1034static VALUE 1035div_day(VALUE d, VALUE *f) 1036{ 1037 if (f) 1038 *f = f_mod(d, INT2FIX(1)); 1039 return f_floor(d); 1040} 1041 1042static VALUE 1043div_df(VALUE d, VALUE *f) 1044{ 1045 VALUE s = day_to_sec(d); 1046 1047 if (f) 1048 *f = f_mod(s, INT2FIX(1)); 1049 return f_floor(s); 1050} 1051 1052#ifndef NDEBUG 1053static VALUE 1054div_sf(VALUE s, VALUE *f) 1055{ 1056 VALUE n = sec_to_ns(s); 1057 1058 if (f) 1059 *f = f_mod(n, INT2FIX(1)); 1060 return f_floor(n); 1061} 1062#endif 1063 1064static void 1065decode_day(VALUE d, VALUE *jd, VALUE *df, VALUE *sf) 1066{ 1067 VALUE f; 1068 1069 *jd = div_day(d, &f); 1070 *df = div_df(f, &f); 1071 *sf = sec_to_ns(f); 1072} 1073 1074inline static double 1075s_virtual_sg(union DateData *x) 1076{ 1077 if (isinf(x->s.sg)) 1078 return x->s.sg; 1079 if (f_zero_p(x->s.nth)) 1080 return x->s.sg; 1081 else if (f_negative_p(x->s.nth)) 1082 return positive_inf; 1083 return negative_inf; 1084} 1085 1086inline static double 1087c_virtual_sg(union DateData *x) 1088{ 1089 if (isinf(x->c.sg)) 1090 return x->c.sg; 1091 if (f_zero_p(x->c.nth)) 1092 return x->c.sg; 1093 else if (f_negative_p(x->c.nth)) 1094 return positive_inf; 1095 return negative_inf; 1096} 1097 1098inline static double 1099m_virtual_sg(union DateData *x) 1100{ 1101 if (simple_dat_p(x)) 1102 return s_virtual_sg(x); 1103 else 1104 return c_virtual_sg(x); 1105} 1106 1107#define canonicalize_jd(_nth, _jd) \ 1108{\ 1109 if (_jd < 0) {\ 1110 _nth = f_sub(_nth, INT2FIX(1));\ 1111 _jd += CM_PERIOD;\ 1112 }\ 1113 if (_jd >= CM_PERIOD) {\ 1114 _nth = f_add(_nth, INT2FIX(1));\ 1115 _jd -= CM_PERIOD;\ 1116 }\ 1117} 1118 1119inline static void 1120canonicalize_s_jd(union DateData *x) 1121{ 1122 int j = x->s.jd; 1123 assert(have_jd_p(x)); 1124 canonicalize_jd(x->s.nth, x->s.jd); 1125 if (x->s.jd != j) 1126 x->flags &= ~HAVE_CIVIL; 1127} 1128 1129inline static void 1130get_s_jd(union DateData *x) 1131{ 1132 assert(simple_dat_p(x)); 1133 if (!have_jd_p(x)) { 1134 int jd, ns; 1135 1136 assert(have_civil_p(x)); 1137#ifndef USE_PACK 1138 c_civil_to_jd(x->s.year, x->s.mon, x->s.mday, 1139 s_virtual_sg(x), &jd, &ns); 1140#else 1141 c_civil_to_jd(x->s.year, EX_MON(x->s.pc), EX_MDAY(x->s.pc), 1142 s_virtual_sg(x), &jd, &ns); 1143#endif 1144 x->s.jd = jd; 1145 x->s.flags |= HAVE_JD; 1146 } 1147} 1148 1149inline static void 1150get_s_civil(union DateData *x) 1151{ 1152 assert(simple_dat_p(x)); 1153 if (!have_civil_p(x)) { 1154 int y, m, d; 1155 1156 assert(have_jd_p(x)); 1157 c_jd_to_civil(x->s.jd, s_virtual_sg(x), &y, &m, &d); 1158 x->s.year = y; 1159#ifndef USE_PACK 1160 x->s.mon = m; 1161 x->s.mday = d; 1162#else 1163 x->s.pc = PACK2(m, d); 1164#endif 1165 x->s.flags |= HAVE_CIVIL; 1166 } 1167} 1168 1169inline static void 1170get_c_df(union DateData *x) 1171{ 1172 assert(complex_dat_p(x)); 1173 if (!have_df_p(x)) { 1174 assert(have_time_p(x)); 1175#ifndef USE_PACK 1176 x->c.df = df_local_to_utc(time_to_df(x->c.hour, x->c.min, x->c.sec), 1177 x->c.of); 1178#else 1179 x->c.df = df_local_to_utc(time_to_df(EX_HOUR(x->c.pc), 1180 EX_MIN(x->c.pc), 1181 EX_SEC(x->c.pc)), 1182 x->c.of); 1183#endif 1184 x->c.flags |= HAVE_DF; 1185 } 1186} 1187 1188inline static void 1189get_c_time(union DateData *x) 1190{ 1191 assert(complex_dat_p(x)); 1192 if (!have_time_p(x)) { 1193#ifndef USE_PACK 1194 int r; 1195 assert(have_df_p(x)); 1196 r = df_utc_to_local(x->c.df, x->c.of); 1197 df_to_time(r, &x->c.hour, &x->c.min, &x->c.sec); 1198 x->c.flags |= HAVE_TIME; 1199#else 1200 int r, m, d, h, min, s; 1201 1202 assert(have_df_p(x)); 1203 m = EX_MON(x->c.pc); 1204 d = EX_MDAY(x->c.pc); 1205 r = df_utc_to_local(x->c.df, x->c.of); 1206 df_to_time(r, &h, &min, &s); 1207 x->c.pc = PACK5(m, d, h, min, s); 1208 x->c.flags |= HAVE_TIME; 1209#endif 1210 } 1211} 1212 1213inline static void 1214canonicalize_c_jd(union DateData *x) 1215{ 1216 int j = x->c.jd; 1217 assert(have_jd_p(x)); 1218 canonicalize_jd(x->c.nth, x->c.jd); 1219 if (x->c.jd != j) 1220 x->flags &= ~HAVE_CIVIL; 1221} 1222 1223inline static void 1224get_c_jd(union DateData *x) 1225{ 1226 assert(complex_dat_p(x)); 1227 if (!have_jd_p(x)) { 1228 int jd, ns; 1229 1230 assert(have_civil_p(x)); 1231#ifndef USE_PACK 1232 c_civil_to_jd(x->c.year, x->c.mon, x->c.mday, 1233 c_virtual_sg(x), &jd, &ns); 1234#else 1235 c_civil_to_jd(x->c.year, EX_MON(x->c.pc), EX_MDAY(x->c.pc), 1236 c_virtual_sg(x), &jd, &ns); 1237#endif 1238 1239 get_c_time(x); 1240#ifndef USE_PACK 1241 x->c.jd = jd_local_to_utc(jd, 1242 time_to_df(x->c.hour, x->c.min, x->c.sec), 1243 x->c.of); 1244#else 1245 x->c.jd = jd_local_to_utc(jd, 1246 time_to_df(EX_HOUR(x->c.pc), 1247 EX_MIN(x->c.pc), 1248 EX_SEC(x->c.pc)), 1249 x->c.of); 1250#endif 1251 x->c.flags |= HAVE_JD; 1252 } 1253} 1254 1255inline static void 1256get_c_civil(union DateData *x) 1257{ 1258 assert(complex_dat_p(x)); 1259 if (!have_civil_p(x)) { 1260#ifndef USE_PACK 1261 int jd, y, m, d; 1262#else 1263 int jd, y, m, d, h, min, s; 1264#endif 1265 1266 assert(have_jd_p(x)); 1267 get_c_df(x); 1268 jd = jd_utc_to_local(x->c.jd, x->c.df, x->c.of); 1269 c_jd_to_civil(jd, c_virtual_sg(x), &y, &m, &d); 1270 x->c.year = y; 1271#ifndef USE_PACK 1272 x->c.mon = m; 1273 x->c.mday = d; 1274#else 1275 h = EX_HOUR(x->c.pc); 1276 min = EX_MIN(x->c.pc); 1277 s = EX_SEC(x->c.pc); 1278 x->c.pc = PACK5(m, d, h, min, s); 1279#endif 1280 x->c.flags |= HAVE_CIVIL; 1281 } 1282} 1283 1284inline static int 1285local_jd(union DateData *x) 1286{ 1287 assert(complex_dat_p(x)); 1288 assert(have_jd_p(x)); 1289 assert(have_df_p(x)); 1290 return jd_utc_to_local(x->c.jd, x->c.df, x->c.of); 1291} 1292 1293inline static int 1294local_df(union DateData *x) 1295{ 1296 assert(complex_dat_p(x)); 1297 assert(have_df_p(x)); 1298 return df_utc_to_local(x->c.df, x->c.of); 1299} 1300 1301static void 1302decode_year(VALUE y, double style, 1303 VALUE *nth, int *ry) 1304{ 1305 int period; 1306 VALUE t; 1307 1308 period = (style < 0) ? 1309 CM_PERIOD_GCY : 1310 CM_PERIOD_JCY; 1311 if (FIXNUM_P(y)) { 1312 long iy, it, inth; 1313 1314 iy = FIX2LONG(y); 1315 if (iy >= (FIXNUM_MAX - 4712)) 1316 goto big; 1317 it = iy + 4712; /* shift */ 1318 inth = DIV(it, ((long)period)); 1319 *nth = LONG2FIX(inth); 1320 if (inth) 1321 it = MOD(it, ((long)period)); 1322 *ry = (int)it - 4712; /* unshift */ 1323 return; 1324 } 1325 big: 1326 t = f_add(y, INT2FIX(4712)); /* shift */ 1327 *nth = f_idiv(t, INT2FIX(period)); 1328 if (f_nonzero_p(*nth)) 1329 t = f_mod(t, INT2FIX(period)); 1330 *ry = FIX2INT(t) - 4712; /* unshift */ 1331} 1332 1333static void 1334encode_year(VALUE nth, int y, double style, 1335 VALUE *ry) 1336{ 1337 int period; 1338 VALUE t; 1339 1340 period = (style < 0) ? 1341 CM_PERIOD_GCY : 1342 CM_PERIOD_JCY; 1343 if (f_zero_p(nth)) 1344 *ry = INT2FIX(y); 1345 else { 1346 t = f_mul(INT2FIX(period), nth); 1347 t = f_add(t, INT2FIX(y)); 1348 *ry = t; 1349 } 1350} 1351 1352static void 1353decode_jd(VALUE jd, VALUE *nth, int *rjd) 1354{ 1355 assert(FIXNUM_P(jd) || RB_TYPE_P(jd, T_BIGNUM)); 1356 *nth = f_idiv(jd, INT2FIX(CM_PERIOD)); 1357 if (f_zero_p(*nth)) { 1358 assert(FIXNUM_P(jd)); 1359 *rjd = FIX2INT(jd); 1360 return; 1361 } 1362 *rjd = FIX2INT(f_mod(jd, INT2FIX(CM_PERIOD))); 1363} 1364 1365static void 1366encode_jd(VALUE nth, int jd, VALUE *rjd) 1367{ 1368 if (f_zero_p(nth)) { 1369 *rjd = INT2FIX(jd); 1370 return; 1371 } 1372 *rjd = f_add(f_mul(INT2FIX(CM_PERIOD), nth), INT2FIX(jd)); 1373} 1374 1375inline static double 1376guess_style(VALUE y, double sg) /* -/+oo or zero */ 1377{ 1378 double style = 0; 1379 1380 if (isinf(sg)) 1381 style = sg; 1382 else if (!FIXNUM_P(y)) 1383 style = f_positive_p(y) ? negative_inf : positive_inf; 1384 else { 1385 long iy = FIX2LONG(y); 1386 1387 assert(FIXNUM_P(y)); 1388 if (iy < REFORM_BEGIN_YEAR) 1389 style = positive_inf; 1390 else if (iy > REFORM_END_YEAR) 1391 style = negative_inf; 1392 } 1393 return style; 1394} 1395 1396inline static void 1397m_canonicalize_jd(union DateData *x) 1398{ 1399 if (simple_dat_p(x)) { 1400 get_s_jd(x); 1401 canonicalize_s_jd(x); 1402 } 1403 else { 1404 get_c_jd(x); 1405 canonicalize_c_jd(x); 1406 } 1407} 1408 1409inline static VALUE 1410m_nth(union DateData *x) 1411{ 1412 if (simple_dat_p(x)) 1413 return x->s.nth; 1414 else { 1415 get_c_civil(x); 1416 return x->c.nth; 1417 } 1418} 1419 1420inline static int 1421m_jd(union DateData *x) 1422{ 1423 if (simple_dat_p(x)) { 1424 get_s_jd(x); 1425 return x->s.jd; 1426 } 1427 else { 1428 get_c_jd(x); 1429 return x->c.jd; 1430 } 1431} 1432 1433static VALUE 1434m_real_jd(union DateData *x) 1435{ 1436 VALUE nth, rjd; 1437 int jd; 1438 1439 nth = m_nth(x); 1440 jd = m_jd(x); 1441 1442 encode_jd(nth, jd, &rjd); 1443 return rjd; 1444} 1445 1446static int 1447m_local_jd(union DateData *x) 1448{ 1449 if (simple_dat_p(x)) { 1450 get_s_jd(x); 1451 return x->s.jd; 1452 } 1453 else { 1454 get_c_jd(x); 1455 get_c_df(x); 1456 return local_jd(x); 1457 } 1458} 1459 1460static VALUE 1461m_real_local_jd(union DateData *x) 1462{ 1463 VALUE nth, rjd; 1464 int jd; 1465 1466 nth = m_nth(x); 1467 jd = m_local_jd(x); 1468 1469 encode_jd(nth, jd, &rjd); 1470 return rjd; 1471} 1472 1473inline static int 1474m_df(union DateData *x) 1475{ 1476 if (simple_dat_p(x)) 1477 return 0; 1478 else { 1479 get_c_df(x); 1480 return x->c.df; 1481 } 1482} 1483 1484#ifndef NDEBUG 1485static VALUE 1486m_df_in_day(union DateData *x) 1487{ 1488 return isec_to_day(m_df(x)); 1489} 1490#endif 1491 1492static int 1493m_local_df(union DateData *x) 1494{ 1495 if (simple_dat_p(x)) 1496 return 0; 1497 else { 1498 get_c_df(x); 1499 return local_df(x); 1500 } 1501} 1502 1503#ifndef NDEBUG 1504static VALUE 1505m_local_df_in_day(union DateData *x) 1506{ 1507 return isec_to_day(m_local_df(x)); 1508} 1509#endif 1510 1511inline static VALUE 1512m_sf(union DateData *x) 1513{ 1514 if (simple_dat_p(x)) 1515 return INT2FIX(0); 1516 else 1517 return x->c.sf; 1518} 1519 1520#ifndef NDEBUG 1521static VALUE 1522m_sf_in_day(union DateData *x) 1523{ 1524 return ns_to_day(m_sf(x)); 1525} 1526#endif 1527 1528static VALUE 1529m_sf_in_sec(union DateData *x) 1530{ 1531 return ns_to_sec(m_sf(x)); 1532} 1533 1534static VALUE 1535m_fr(union DateData *x) 1536{ 1537 if (simple_dat_p(x)) 1538 return INT2FIX(0); 1539 else { 1540 int df; 1541 VALUE sf, fr; 1542 1543 df = m_local_df(x); 1544 sf = m_sf(x); 1545 fr = isec_to_day(df); 1546 if (f_nonzero_p(sf)) 1547 fr = f_add(fr, ns_to_day(sf)); 1548 return fr; 1549 } 1550} 1551 1552#define HALF_DAYS_IN_SECONDS (DAY_IN_SECONDS / 2) 1553 1554static VALUE 1555m_ajd(union DateData *x) 1556{ 1557 VALUE r, sf; 1558 int df; 1559 1560 if (simple_dat_p(x)) { 1561 r = m_real_jd(x); 1562 if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2)) { 1563 long ir = FIX2LONG(r); 1564 ir = ir * 2 - 1; 1565 return rb_rational_new2(LONG2FIX(ir), INT2FIX(2)); 1566 } 1567 else 1568 return rb_rational_new2(f_sub(f_mul(r, 1569 INT2FIX(2)), 1570 INT2FIX(1)), 1571 INT2FIX(2)); 1572 } 1573 1574 r = m_real_jd(x); 1575 df = m_df(x); 1576 df -= HALF_DAYS_IN_SECONDS; 1577 if (df) 1578 r = f_add(r, isec_to_day(df)); 1579 sf = m_sf(x); 1580 if (f_nonzero_p(sf)) 1581 r = f_add(r, ns_to_day(sf)); 1582 1583 return r; 1584} 1585 1586static VALUE 1587m_amjd(union DateData *x) 1588{ 1589 VALUE r, sf; 1590 int df; 1591 1592 r = m_real_jd(x); 1593 if (FIXNUM_P(r) && FIX2LONG(r) >= (FIXNUM_MIN + 2400001)) { 1594 long ir = FIX2LONG(r); 1595 ir -= 2400001; 1596 r = rb_rational_new1(LONG2FIX(ir)); 1597 } 1598 else 1599 r = rb_rational_new1(f_sub(m_real_jd(x), 1600 INT2FIX(2400001))); 1601 1602 if (simple_dat_p(x)) 1603 return r; 1604 1605 df = m_df(x); 1606 if (df) 1607 r = f_add(r, isec_to_day(df)); 1608 sf = m_sf(x); 1609 if (f_nonzero_p(sf)) 1610 r = f_add(r, ns_to_day(sf)); 1611 1612 return r; 1613} 1614 1615inline static int 1616m_of(union DateData *x) 1617{ 1618 if (simple_dat_p(x)) 1619 return 0; 1620 else { 1621 get_c_jd(x); 1622 return x->c.of; 1623 } 1624} 1625 1626static VALUE 1627m_of_in_day(union DateData *x) 1628{ 1629 return isec_to_day(m_of(x)); 1630} 1631 1632inline static double 1633m_sg(union DateData *x) 1634{ 1635 if (simple_dat_p(x)) 1636 return x->s.sg; 1637 else { 1638 get_c_jd(x); 1639 return x->c.sg; 1640 } 1641} 1642 1643static int 1644m_julian_p(union DateData *x) 1645{ 1646 int jd; 1647 double sg; 1648 1649 if (simple_dat_p(x)) { 1650 get_s_jd(x); 1651 jd = x->s.jd; 1652 sg = s_virtual_sg(x); 1653 } 1654 else { 1655 get_c_jd(x); 1656 jd = x->c.jd; 1657 sg = c_virtual_sg(x); 1658 } 1659 if (isinf(sg)) 1660 return sg == positive_inf; 1661 return jd < sg; 1662} 1663 1664inline static int 1665m_gregorian_p(union DateData *x) 1666{ 1667 return !m_julian_p(x); 1668} 1669 1670inline static int 1671m_proleptic_julian_p(union DateData *x) 1672{ 1673 double sg; 1674 1675 sg = m_sg(x); 1676 if (isinf(sg) && sg > 0) 1677 return 1; 1678 return 0; 1679} 1680 1681inline static int 1682m_proleptic_gregorian_p(union DateData *x) 1683{ 1684 double sg; 1685 1686 sg = m_sg(x); 1687 if (isinf(sg) && sg < 0) 1688 return 1; 1689 return 0; 1690} 1691 1692inline static int 1693m_year(union DateData *x) 1694{ 1695 if (simple_dat_p(x)) { 1696 get_s_civil(x); 1697 return x->s.year; 1698 } 1699 else { 1700 get_c_civil(x); 1701 return x->c.year; 1702 } 1703} 1704 1705static VALUE 1706m_real_year(union DateData *x) 1707{ 1708 VALUE nth, ry; 1709 int year; 1710 1711 nth = m_nth(x); 1712 year = m_year(x); 1713 1714 if (f_zero_p(nth)) 1715 return INT2FIX(year); 1716 1717 encode_year(nth, year, 1718 m_gregorian_p(x) ? -1 : +1, 1719 &ry); 1720 return ry; 1721} 1722 1723 1724#ifdef USE_PACK 1725inline static int 1726m_pc(union DateData *x) 1727{ 1728 if (simple_dat_p(x)) { 1729 get_s_civil(x); 1730 return x->s.pc; 1731 } 1732 else { 1733 get_c_civil(x); 1734 get_c_time(x); 1735 return x->c.pc; 1736 } 1737} 1738#endif 1739 1740inline static int 1741m_mon(union DateData *x) 1742{ 1743 if (simple_dat_p(x)) { 1744 get_s_civil(x); 1745#ifndef USE_PACK 1746 return x->s.mon; 1747#else 1748 return EX_MON(x->s.pc); 1749#endif 1750 } 1751 else { 1752 get_c_civil(x); 1753#ifndef USE_PACK 1754 return x->c.mon; 1755#else 1756 return EX_MON(x->c.pc); 1757#endif 1758 } 1759} 1760 1761inline static int 1762m_mday(union DateData *x) 1763{ 1764 if (simple_dat_p(x)) { 1765 get_s_civil(x); 1766#ifndef USE_PACK 1767 return x->s.mday; 1768#else 1769 return EX_MDAY(x->s.pc); 1770#endif 1771 } 1772 else { 1773 get_c_civil(x); 1774#ifndef USE_PACK 1775 return x->c.mday; 1776#else 1777 return EX_MDAY(x->c.pc); 1778#endif 1779 } 1780} 1781 1782static const int yeartab[2][13] = { 1783 { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, 1784 { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } 1785}; 1786 1787static int 1788c_julian_to_yday(int y, int m, int d) 1789{ 1790 assert(m >= 1 && m <= 12); 1791 return yeartab[c_julian_leap_p(y) ? 1 : 0][m] + d; 1792} 1793 1794static int 1795c_gregorian_to_yday(int y, int m, int d) 1796{ 1797 assert(m >= 1 && m <= 12); 1798 return yeartab[c_gregorian_leap_p(y) ? 1 : 0][m] + d; 1799} 1800 1801static int 1802m_yday(union DateData *x) 1803{ 1804 int jd, ry, rd; 1805 double sg; 1806 1807 jd = m_local_jd(x); 1808 sg = m_virtual_sg(x); /* !=m_sg() */ 1809 1810 if (m_proleptic_gregorian_p(x) || 1811 (jd - sg) > 366) 1812 return c_gregorian_to_yday(m_year(x), m_mon(x), m_mday(x)); 1813 if (m_proleptic_julian_p(x)) 1814 return c_julian_to_yday(m_year(x), m_mon(x), m_mday(x)); 1815 c_jd_to_ordinal(jd, sg, &ry, &rd); 1816 return rd; 1817} 1818 1819static int 1820m_wday(union DateData *x) 1821{ 1822 return c_jd_to_wday(m_local_jd(x)); 1823} 1824 1825static int 1826m_cwyear(union DateData *x) 1827{ 1828 int ry, rw, rd; 1829 1830 c_jd_to_commercial(m_local_jd(x), m_virtual_sg(x), /* !=m_sg() */ 1831 &ry, &rw, &rd); 1832 return ry; 1833} 1834 1835static VALUE 1836m_real_cwyear(union DateData *x) 1837{ 1838 VALUE nth, ry; 1839 int year; 1840 1841 nth = m_nth(x); 1842 year = m_cwyear(x); 1843 1844 if (f_zero_p(nth)) 1845 return INT2FIX(year); 1846 1847 encode_year(nth, year, 1848 m_gregorian_p(x) ? -1 : +1, 1849 &ry); 1850 return ry; 1851} 1852 1853static int 1854m_cweek(union DateData *x) 1855{ 1856 int ry, rw, rd; 1857 1858 c_jd_to_commercial(m_local_jd(x), m_virtual_sg(x), /* !=m_sg() */ 1859 &ry, &rw, &rd); 1860 return rw; 1861} 1862 1863static int 1864m_cwday(union DateData *x) 1865{ 1866 int w; 1867 1868 w = m_wday(x); 1869 if (w == 0) 1870 w = 7; 1871 return w; 1872} 1873 1874static int 1875m_wnumx(union DateData *x, int f) 1876{ 1877 int ry, rw, rd; 1878 1879 c_jd_to_weeknum(m_local_jd(x), f, m_virtual_sg(x), /* !=m_sg() */ 1880 &ry, &rw, &rd); 1881 return rw; 1882} 1883 1884static int 1885m_wnum0(union DateData *x) 1886{ 1887 return m_wnumx(x, 0); 1888} 1889 1890static int 1891m_wnum1(union DateData *x) 1892{ 1893 return m_wnumx(x, 1); 1894} 1895 1896inline static int 1897m_hour(union DateData *x) 1898{ 1899 if (simple_dat_p(x)) 1900 return 0; 1901 else { 1902 get_c_time(x); 1903#ifndef USE_PACK 1904 return x->c.hour; 1905#else 1906 return EX_HOUR(x->c.pc); 1907#endif 1908 } 1909} 1910 1911inline static int 1912m_min(union DateData *x) 1913{ 1914 if (simple_dat_p(x)) 1915 return 0; 1916 else { 1917 get_c_time(x); 1918#ifndef USE_PACK 1919 return x->c.min; 1920#else 1921 return EX_MIN(x->c.pc); 1922#endif 1923 } 1924} 1925 1926inline static int 1927m_sec(union DateData *x) 1928{ 1929 if (simple_dat_p(x)) 1930 return 0; 1931 else { 1932 get_c_time(x); 1933#ifndef USE_PACK 1934 return x->c.sec; 1935#else 1936 return EX_SEC(x->c.pc); 1937#endif 1938 } 1939} 1940 1941#define decode_offset(of,s,h,m)\ 1942{\ 1943 int a;\ 1944 s = (of < 0) ? '-' : '+';\ 1945 a = (of < 0) ? -of : of;\ 1946 h = a / HOUR_IN_SECONDS;\ 1947 m = a % HOUR_IN_SECONDS / MINUTE_IN_SECONDS;\ 1948} 1949 1950static VALUE 1951of2str(int of) 1952{ 1953 int s, h, m; 1954 1955 decode_offset(of, s, h, m); 1956 return rb_enc_sprintf(rb_usascii_encoding(), "%c%02d:%02d", s, h, m); 1957} 1958 1959static VALUE 1960m_zone(union DateData *x) 1961{ 1962 if (simple_dat_p(x)) 1963 return rb_usascii_str_new2("+00:00"); 1964 return of2str(m_of(x)); 1965} 1966 1967inline static VALUE 1968f_kind_of_p(VALUE x, VALUE c) 1969{ 1970 return rb_obj_is_kind_of(x, c); 1971} 1972 1973inline static VALUE 1974k_date_p(VALUE x) 1975{ 1976 return f_kind_of_p(x, cDate); 1977} 1978 1979inline static VALUE 1980k_datetime_p(VALUE x) 1981{ 1982 return f_kind_of_p(x, cDateTime); 1983} 1984 1985inline static VALUE 1986k_numeric_p(VALUE x) 1987{ 1988 return f_kind_of_p(x, rb_cNumeric); 1989} 1990 1991inline static VALUE 1992k_rational_p(VALUE x) 1993{ 1994 return f_kind_of_p(x, rb_cRational); 1995} 1996 1997#ifndef NDEBUG 1998static void 1999civil_to_jd(VALUE y, int m, int d, double sg, 2000 VALUE *nth, int *ry, 2001 int *rjd, 2002 int *ns) 2003{ 2004 double style = guess_style(y, sg); 2005 2006 if (style == 0) { 2007 int jd; 2008 2009 c_civil_to_jd(FIX2INT(y), m, d, sg, &jd, ns); 2010 decode_jd(INT2FIX(jd), nth, rjd); 2011 if (f_zero_p(*nth)) 2012 *ry = FIX2INT(y); 2013 else { 2014 VALUE nth2; 2015 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2016 } 2017 } 2018 else { 2019 decode_year(y, style, nth, ry); 2020 c_civil_to_jd(*ry, m, d, style, rjd, ns); 2021 } 2022} 2023 2024static void 2025jd_to_civil(VALUE jd, double sg, 2026 VALUE *nth, int *rjd, 2027 int *ry, int *rm, int *rd) 2028{ 2029 decode_jd(jd, nth, rjd); 2030 c_jd_to_civil(*rjd, sg, ry, rm, rd); 2031} 2032 2033static void 2034ordinal_to_jd(VALUE y, int d, double sg, 2035 VALUE *nth, int *ry, 2036 int *rjd, 2037 int *ns) 2038{ 2039 double style = guess_style(y, sg); 2040 2041 if (style == 0) { 2042 int jd; 2043 2044 c_ordinal_to_jd(FIX2INT(y), d, sg, &jd, ns); 2045 decode_jd(INT2FIX(jd), nth, rjd); 2046 if (f_zero_p(*nth)) 2047 *ry = FIX2INT(y); 2048 else { 2049 VALUE nth2; 2050 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2051 } 2052 } 2053 else { 2054 decode_year(y, style, nth, ry); 2055 c_ordinal_to_jd(*ry, d, style, rjd, ns); 2056 } 2057} 2058 2059static void 2060jd_to_ordinal(VALUE jd, double sg, 2061 VALUE *nth, int *rjd, 2062 int *ry, int *rd) 2063{ 2064 decode_jd(jd, nth, rjd); 2065 c_jd_to_ordinal(*rjd, sg, ry, rd); 2066} 2067 2068static void 2069commercial_to_jd(VALUE y, int w, int d, double sg, 2070 VALUE *nth, int *ry, 2071 int *rjd, 2072 int *ns) 2073{ 2074 double style = guess_style(y, sg); 2075 2076 if (style == 0) { 2077 int jd; 2078 2079 c_commercial_to_jd(FIX2INT(y), w, d, sg, &jd, ns); 2080 decode_jd(INT2FIX(jd), nth, rjd); 2081 if (f_zero_p(*nth)) 2082 *ry = FIX2INT(y); 2083 else { 2084 VALUE nth2; 2085 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2086 } 2087 } 2088 else { 2089 decode_year(y, style, nth, ry); 2090 c_commercial_to_jd(*ry, w, d, style, rjd, ns); 2091 } 2092} 2093 2094static void 2095jd_to_commercial(VALUE jd, double sg, 2096 VALUE *nth, int *rjd, 2097 int *ry, int *rw, int *rd) 2098{ 2099 decode_jd(jd, nth, rjd); 2100 c_jd_to_commercial(*rjd, sg, ry, rw, rd); 2101} 2102 2103static void 2104weeknum_to_jd(VALUE y, int w, int d, int f, double sg, 2105 VALUE *nth, int *ry, 2106 int *rjd, 2107 int *ns) 2108{ 2109 double style = guess_style(y, sg); 2110 2111 if (style == 0) { 2112 int jd; 2113 2114 c_weeknum_to_jd(FIX2INT(y), w, d, f, sg, &jd, ns); 2115 decode_jd(INT2FIX(jd), nth, rjd); 2116 if (f_zero_p(*nth)) 2117 *ry = FIX2INT(y); 2118 else { 2119 VALUE nth2; 2120 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2121 } 2122 } 2123 else { 2124 decode_year(y, style, nth, ry); 2125 c_weeknum_to_jd(*ry, w, d, f, style, rjd, ns); 2126 } 2127} 2128 2129static void 2130jd_to_weeknum(VALUE jd, int f, double sg, 2131 VALUE *nth, int *rjd, 2132 int *ry, int *rw, int *rd) 2133{ 2134 decode_jd(jd, nth, rjd); 2135 c_jd_to_weeknum(*rjd, f, sg, ry, rw, rd); 2136} 2137 2138static void 2139nth_kday_to_jd(VALUE y, int m, int n, int k, double sg, 2140 VALUE *nth, int *ry, 2141 int *rjd, 2142 int *ns) 2143{ 2144 double style = guess_style(y, sg); 2145 2146 if (style == 0) { 2147 int jd; 2148 2149 c_nth_kday_to_jd(FIX2INT(y), m, n, k, sg, &jd, ns); 2150 decode_jd(INT2FIX(jd), nth, rjd); 2151 if (f_zero_p(*nth)) 2152 *ry = FIX2INT(y); 2153 else { 2154 VALUE nth2; 2155 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2156 } 2157 } 2158 else { 2159 decode_year(y, style, nth, ry); 2160 c_nth_kday_to_jd(*ry, m, n, k, style, rjd, ns); 2161 } 2162} 2163 2164static void 2165jd_to_nth_kday(VALUE jd, double sg, 2166 VALUE *nth, int *rjd, 2167 int *ry, int *rm, int *rn, int *rk) 2168{ 2169 decode_jd(jd, nth, rjd); 2170 c_jd_to_nth_kday(*rjd, sg, ry, rm, rn, rk); 2171} 2172#endif 2173 2174static int 2175valid_ordinal_p(VALUE y, int d, double sg, 2176 VALUE *nth, int *ry, 2177 int *rd, int *rjd, 2178 int *ns) 2179{ 2180 double style = guess_style(y, sg); 2181 int r; 2182 2183 if (style == 0) { 2184 int jd; 2185 2186 r = c_valid_ordinal_p(FIX2INT(y), d, sg, rd, &jd, ns); 2187 if (!r) 2188 return 0; 2189 decode_jd(INT2FIX(jd), nth, rjd); 2190 if (f_zero_p(*nth)) 2191 *ry = FIX2INT(y); 2192 else { 2193 VALUE nth2; 2194 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2195 } 2196 } 2197 else { 2198 decode_year(y, style, nth, ry); 2199 r = c_valid_ordinal_p(*ry, d, style, rd, rjd, ns); 2200 } 2201 return r; 2202} 2203 2204static int 2205valid_gregorian_p(VALUE y, int m, int d, 2206 VALUE *nth, int *ry, 2207 int *rm, int *rd) 2208{ 2209 decode_year(y, -1, nth, ry); 2210 return c_valid_gregorian_p(*ry, m, d, rm, rd); 2211} 2212 2213static int 2214valid_civil_p(VALUE y, int m, int d, double sg, 2215 VALUE *nth, int *ry, 2216 int *rm, int *rd, int *rjd, 2217 int *ns) 2218{ 2219 double style = guess_style(y, sg); 2220 int r; 2221 2222 if (style == 0) { 2223 int jd; 2224 2225 r = c_valid_civil_p(FIX2INT(y), m, d, sg, rm, rd, &jd, ns); 2226 if (!r) 2227 return 0; 2228 decode_jd(INT2FIX(jd), nth, rjd); 2229 if (f_zero_p(*nth)) 2230 *ry = FIX2INT(y); 2231 else { 2232 VALUE nth2; 2233 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2234 } 2235 } 2236 else { 2237 decode_year(y, style, nth, ry); 2238 if (style < 0) 2239 r = c_valid_gregorian_p(*ry, m, d, rm, rd); 2240 else 2241 r = c_valid_julian_p(*ry, m, d, rm, rd); 2242 if (!r) 2243 return 0; 2244 c_civil_to_jd(*ry, *rm, *rd, style, rjd, ns); 2245 } 2246 return r; 2247} 2248 2249static int 2250valid_commercial_p(VALUE y, int w, int d, double sg, 2251 VALUE *nth, int *ry, 2252 int *rw, int *rd, int *rjd, 2253 int *ns) 2254{ 2255 double style = guess_style(y, sg); 2256 int r; 2257 2258 if (style == 0) { 2259 int jd; 2260 2261 r = c_valid_commercial_p(FIX2INT(y), w, d, sg, rw, rd, &jd, ns); 2262 if (!r) 2263 return 0; 2264 decode_jd(INT2FIX(jd), nth, rjd); 2265 if (f_zero_p(*nth)) 2266 *ry = FIX2INT(y); 2267 else { 2268 VALUE nth2; 2269 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2270 } 2271 } 2272 else { 2273 decode_year(y, style, nth, ry); 2274 r = c_valid_commercial_p(*ry, w, d, style, rw, rd, rjd, ns); 2275 } 2276 return r; 2277} 2278 2279static int 2280valid_weeknum_p(VALUE y, int w, int d, int f, double sg, 2281 VALUE *nth, int *ry, 2282 int *rw, int *rd, int *rjd, 2283 int *ns) 2284{ 2285 double style = guess_style(y, sg); 2286 int r; 2287 2288 if (style == 0) { 2289 int jd; 2290 2291 r = c_valid_weeknum_p(FIX2INT(y), w, d, f, sg, rw, rd, &jd, ns); 2292 if (!r) 2293 return 0; 2294 decode_jd(INT2FIX(jd), nth, rjd); 2295 if (f_zero_p(*nth)) 2296 *ry = FIX2INT(y); 2297 else { 2298 VALUE nth2; 2299 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2300 } 2301 } 2302 else { 2303 decode_year(y, style, nth, ry); 2304 r = c_valid_weeknum_p(*ry, w, d, f, style, rw, rd, rjd, ns); 2305 } 2306 return r; 2307} 2308 2309#ifndef NDEBUG 2310static int 2311valid_nth_kday_p(VALUE y, int m, int n, int k, double sg, 2312 VALUE *nth, int *ry, 2313 int *rm, int *rn, int *rk, int *rjd, 2314 int *ns) 2315{ 2316 double style = guess_style(y, sg); 2317 int r; 2318 2319 if (style == 0) { 2320 int jd; 2321 2322 r = c_valid_nth_kday_p(FIX2INT(y), m, n, k, sg, rm, rn, rk, &jd, ns); 2323 if (!r) 2324 return 0; 2325 decode_jd(INT2FIX(jd), nth, rjd); 2326 if (f_zero_p(*nth)) 2327 *ry = FIX2INT(y); 2328 else { 2329 VALUE nth2; 2330 decode_year(y, *ns ? -1 : +1, &nth2, ry); 2331 } 2332 } 2333 else { 2334 decode_year(y, style, nth, ry); 2335 r = c_valid_nth_kday_p(*ry, m, n, k, style, rm, rn, rk, rjd, ns); 2336 } 2337 return r; 2338} 2339#endif 2340 2341VALUE date_zone_to_diff(VALUE); 2342 2343static int 2344offset_to_sec(VALUE vof, int *rof) 2345{ 2346 switch (TYPE(vof)) { 2347 case T_FIXNUM: 2348 { 2349 long n; 2350 2351 n = FIX2LONG(vof); 2352 if (n != -1 && n != 0 && n != 1) 2353 return 0; 2354 *rof = (int)n * DAY_IN_SECONDS; 2355 return 1; 2356 } 2357 case T_FLOAT: 2358 { 2359 double n; 2360 2361 n = RFLOAT_VALUE(vof) * DAY_IN_SECONDS; 2362 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) 2363 return 0; 2364 *rof = (int)round(n); 2365 if (*rof != n) 2366 rb_warning("fraction of offset is ignored"); 2367 return 1; 2368 } 2369 default: 2370 if (!k_numeric_p(vof)) 2371 rb_raise(rb_eTypeError, "expected numeric"); 2372 vof = f_to_r(vof); 2373#ifdef CANONICALIZATION_FOR_MATHN 2374 if (!k_rational_p(vof)) 2375 return offset_to_sec(vof, rof); 2376#endif 2377 /* fall through */ 2378 case T_RATIONAL: 2379 { 2380 VALUE vs, vn, vd; 2381 long n; 2382 2383 vs = day_to_sec(vof); 2384 2385#ifdef CANONICALIZATION_FOR_MATHN 2386 if (!k_rational_p(vs)) { 2387 if (!FIXNUM_P(vs)) 2388 return 0; 2389 n = FIX2LONG(vs); 2390 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) 2391 return 0; 2392 *rof = (int)n; 2393 return 1; 2394 } 2395#endif 2396 vn = RRATIONAL(vs)->num; 2397 vd = RRATIONAL(vs)->den; 2398 2399 if (FIXNUM_P(vn) && FIXNUM_P(vd) && (FIX2LONG(vd) == 1)) 2400 n = FIX2LONG(vn); 2401 else { 2402 vn = f_round(vs); 2403 if (!f_eqeq_p(vn, vs)) 2404 rb_warning("fraction of offset is ignored"); 2405 if (!FIXNUM_P(vn)) 2406 return 0; 2407 n = FIX2LONG(vn); 2408 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) 2409 return 0; 2410 } 2411 *rof = (int)n; 2412 return 1; 2413 } 2414 case T_STRING: 2415 { 2416 VALUE vs = date_zone_to_diff(vof); 2417 long n; 2418 2419 if (!FIXNUM_P(vs)) 2420 return 0; 2421 n = FIX2LONG(vs); 2422 if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) 2423 return 0; 2424 *rof = (int)n; 2425 return 1; 2426 } 2427 } 2428 return 0; 2429} 2430 2431/* date */ 2432 2433#define valid_sg(sg) \ 2434{\ 2435 if (!c_valid_start_p(sg)) {\ 2436 sg = 0;\ 2437 rb_warning("invalid start is ignored");\ 2438 }\ 2439} 2440 2441static VALUE 2442valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2443{ 2444 double sg = NUM2DBL(argv[1]); 2445 valid_sg(sg); 2446 return argv[0]; 2447} 2448 2449#ifndef NDEBUG 2450static VALUE 2451date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass) 2452{ 2453 VALUE vjd, vsg; 2454 VALUE argv2[2]; 2455 2456 rb_scan_args(argc, argv, "11", &vjd, &vsg); 2457 2458 argv2[0] = vjd; 2459 if (argc < 2) 2460 argv2[1] = DBL2NUM(GREGORIAN); 2461 else 2462 argv2[1] = vsg; 2463 2464 return valid_jd_sub(2, argv2, klass, 1); 2465} 2466#endif 2467 2468/* 2469 * call-seq: 2470 * Date.valid_jd?(jd[, start=Date::ITALY]) -> bool 2471 * 2472 * Just returns true. It's nonsense, but is for symmetry. 2473 * 2474 * Date.valid_jd?(2451944) #=> true 2475 * 2476 * See also jd. 2477 */ 2478static VALUE 2479date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass) 2480{ 2481 VALUE vjd, vsg; 2482 VALUE argv2[2]; 2483 2484 rb_scan_args(argc, argv, "11", &vjd, &vsg); 2485 2486 argv2[0] = vjd; 2487 if (argc < 2) 2488 argv2[1] = INT2FIX(DEFAULT_SG); 2489 else 2490 argv2[1] = vsg; 2491 2492 if (NIL_P(valid_jd_sub(2, argv2, klass, 0))) 2493 return Qfalse; 2494 return Qtrue; 2495} 2496 2497static VALUE 2498valid_civil_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2499{ 2500 VALUE nth, y; 2501 int m, d, ry, rm, rd; 2502 double sg; 2503 2504 y = argv[0]; 2505 m = NUM2INT(argv[1]); 2506 d = NUM2INT(argv[2]); 2507 sg = NUM2DBL(argv[3]); 2508 2509 valid_sg(sg); 2510 2511 if (!need_jd && (guess_style(y, sg) < 0)) { 2512 if (!valid_gregorian_p(y, m, d, 2513 &nth, &ry, 2514 &rm, &rd)) 2515 return Qnil; 2516 return INT2FIX(0); /* dummy */ 2517 } 2518 else { 2519 int rjd, ns; 2520 VALUE rjd2; 2521 2522 if (!valid_civil_p(y, m, d, sg, 2523 &nth, &ry, 2524 &rm, &rd, &rjd, 2525 &ns)) 2526 return Qnil; 2527 if (!need_jd) 2528 return INT2FIX(0); /* dummy */ 2529 encode_jd(nth, rjd, &rjd2); 2530 return rjd2; 2531 } 2532} 2533 2534#ifndef NDEBUG 2535static VALUE 2536date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass) 2537{ 2538 VALUE vy, vm, vd, vsg; 2539 VALUE argv2[4]; 2540 2541 rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg); 2542 2543 argv2[0] = vy; 2544 argv2[1] = vm; 2545 argv2[2] = vd; 2546 if (argc < 4) 2547 argv2[3] = DBL2NUM(GREGORIAN); 2548 else 2549 argv2[3] = vsg; 2550 2551 return valid_civil_sub(4, argv2, klass, 1); 2552} 2553#endif 2554 2555/* 2556 * call-seq: 2557 * Date.valid_civil?(year, month, mday[, start=Date::ITALY]) -> bool 2558 * Date.valid_date?(year, month, mday[, start=Date::ITALY]) -> bool 2559 * 2560 * Returns true if the given calendar date is valid, and false if not. 2561 * 2562 * Date.valid_date?(2001,2,3) #=> true 2563 * Date.valid_date?(2001,2,29) #=> false 2564 * 2565 * See also jd and civil. 2566 */ 2567static VALUE 2568date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass) 2569{ 2570 VALUE vy, vm, vd, vsg; 2571 VALUE argv2[4]; 2572 2573 rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg); 2574 2575 argv2[0] = vy; 2576 argv2[1] = vm; 2577 argv2[2] = vd; 2578 if (argc < 4) 2579 argv2[3] = INT2FIX(DEFAULT_SG); 2580 else 2581 argv2[3] = vsg; 2582 2583 if (NIL_P(valid_civil_sub(4, argv2, klass, 0))) 2584 return Qfalse; 2585 return Qtrue; 2586} 2587 2588static VALUE 2589valid_ordinal_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2590{ 2591 VALUE nth, y; 2592 int d, ry, rd; 2593 double sg; 2594 2595 y = argv[0]; 2596 d = NUM2INT(argv[1]); 2597 sg = NUM2DBL(argv[2]); 2598 2599 valid_sg(sg); 2600 2601 { 2602 int rjd, ns; 2603 VALUE rjd2; 2604 2605 if (!valid_ordinal_p(y, d, sg, 2606 &nth, &ry, 2607 &rd, &rjd, 2608 &ns)) 2609 return Qnil; 2610 if (!need_jd) 2611 return INT2FIX(0); /* dummy */ 2612 encode_jd(nth, rjd, &rjd2); 2613 return rjd2; 2614 } 2615} 2616 2617#ifndef NDEBUG 2618static VALUE 2619date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass) 2620{ 2621 VALUE vy, vd, vsg; 2622 VALUE argv2[3]; 2623 2624 rb_scan_args(argc, argv, "21", &vy, &vd, &vsg); 2625 2626 argv2[0] = vy; 2627 argv2[1] = vd; 2628 if (argc < 3) 2629 argv2[2] = DBL2NUM(GREGORIAN); 2630 else 2631 argv2[2] = vsg; 2632 2633 return valid_ordinal_sub(3, argv2, klass, 1); 2634} 2635#endif 2636 2637/* 2638 * call-seq: 2639 * Date.valid_ordinal?(year, yday[, start=Date::ITALY]) -> bool 2640 * 2641 * Returns true if the given ordinal date is valid, and false if not. 2642 * 2643 * Date.valid_ordinal?(2001,34) #=> true 2644 * Date.valid_ordinal?(2001,366) #=> false 2645 * 2646 * See also jd and ordinal. 2647 */ 2648static VALUE 2649date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass) 2650{ 2651 VALUE vy, vd, vsg; 2652 VALUE argv2[3]; 2653 2654 rb_scan_args(argc, argv, "21", &vy, &vd, &vsg); 2655 2656 argv2[0] = vy; 2657 argv2[1] = vd; 2658 if (argc < 3) 2659 argv2[2] = INT2FIX(DEFAULT_SG); 2660 else 2661 argv2[2] = vsg; 2662 2663 if (NIL_P(valid_ordinal_sub(3, argv2, klass, 0))) 2664 return Qfalse; 2665 return Qtrue; 2666} 2667 2668static VALUE 2669valid_commercial_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2670{ 2671 VALUE nth, y; 2672 int w, d, ry, rw, rd; 2673 double sg; 2674 2675 y = argv[0]; 2676 w = NUM2INT(argv[1]); 2677 d = NUM2INT(argv[2]); 2678 sg = NUM2DBL(argv[3]); 2679 2680 valid_sg(sg); 2681 2682 { 2683 int rjd, ns; 2684 VALUE rjd2; 2685 2686 if (!valid_commercial_p(y, w, d, sg, 2687 &nth, &ry, 2688 &rw, &rd, &rjd, 2689 &ns)) 2690 return Qnil; 2691 if (!need_jd) 2692 return INT2FIX(0); /* dummy */ 2693 encode_jd(nth, rjd, &rjd2); 2694 return rjd2; 2695 } 2696} 2697 2698#ifndef NDEBUG 2699static VALUE 2700date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass) 2701{ 2702 VALUE vy, vw, vd, vsg; 2703 VALUE argv2[4]; 2704 2705 rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg); 2706 2707 argv2[0] = vy; 2708 argv2[1] = vw; 2709 argv2[2] = vd; 2710 if (argc < 4) 2711 argv2[3] = DBL2NUM(GREGORIAN); 2712 else 2713 argv2[3] = vsg; 2714 2715 return valid_commercial_sub(4, argv2, klass, 1); 2716} 2717#endif 2718 2719/* 2720 * call-seq: 2721 * Date.valid_commercial?(cwyear, cweek, cwday[, start=Date::ITALY]) -> bool 2722 * 2723 * Returns true if the given week date is valid, and false if not. 2724 * 2725 * Date.valid_commercial?(2001,5,6) #=> true 2726 * Date.valid_commercial?(2001,5,8) #=> false 2727 * 2728 * See also jd and commercial. 2729 */ 2730static VALUE 2731date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) 2732{ 2733 VALUE vy, vw, vd, vsg; 2734 VALUE argv2[4]; 2735 2736 rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg); 2737 2738 argv2[0] = vy; 2739 argv2[1] = vw; 2740 argv2[2] = vd; 2741 if (argc < 4) 2742 argv2[3] = INT2FIX(DEFAULT_SG); 2743 else 2744 argv2[3] = vsg; 2745 2746 if (NIL_P(valid_commercial_sub(4, argv2, klass, 0))) 2747 return Qfalse; 2748 return Qtrue; 2749} 2750 2751#ifndef NDEBUG 2752static VALUE 2753valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2754{ 2755 VALUE nth, y; 2756 int w, d, f, ry, rw, rd; 2757 double sg; 2758 2759 y = argv[0]; 2760 w = NUM2INT(argv[1]); 2761 d = NUM2INT(argv[2]); 2762 f = NUM2INT(argv[3]); 2763 sg = NUM2DBL(argv[4]); 2764 2765 valid_sg(sg); 2766 2767 { 2768 int rjd, ns; 2769 VALUE rjd2; 2770 2771 if (!valid_weeknum_p(y, w, d, f, sg, 2772 &nth, &ry, 2773 &rw, &rd, &rjd, 2774 &ns)) 2775 return Qnil; 2776 if (!need_jd) 2777 return INT2FIX(0); /* dummy */ 2778 encode_jd(nth, rjd, &rjd2); 2779 return rjd2; 2780 } 2781} 2782 2783static VALUE 2784date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass) 2785{ 2786 VALUE vy, vw, vd, vf, vsg; 2787 VALUE argv2[5]; 2788 2789 rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg); 2790 2791 argv2[0] = vy; 2792 argv2[1] = vw; 2793 argv2[2] = vd; 2794 argv2[3] = vf; 2795 if (argc < 5) 2796 argv2[4] = DBL2NUM(GREGORIAN); 2797 else 2798 argv2[4] = vsg; 2799 2800 return valid_weeknum_sub(5, argv2, klass, 1); 2801} 2802 2803static VALUE 2804date_s_valid_weeknum_p(int argc, VALUE *argv, VALUE klass) 2805{ 2806 VALUE vy, vw, vd, vf, vsg; 2807 VALUE argv2[5]; 2808 2809 rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg); 2810 2811 argv2[0] = vy; 2812 argv2[1] = vw; 2813 argv2[2] = vd; 2814 argv2[3] = vf; 2815 if (argc < 5) 2816 argv2[4] = INT2FIX(DEFAULT_SG); 2817 else 2818 argv2[4] = vsg; 2819 2820 if (NIL_P(valid_weeknum_sub(5, argv2, klass, 0))) 2821 return Qfalse; 2822 return Qtrue; 2823} 2824 2825static VALUE 2826valid_nth_kday_sub(int argc, VALUE *argv, VALUE klass, int need_jd) 2827{ 2828 VALUE nth, y; 2829 int m, n, k, ry, rm, rn, rk; 2830 double sg; 2831 2832 y = argv[0]; 2833 m = NUM2INT(argv[1]); 2834 n = NUM2INT(argv[2]); 2835 k = NUM2INT(argv[3]); 2836 sg = NUM2DBL(argv[4]); 2837 2838 { 2839 int rjd, ns; 2840 VALUE rjd2; 2841 2842 if (!valid_nth_kday_p(y, m, n, k, sg, 2843 &nth, &ry, 2844 &rm, &rn, &rk, &rjd, 2845 &ns)) 2846 return Qnil; 2847 if (!need_jd) 2848 return INT2FIX(0); /* dummy */ 2849 encode_jd(nth, rjd, &rjd2); 2850 return rjd2; 2851 } 2852} 2853 2854static VALUE 2855date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) 2856{ 2857 VALUE vy, vm, vn, vk, vsg; 2858 VALUE argv2[5]; 2859 2860 rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg); 2861 2862 argv2[0] = vy; 2863 argv2[1] = vm; 2864 argv2[2] = vn; 2865 argv2[3] = vk; 2866 if (argc < 5) 2867 argv2[4] = DBL2NUM(GREGORIAN); 2868 else 2869 argv2[4] = vsg; 2870 2871 return valid_nth_kday_sub(5, argv2, klass, 1); 2872} 2873 2874static VALUE 2875date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) 2876{ 2877 VALUE vy, vm, vn, vk, vsg; 2878 VALUE argv2[5]; 2879 2880 rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg); 2881 2882 argv2[0] = vy; 2883 argv2[1] = vm; 2884 argv2[2] = vn; 2885 argv2[3] = vk; 2886 if (argc < 5) 2887 argv2[4] = INT2FIX(DEFAULT_SG); 2888 else 2889 argv2[4] = vsg; 2890 2891 if (NIL_P(valid_nth_kday_sub(5, argv2, klass, 0))) 2892 return Qfalse; 2893 return Qtrue; 2894} 2895 2896static VALUE 2897date_s_zone_to_diff(VALUE klass, VALUE str) 2898{ 2899 return date_zone_to_diff(str); 2900} 2901#endif 2902 2903/* 2904 * call-seq: 2905 * Date.julian_leap?(year) -> bool 2906 * 2907 * Returns true if the given year is a leap year of the proleptic 2908 * Julian calendar. 2909 * 2910 * Date.julian_leap?(1900) #=> true 2911 * Date.julian_leap?(1901) #=> false 2912 */ 2913static VALUE 2914date_s_julian_leap_p(VALUE klass, VALUE y) 2915{ 2916 VALUE nth; 2917 int ry; 2918 2919 decode_year(y, +1, &nth, &ry); 2920 return f_boolcast(c_julian_leap_p(ry)); 2921} 2922 2923/* 2924 * call-seq: 2925 * Date.gregorian_leap?(year) -> bool 2926 * Date.leap?(year) -> bool 2927 * 2928 * Returns true if the given year is a leap year of the proleptic 2929 * Gregorian calendar. 2930 * 2931 * Date.gregorian_leap?(1900) #=> false 2932 * Date.gregorian_leap?(2000) #=> true 2933 */ 2934static VALUE 2935date_s_gregorian_leap_p(VALUE klass, VALUE y) 2936{ 2937 VALUE nth; 2938 int ry; 2939 2940 decode_year(y, -1, &nth, &ry); 2941 return f_boolcast(c_gregorian_leap_p(ry)); 2942} 2943 2944static void 2945d_lite_gc_mark(union DateData *dat) 2946{ 2947 if (simple_dat_p(dat)) 2948 rb_gc_mark(dat->s.nth); 2949 else { 2950 rb_gc_mark(dat->c.nth); 2951 rb_gc_mark(dat->c.sf); 2952 2953 } 2954} 2955 2956inline static VALUE 2957d_simple_new_internal(VALUE klass, 2958 VALUE nth, int jd, 2959 double sg, 2960 int y, int m, int d, 2961 unsigned flags) 2962{ 2963 struct SimpleDateData *dat; 2964 VALUE obj; 2965 2966 obj = Data_Make_Struct(klass, struct SimpleDateData, 2967 d_lite_gc_mark, -1, dat); 2968 set_to_simple(dat, nth, jd, sg, y, m, d, flags & ~COMPLEX_DAT); 2969 2970 assert(have_jd_p(dat) || have_civil_p(dat)); 2971 2972 return obj; 2973} 2974 2975inline static VALUE 2976d_complex_new_internal(VALUE klass, 2977 VALUE nth, int jd, 2978 int df, VALUE sf, 2979 int of, double sg, 2980 int y, int m, int d, 2981 int h, int min, int s, 2982 unsigned flags) 2983{ 2984 struct ComplexDateData *dat; 2985 VALUE obj; 2986 2987 obj = Data_Make_Struct(klass, struct ComplexDateData, 2988 d_lite_gc_mark, -1, dat); 2989 set_to_complex(dat, nth, jd, df, sf, of, sg, 2990 y, m, d, h, min, s, flags | COMPLEX_DAT); 2991 2992 assert(have_jd_p(dat) || have_civil_p(dat)); 2993 assert(have_df_p(dat) || have_time_p(dat)); 2994 2995 return obj; 2996} 2997 2998static VALUE 2999d_lite_s_alloc_simple(VALUE klass) 3000{ 3001 return d_simple_new_internal(klass, 3002 INT2FIX(0), 0, 3003 DEFAULT_SG, 3004 0, 0, 0, 3005 HAVE_JD); 3006} 3007 3008static VALUE 3009d_lite_s_alloc_complex(VALUE klass) 3010{ 3011 return d_complex_new_internal(klass, 3012 INT2FIX(0), 0, 3013 0, INT2FIX(0), 3014 0, DEFAULT_SG, 3015 0, 0, 0, 3016 0, 0, 0, 3017 HAVE_JD | HAVE_DF); 3018} 3019 3020static VALUE 3021d_lite_s_alloc(VALUE klass) 3022{ 3023 return d_lite_s_alloc_complex(klass); 3024} 3025 3026static void 3027old_to_new(VALUE ajd, VALUE of, VALUE sg, 3028 VALUE *rnth, int *rjd, int *rdf, VALUE *rsf, 3029 int *rof, double *rsg) 3030{ 3031 VALUE jd, df, sf, of2, t; 3032 3033 decode_day(f_add(ajd, half_days_in_day), 3034 &jd, &df, &sf); 3035 t = day_to_sec(of); 3036 of2 = f_round(t); 3037 3038 if (!f_eqeq_p(of2, t)) 3039 rb_warning("fraction of offset is ignored"); 3040 3041 decode_jd(jd, rnth, rjd); 3042 3043 *rdf = NUM2INT(df); 3044 *rsf = sf; 3045 *rof = NUM2INT(of2); 3046 *rsg = NUM2DBL(sg); 3047 3048 if (*rdf < 0 || *rdf >= DAY_IN_SECONDS) 3049 rb_raise(rb_eArgError, "invalid day fraction"); 3050 3051 if (f_lt_p(*rsf, INT2FIX(0)) || 3052 f_ge_p(*rsf, INT2FIX(SECOND_IN_NANOSECONDS))) 3053 3054 if (*rof < -DAY_IN_SECONDS || *rof > DAY_IN_SECONDS) { 3055 *rof = 0; 3056 rb_warning("invalid offset is ignored"); 3057 } 3058 3059 if (!c_valid_start_p(*rsg)) { 3060 *rsg = DEFAULT_SG; 3061 rb_warning("invalid start is ignored"); 3062 } 3063} 3064 3065#ifndef NDEBUG 3066static VALUE 3067date_s_new_bang(int argc, VALUE *argv, VALUE klass) 3068{ 3069 VALUE ajd, of, sg, nth, sf; 3070 int jd, df, rof; 3071 double rsg; 3072 3073 rb_scan_args(argc, argv, "03", &ajd, &of, &sg); 3074 3075 switch (argc) { 3076 case 0: 3077 ajd = INT2FIX(0); 3078 case 1: 3079 of = INT2FIX(0); 3080 case 2: 3081 sg = INT2FIX(DEFAULT_SG); 3082 } 3083 3084 old_to_new(ajd, of, sg, 3085 &nth, &jd, &df, &sf, &rof, &rsg); 3086 3087 if (!df && f_zero_p(sf) && !rof) 3088 return d_simple_new_internal(klass, 3089 nth, jd, 3090 rsg, 3091 0, 0, 0, 3092 HAVE_JD); 3093 else 3094 return d_complex_new_internal(klass, 3095 nth, jd, 3096 df, sf, 3097 rof, rsg, 3098 0, 0, 0, 3099 0, 0, 0, 3100 HAVE_JD | HAVE_DF); 3101} 3102#endif 3103 3104inline static int 3105wholenum_p(VALUE x) 3106{ 3107 if (FIXNUM_P(x)) 3108 return 1; 3109 switch (TYPE(x)) { 3110 case T_BIGNUM: 3111 return 1; 3112 case T_FLOAT: 3113 { 3114 double d = RFLOAT_VALUE(x); 3115 return round(d) == d; 3116 } 3117 break; 3118 case T_RATIONAL: 3119 { 3120 VALUE den = RRATIONAL(x)->den; 3121 return FIXNUM_P(den) && FIX2LONG(den) == 1; 3122 } 3123 break; 3124 } 3125 return 0; 3126} 3127 3128inline static VALUE 3129to_integer(VALUE x) 3130{ 3131 if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM)) 3132 return x; 3133 return f_to_i(x); 3134} 3135 3136inline static VALUE 3137d_trunc(VALUE d, VALUE *fr) 3138{ 3139 VALUE rd; 3140 3141 if (wholenum_p(d)) { 3142 rd = to_integer(d); 3143 *fr = INT2FIX(0); 3144 } 3145 else { 3146 rd = f_idiv(d, INT2FIX(1)); 3147 *fr = f_mod(d, INT2FIX(1)); 3148 } 3149 return rd; 3150} 3151 3152#define jd_trunc d_trunc 3153#define k_trunc d_trunc 3154 3155inline static VALUE 3156h_trunc(VALUE h, VALUE *fr) 3157{ 3158 VALUE rh; 3159 3160 if (wholenum_p(h)) { 3161 rh = to_integer(h); 3162 *fr = INT2FIX(0); 3163 } 3164 else { 3165 rh = f_idiv(h, INT2FIX(1)); 3166 *fr = f_mod(h, INT2FIX(1)); 3167 *fr = f_quo(*fr, INT2FIX(24)); 3168 } 3169 return rh; 3170} 3171 3172inline static VALUE 3173min_trunc(VALUE min, VALUE *fr) 3174{ 3175 VALUE rmin; 3176 3177 if (wholenum_p(min)) { 3178 rmin = to_integer(min); 3179 *fr = INT2FIX(0); 3180 } 3181 else { 3182 rmin = f_idiv(min, INT2FIX(1)); 3183 *fr = f_mod(min, INT2FIX(1)); 3184 *fr = f_quo(*fr, INT2FIX(1440)); 3185 } 3186 return rmin; 3187} 3188 3189inline static VALUE 3190s_trunc(VALUE s, VALUE *fr) 3191{ 3192 VALUE rs; 3193 3194 if (wholenum_p(s)) { 3195 rs = to_integer(s); 3196 *fr = INT2FIX(0); 3197 } 3198 else { 3199 rs = f_idiv(s, INT2FIX(1)); 3200 *fr = f_mod(s, INT2FIX(1)); 3201 *fr = f_quo(*fr, INT2FIX(86400)); 3202 } 3203 return rs; 3204} 3205 3206#define num2num_with_frac(s,n) \ 3207{\ 3208 s = s##_trunc(v##s, &fr);\ 3209 if (f_nonzero_p(fr)) {\ 3210 if (argc > n)\ 3211 rb_raise(rb_eArgError, "invalid fraction");\ 3212 fr2 = fr;\ 3213 }\ 3214} 3215 3216#define num2int_with_frac(s,n) \ 3217{\ 3218 s = NUM2INT(s##_trunc(v##s, &fr));\ 3219 if (f_nonzero_p(fr)) {\ 3220 if (argc > n)\ 3221 rb_raise(rb_eArgError, "invalid fraction");\ 3222 fr2 = fr;\ 3223 }\ 3224} 3225 3226#define canon24oc() \ 3227{\ 3228 if (rh == 24) {\ 3229 rh = 0;\ 3230 fr2 = f_add(fr2, INT2FIX(1));\ 3231 }\ 3232} 3233 3234#define add_frac() \ 3235{\ 3236 if (f_nonzero_p(fr2))\ 3237 ret = d_lite_plus(ret, fr2);\ 3238} 3239 3240#define val2sg(vsg,dsg) \ 3241{\ 3242 dsg = NUM2DBL(vsg);\ 3243 if (!c_valid_start_p(dsg)) {\ 3244 dsg = DEFAULT_SG;\ 3245 rb_warning("invalid start is ignored");\ 3246 }\ 3247} 3248 3249static VALUE d_lite_plus(VALUE, VALUE); 3250 3251/* 3252 * call-seq: 3253 * Date.jd([jd=0[, start=Date::ITALY]]) -> date 3254 * 3255 * Creates a date object denoting the given chronological Julian day 3256 * number. 3257 * 3258 * Date.jd(2451944) #=> #<Date: 2001-02-03 ...> 3259 * Date.jd(2451945) #=> #<Date: 2001-02-04 ...> 3260 * Date.jd(0) #=> #<Date: -4712-01-01 ...> 3261 * 3262 * See also new. 3263 */ 3264static VALUE 3265date_s_jd(int argc, VALUE *argv, VALUE klass) 3266{ 3267 VALUE vjd, vsg, jd, fr, fr2, ret; 3268 double sg; 3269 3270 rb_scan_args(argc, argv, "02", &vjd, &vsg); 3271 3272 jd = INT2FIX(0); 3273 fr2 = INT2FIX(0); 3274 sg = DEFAULT_SG; 3275 3276 switch (argc) { 3277 case 2: 3278 val2sg(vsg, sg); 3279 case 1: 3280 num2num_with_frac(jd, positive_inf); 3281 } 3282 3283 { 3284 VALUE nth; 3285 int rjd; 3286 3287 decode_jd(jd, &nth, &rjd); 3288 ret = d_simple_new_internal(klass, 3289 nth, rjd, 3290 sg, 3291 0, 0, 0, 3292 HAVE_JD); 3293 } 3294 add_frac(); 3295 return ret; 3296} 3297 3298/* 3299 * call-seq: 3300 * Date.ordinal([year=-4712[, yday=1[, start=Date::ITALY]]]) -> date 3301 * 3302 * Creates a date object denoting the given ordinal date. 3303 * 3304 * The day of year should be a negative or a positive number (as a 3305 * relative day from the end of year when negative). It should not be 3306 * zero. 3307 * 3308 * Date.ordinal(2001) #=> #<Date: 2001-01-01 ...> 3309 * Date.ordinal(2001,34) #=> #<Date: 2001-02-03 ...> 3310 * Date.ordinal(2001,-1) #=> #<Date: 2001-12-31 ...> 3311 * 3312 * See also jd and new. 3313 */ 3314static VALUE 3315date_s_ordinal(int argc, VALUE *argv, VALUE klass) 3316{ 3317 VALUE vy, vd, vsg, y, fr, fr2, ret; 3318 int d; 3319 double sg; 3320 3321 rb_scan_args(argc, argv, "03", &vy, &vd, &vsg); 3322 3323 y = INT2FIX(-4712); 3324 d = 1; 3325 fr2 = INT2FIX(0); 3326 sg = DEFAULT_SG; 3327 3328 switch (argc) { 3329 case 3: 3330 val2sg(vsg, sg); 3331 case 2: 3332 num2int_with_frac(d, positive_inf); 3333 case 1: 3334 y = vy; 3335 } 3336 3337 { 3338 VALUE nth; 3339 int ry, rd, rjd, ns; 3340 3341 if (!valid_ordinal_p(y, d, sg, 3342 &nth, &ry, 3343 &rd, &rjd, 3344 &ns)) 3345 rb_raise(rb_eArgError, "invalid date"); 3346 3347 ret = d_simple_new_internal(klass, 3348 nth, rjd, 3349 sg, 3350 0, 0, 0, 3351 HAVE_JD); 3352 } 3353 add_frac(); 3354 return ret; 3355} 3356 3357/* 3358 * call-seq: 3359 * Date.civil([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]]) -> date 3360 * Date.new([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]]) -> date 3361 * 3362 * Creates a date object denoting the given calendar date. 3363 * 3364 * In this class, BCE years are counted astronomically. Thus, the 3365 * year before the year 1 is the year zero, and the year preceding the 3366 * year zero is the year -1. The month and the day of month should be 3367 * a negative or a positive number (as a relative month/day from the 3368 * end of year/month when negative). They should not be zero. 3369 * 3370 * The last argument should be a Julian day number which denotes the 3371 * day of calendar reform. Date::ITALY (2299161=1582-10-15), 3372 * Date::ENGLAND (2361222=1752-09-14), Date::GREGORIAN (the proleptic 3373 * Gregorian calendar) and Date::JULIAN (the proleptic Julian 3374 * calendar) can be specified as a day of calendar reform. 3375 * 3376 * Date.new(2001) #=> #<Date: 2001-01-01 ...> 3377 * Date.new(2001,2,3) #=> #<Date: 2001-02-03 ...> 3378 * Date.new(2001,2,-1) #=> #<Date: 2001-02-28 ...> 3379 * 3380 * See also jd. 3381 */ 3382static VALUE 3383date_s_civil(int argc, VALUE *argv, VALUE klass) 3384{ 3385 VALUE vy, vm, vd, vsg, y, fr, fr2, ret; 3386 int m, d; 3387 double sg; 3388 3389 rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg); 3390 3391 y = INT2FIX(-4712); 3392 m = 1; 3393 d = 1; 3394 fr2 = INT2FIX(0); 3395 sg = DEFAULT_SG; 3396 3397 switch (argc) { 3398 case 4: 3399 val2sg(vsg, sg); 3400 case 3: 3401 num2int_with_frac(d, positive_inf); 3402 case 2: 3403 m = NUM2INT(vm); 3404 case 1: 3405 y = vy; 3406 } 3407 3408 if (guess_style(y, sg) < 0) { 3409 VALUE nth; 3410 int ry, rm, rd; 3411 3412 if (!valid_gregorian_p(y, m, d, 3413 &nth, &ry, 3414 &rm, &rd)) 3415 rb_raise(rb_eArgError, "invalid date"); 3416 3417 ret = d_simple_new_internal(klass, 3418 nth, 0, 3419 sg, 3420 ry, rm, rd, 3421 HAVE_CIVIL); 3422 } 3423 else { 3424 VALUE nth; 3425 int ry, rm, rd, rjd, ns; 3426 3427 if (!valid_civil_p(y, m, d, sg, 3428 &nth, &ry, 3429 &rm, &rd, &rjd, 3430 &ns)) 3431 rb_raise(rb_eArgError, "invalid date"); 3432 3433 ret = d_simple_new_internal(klass, 3434 nth, rjd, 3435 sg, 3436 ry, rm, rd, 3437 HAVE_JD | HAVE_CIVIL); 3438 } 3439 add_frac(); 3440 return ret; 3441} 3442 3443/* 3444 * call-seq: 3445 * Date.commercial([cwyear=-4712[, cweek=1[, cwday=1[, start=Date::ITALY]]]]) -> date 3446 * 3447 * Creates a date object denoting the given week date. 3448 * 3449 * The week and the day of week should be a negative or a positive 3450 * number (as a relative week/day from the end of year/week when 3451 * negative). They should not be zero. 3452 * 3453 * Date.commercial(2001) #=> #<Date: 2001-01-01 ...> 3454 * Date.commercial(2002) #=> #<Date: 2001-12-31 ...> 3455 * Date.commercial(2001,5,6) #=> #<Date: 2001-02-03 ...> 3456 * 3457 * See also jd and new. 3458 */ 3459static VALUE 3460date_s_commercial(int argc, VALUE *argv, VALUE klass) 3461{ 3462 VALUE vy, vw, vd, vsg, y, fr, fr2, ret; 3463 int w, d; 3464 double sg; 3465 3466 rb_scan_args(argc, argv, "04", &vy, &vw, &vd, &vsg); 3467 3468 y = INT2FIX(-4712); 3469 w = 1; 3470 d = 1; 3471 fr2 = INT2FIX(0); 3472 sg = DEFAULT_SG; 3473 3474 switch (argc) { 3475 case 4: 3476 val2sg(vsg, sg); 3477 case 3: 3478 num2int_with_frac(d, positive_inf); 3479 case 2: 3480 w = NUM2INT(vw); 3481 case 1: 3482 y = vy; 3483 } 3484 3485 { 3486 VALUE nth; 3487 int ry, rw, rd, rjd, ns; 3488 3489 if (!valid_commercial_p(y, w, d, sg, 3490 &nth, &ry, 3491 &rw, &rd, &rjd, 3492 &ns)) 3493 rb_raise(rb_eArgError, "invalid date"); 3494 3495 ret = d_simple_new_internal(klass, 3496 nth, rjd, 3497 sg, 3498 0, 0, 0, 3499 HAVE_JD); 3500 } 3501 add_frac(); 3502 return ret; 3503} 3504 3505#ifndef NDEBUG 3506static VALUE 3507date_s_weeknum(int argc, VALUE *argv, VALUE klass) 3508{ 3509 VALUE vy, vw, vd, vf, vsg, y, fr, fr2, ret; 3510 int w, d, f; 3511 double sg; 3512 3513 rb_scan_args(argc, argv, "05", &vy, &vw, &vd, &vf, &vsg); 3514 3515 y = INT2FIX(-4712); 3516 w = 0; 3517 d = 1; 3518 f = 0; 3519 fr2 = INT2FIX(0); 3520 sg = DEFAULT_SG; 3521 3522 switch (argc) { 3523 case 5: 3524 val2sg(vsg, sg); 3525 case 4: 3526 f = NUM2INT(vf); 3527 case 3: 3528 num2int_with_frac(d, positive_inf); 3529 case 2: 3530 w = NUM2INT(vw); 3531 case 1: 3532 y = vy; 3533 } 3534 3535 { 3536 VALUE nth; 3537 int ry, rw, rd, rjd, ns; 3538 3539 if (!valid_weeknum_p(y, w, d, f, sg, 3540 &nth, &ry, 3541 &rw, &rd, &rjd, 3542 &ns)) 3543 rb_raise(rb_eArgError, "invalid date"); 3544 3545 ret = d_simple_new_internal(klass, 3546 nth, rjd, 3547 sg, 3548 0, 0, 0, 3549 HAVE_JD); 3550 } 3551 add_frac(); 3552 return ret; 3553} 3554 3555static VALUE 3556date_s_nth_kday(int argc, VALUE *argv, VALUE klass) 3557{ 3558 VALUE vy, vm, vn, vk, vsg, y, fr, fr2, ret; 3559 int m, n, k; 3560 double sg; 3561 3562 rb_scan_args(argc, argv, "05", &vy, &vm, &vn, &vk, &vsg); 3563 3564 y = INT2FIX(-4712); 3565 m = 1; 3566 n = 1; 3567 k = 1; 3568 fr2 = INT2FIX(0); 3569 sg = DEFAULT_SG; 3570 3571 switch (argc) { 3572 case 5: 3573 val2sg(vsg, sg); 3574 case 4: 3575 num2int_with_frac(k, positive_inf); 3576 case 3: 3577 n = NUM2INT(vn); 3578 case 2: 3579 m = NUM2INT(vm); 3580 case 1: 3581 y = vy; 3582 } 3583 3584 { 3585 VALUE nth; 3586 int ry, rm, rn, rk, rjd, ns; 3587 3588 if (!valid_nth_kday_p(y, m, n, k, sg, 3589 &nth, &ry, 3590 &rm, &rn, &rk, &rjd, 3591 &ns)) 3592 rb_raise(rb_eArgError, "invalid date"); 3593 3594 ret = d_simple_new_internal(klass, 3595 nth, rjd, 3596 sg, 3597 0, 0, 0, 3598 HAVE_JD); 3599 } 3600 add_frac(); 3601 return ret; 3602} 3603#endif 3604 3605#if !defined(HAVE_GMTIME_R) 3606static struct tm* 3607gmtime_r(const time_t *t, struct tm *tm) 3608{ 3609 auto struct tm *tmp = gmtime(t); 3610 if (tmp) 3611 *tm = *tmp; 3612 return tmp; 3613} 3614 3615static struct tm* 3616localtime_r(const time_t *t, struct tm *tm) 3617{ 3618 auto struct tm *tmp = localtime(t); 3619 if (tmp) 3620 *tm = *tmp; 3621 return tmp; 3622} 3623#endif 3624 3625static void set_sg(union DateData *, double); 3626 3627/* 3628 * call-seq: 3629 * Date.today([start=Date::ITALY]) -> date 3630 * 3631 * Date.today #=> #<Date: 2011-06-11 ..> 3632 * 3633 * Creates a date object denoting the present day. 3634 */ 3635static VALUE 3636date_s_today(int argc, VALUE *argv, VALUE klass) 3637{ 3638 VALUE vsg, nth, ret; 3639 double sg; 3640 time_t t; 3641 struct tm tm; 3642 int y, ry, m, d; 3643 3644 rb_scan_args(argc, argv, "01", &vsg); 3645 3646 if (argc < 1) 3647 sg = DEFAULT_SG; 3648 else 3649 val2sg(vsg, sg); 3650 3651 if (time(&t) == -1) 3652 rb_sys_fail("time"); 3653 tzset(); 3654 if (!localtime_r(&t, &tm)) 3655 rb_sys_fail("localtime"); 3656 3657 y = tm.tm_year + 1900; 3658 m = tm.tm_mon + 1; 3659 d = tm.tm_mday; 3660 3661 decode_year(INT2FIX(y), -1, &nth, &ry); 3662 3663 ret = d_simple_new_internal(klass, 3664 nth, 0, 3665 GREGORIAN, 3666 ry, m, d, 3667 HAVE_CIVIL); 3668 { 3669 get_d1(ret); 3670 set_sg(dat, sg); 3671 } 3672 return ret; 3673} 3674 3675#define set_hash0(k,v) rb_hash_aset(hash, k, v) 3676#define ref_hash0(k) rb_hash_aref(hash, k) 3677#define del_hash0(k) rb_hash_delete(hash, k) 3678 3679#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v) 3680#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k))) 3681#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k))) 3682 3683static VALUE 3684rt_rewrite_frags(VALUE hash) 3685{ 3686 VALUE seconds; 3687 3688 seconds = ref_hash("seconds"); 3689 if (!NIL_P(seconds)) { 3690 VALUE d, h, min, s, fr; 3691 3692 d = f_idiv(seconds, INT2FIX(DAY_IN_SECONDS)); 3693 fr = f_mod(seconds, INT2FIX(DAY_IN_SECONDS)); 3694 3695 h = f_idiv(fr, INT2FIX(HOUR_IN_SECONDS)); 3696 fr = f_mod(fr, INT2FIX(HOUR_IN_SECONDS)); 3697 3698 min = f_idiv(fr, INT2FIX(MINUTE_IN_SECONDS)); 3699 fr = f_mod(fr, INT2FIX(MINUTE_IN_SECONDS)); 3700 3701 s = f_idiv(fr, INT2FIX(1)); 3702 fr = f_mod(fr, INT2FIX(1)); 3703 3704 set_hash("jd", f_add(UNIX_EPOCH_IN_CJD, d)); 3705 set_hash("hour", h); 3706 set_hash("min", min); 3707 set_hash("sec", s); 3708 set_hash("sec_fraction", fr); 3709 del_hash("seconds"); 3710 del_hash("offset"); 3711 } 3712 return hash; 3713} 3714 3715#define sym(x) ID2SYM(rb_intern(x)) 3716 3717static VALUE d_lite_year(VALUE); 3718static VALUE d_lite_wday(VALUE); 3719static VALUE d_lite_jd(VALUE); 3720 3721static VALUE 3722rt_complete_frags(VALUE klass, VALUE hash) 3723{ 3724 static VALUE tab = Qnil; 3725 int g, e; 3726 VALUE k, a, d; 3727 3728 if (NIL_P(tab)) { 3729 tab = rb_ary_new3(11, 3730 rb_ary_new3(2, 3731 sym("time"), 3732 rb_ary_new3(3, 3733 sym("hour"), 3734 sym("min"), 3735 sym("sec"))), 3736 rb_ary_new3(2, 3737 Qnil, 3738 rb_ary_new3(1, 3739 sym("jd"))), 3740 rb_ary_new3(2, 3741 sym("ordinal"), 3742 rb_ary_new3(5, 3743 sym("year"), 3744 sym("yday"), 3745 sym("hour"), 3746 sym("min"), 3747 sym("sec"))), 3748 rb_ary_new3(2, 3749 sym("civil"), 3750 rb_ary_new3(6, 3751 sym("year"), 3752 sym("mon"), 3753 sym("mday"), 3754 sym("hour"), 3755 sym("min"), 3756 sym("sec"))), 3757 rb_ary_new3(2, 3758 sym("commercial"), 3759 rb_ary_new3(6, 3760 sym("cwyear"), 3761 sym("cweek"), 3762 sym("cwday"), 3763 sym("hour"), 3764 sym("min"), 3765 sym("sec"))), 3766 rb_ary_new3(2, 3767 sym("wday"), 3768 rb_ary_new3(4, 3769 sym("wday"), 3770 sym("hour"), 3771 sym("min"), 3772 sym("sec"))), 3773 rb_ary_new3(2, 3774 sym("wnum0"), 3775 rb_ary_new3(6, 3776 sym("year"), 3777 sym("wnum0"), 3778 sym("wday"), 3779 sym("hour"), 3780 sym("min"), 3781 sym("sec"))), 3782 rb_ary_new3(2, 3783 sym("wnum1"), 3784 rb_ary_new3(6, 3785 sym("year"), 3786 sym("wnum1"), 3787 sym("wday"), 3788 sym("hour"), 3789 sym("min"), 3790 sym("sec"))), 3791 rb_ary_new3(2, 3792 Qnil, 3793 rb_ary_new3(6, 3794 sym("cwyear"), 3795 sym("cweek"), 3796 sym("wday"), 3797 sym("hour"), 3798 sym("min"), 3799 sym("sec"))), 3800 rb_ary_new3(2, 3801 Qnil, 3802 rb_ary_new3(6, 3803 sym("year"), 3804 sym("wnum0"), 3805 sym("cwday"), 3806 sym("hour"), 3807 sym("min"), 3808 sym("sec"))), 3809 rb_ary_new3(2, 3810 Qnil, 3811 rb_ary_new3(6, 3812 sym("year"), 3813 sym("wnum1"), 3814 sym("cwday"), 3815 sym("hour"), 3816 sym("min"), 3817 sym("sec")))); 3818 rb_gc_register_mark_object(tab); 3819 } 3820 3821 { 3822 int i, eno = 0, idx = 0; 3823 3824 for (i = 0; i < RARRAY_LENINT(tab); i++) { 3825 VALUE x, a; 3826 3827 x = RARRAY_PTR(tab)[i]; 3828 a = RARRAY_PTR(x)[1]; 3829 3830 { 3831 int j, n = 0; 3832 3833 for (j = 0; j < RARRAY_LENINT(a); j++) 3834 if (!NIL_P(ref_hash0(RARRAY_PTR(a)[j]))) 3835 n++; 3836 if (n > eno) { 3837 eno = n; 3838 idx = i; 3839 } 3840 } 3841 } 3842 if (eno == 0) 3843 g = 0; 3844 else { 3845 g = 1; 3846 k = RARRAY_PTR(RARRAY_PTR(tab)[idx])[0]; 3847 a = RARRAY_PTR(RARRAY_PTR(tab)[idx])[1]; 3848 e = eno; 3849 } 3850 } 3851 3852 d = Qnil; 3853 3854 if (g && !NIL_P(k) && (RARRAY_LENINT(a) - e)) { 3855 if (k == sym("ordinal")) { 3856 if (NIL_P(ref_hash("year"))) { 3857 if (NIL_P(d)) 3858 d = date_s_today(0, (VALUE *)0, cDate); 3859 set_hash("year", d_lite_year(d)); 3860 } 3861 if (NIL_P(ref_hash("yday"))) 3862 set_hash("yday", INT2FIX(1)); 3863 } 3864 else if (k == sym("civil")) { 3865 int i; 3866 3867 for (i = 0; i < RARRAY_LENINT(a); i++) { 3868 VALUE e = RARRAY_PTR(a)[i]; 3869 3870 if (!NIL_P(ref_hash0(e))) 3871 break; 3872 if (NIL_P(d)) 3873 d = date_s_today(0, (VALUE *)0, cDate); 3874 set_hash0(e, rb_funcall(d, SYM2ID(e), 0)); 3875 } 3876 if (NIL_P(ref_hash("mon"))) 3877 set_hash("mon", INT2FIX(1)); 3878 if (NIL_P(ref_hash("mday"))) 3879 set_hash("mday", INT2FIX(1)); 3880 } 3881 else if (k == sym("commercial")) { 3882 int i; 3883 3884 for (i = 0; i < RARRAY_LENINT(a); i++) { 3885 VALUE e = RARRAY_PTR(a)[i]; 3886 3887 if (!NIL_P(ref_hash0(e))) 3888 break; 3889 if (NIL_P(d)) 3890 d = date_s_today(0, (VALUE *)0, cDate); 3891 set_hash0(e, rb_funcall(d, SYM2ID(e), 0)); 3892 } 3893 if (NIL_P(ref_hash("cweek"))) 3894 set_hash("cweek", INT2FIX(1)); 3895 if (NIL_P(ref_hash("cwday"))) 3896 set_hash("cwday", INT2FIX(1)); 3897 } 3898 else if (k == sym("wday")) { 3899 if (NIL_P(d)) 3900 d = date_s_today(0, (VALUE *)0, cDate); 3901 set_hash("jd", d_lite_jd(f_add(f_sub(d, 3902 d_lite_wday(d)), 3903 ref_hash("wday")))); 3904 } 3905 else if (k == sym("wnum0")) { 3906 int i; 3907 3908 for (i = 0; i < RARRAY_LENINT(a); i++) { 3909 VALUE e = RARRAY_PTR(a)[i]; 3910 3911 if (!NIL_P(ref_hash0(e))) 3912 break; 3913 if (NIL_P(d)) 3914 d = date_s_today(0, (VALUE *)0, cDate); 3915 set_hash0(e, rb_funcall(d, SYM2ID(e), 0)); 3916 } 3917 if (NIL_P(ref_hash("wnum0"))) 3918 set_hash("wnum0", INT2FIX(0)); 3919 if (NIL_P(ref_hash("wday"))) 3920 set_hash("wday", INT2FIX(0)); 3921 } 3922 else if (k == sym("wnum1")) { 3923 int i; 3924 3925 for (i = 0; i < RARRAY_LENINT(a); i++) { 3926 VALUE e = RARRAY_PTR(a)[i]; 3927 3928 if (!NIL_P(ref_hash0(e))) 3929 break; 3930 if (NIL_P(d)) 3931 d = date_s_today(0, (VALUE *)0, cDate); 3932 set_hash0(e, rb_funcall(d, SYM2ID(e), 0)); 3933 } 3934 if (NIL_P(ref_hash("wnum1"))) 3935 set_hash("wnum1", INT2FIX(0)); 3936 if (NIL_P(ref_hash("wday"))) 3937 set_hash("wday", INT2FIX(1)); 3938 } 3939 } 3940 3941 if (g && k == sym("time")) { 3942 if (f_le_p(klass, cDateTime)) { 3943 if (NIL_P(d)) 3944 d = date_s_today(0, (VALUE *)0, cDate); 3945 if (NIL_P(ref_hash("jd"))) 3946 set_hash("jd", d_lite_jd(d)); 3947 } 3948 } 3949 3950 if (NIL_P(ref_hash("hour"))) 3951 set_hash("hour", INT2FIX(0)); 3952 if (NIL_P(ref_hash("min"))) 3953 set_hash("min", INT2FIX(0)); 3954 if (NIL_P(ref_hash("sec"))) 3955 set_hash("sec", INT2FIX(0)); 3956 else if (f_gt_p(ref_hash("sec"), INT2FIX(59))) 3957 set_hash("sec", INT2FIX(59)); 3958 3959 return hash; 3960} 3961 3962static VALUE 3963rt__valid_jd_p(VALUE jd, VALUE sg) 3964{ 3965 return jd; 3966} 3967 3968static VALUE 3969rt__valid_ordinal_p(VALUE y, VALUE d, VALUE sg) 3970{ 3971 VALUE nth, rjd2; 3972 int ry, rd, rjd, ns; 3973 3974 if (!valid_ordinal_p(y, NUM2INT(d), NUM2DBL(sg), 3975 &nth, &ry, 3976 &rd, &rjd, 3977 &ns)) 3978 return Qnil; 3979 encode_jd(nth, rjd, &rjd2); 3980 return rjd2; 3981} 3982 3983static VALUE 3984rt__valid_civil_p(VALUE y, VALUE m, VALUE d, VALUE sg) 3985{ 3986 VALUE nth, rjd2; 3987 int ry, rm, rd, rjd, ns; 3988 3989 if (!valid_civil_p(y, NUM2INT(m), NUM2INT(d), NUM2DBL(sg), 3990 &nth, &ry, 3991 &rm, &rd, &rjd, 3992 &ns)) 3993 return Qnil; 3994 encode_jd(nth, rjd, &rjd2); 3995 return rjd2; 3996} 3997 3998static VALUE 3999rt__valid_commercial_p(VALUE y, VALUE w, VALUE d, VALUE sg) 4000{ 4001 VALUE nth, rjd2; 4002 int ry, rw, rd, rjd, ns; 4003 4004 if (!valid_commercial_p(y, NUM2INT(w), NUM2INT(d), NUM2DBL(sg), 4005 &nth, &ry, 4006 &rw, &rd, &rjd, 4007 &ns)) 4008 return Qnil; 4009 encode_jd(nth, rjd, &rjd2); 4010 return rjd2; 4011} 4012 4013static VALUE 4014rt__valid_weeknum_p(VALUE y, VALUE w, VALUE d, VALUE f, VALUE sg) 4015{ 4016 VALUE nth, rjd2; 4017 int ry, rw, rd, rjd, ns; 4018 4019 if (!valid_weeknum_p(y, NUM2INT(w), NUM2INT(d), NUM2INT(f), NUM2DBL(sg), 4020 &nth, &ry, 4021 &rw, &rd, &rjd, 4022 &ns)) 4023 return Qnil; 4024 encode_jd(nth, rjd, &rjd2); 4025 return rjd2; 4026} 4027 4028static VALUE 4029rt__valid_date_frags_p(VALUE hash, VALUE sg) 4030{ 4031 { 4032 VALUE vjd; 4033 4034 if (!NIL_P(vjd = ref_hash("jd"))) { 4035 VALUE jd = rt__valid_jd_p(vjd, sg); 4036 if (!NIL_P(jd)) 4037 return jd; 4038 } 4039 } 4040 4041 { 4042 VALUE year, yday; 4043 4044 if (!NIL_P(yday = ref_hash("yday")) && 4045 !NIL_P(year = ref_hash("year"))) { 4046 VALUE jd = rt__valid_ordinal_p(year, yday, sg); 4047 if (!NIL_P(jd)) 4048 return jd; 4049 } 4050 } 4051 4052 { 4053 VALUE year, mon, mday; 4054 4055 if (!NIL_P(mday = ref_hash("mday")) && 4056 !NIL_P(mon = ref_hash("mon")) && 4057 !NIL_P(year = ref_hash("year"))) { 4058 VALUE jd = rt__valid_civil_p(year, mon, mday, sg); 4059 if (!NIL_P(jd)) 4060 return jd; 4061 } 4062 } 4063 4064 { 4065 VALUE year, week, wday; 4066 4067 wday = ref_hash("cwday"); 4068 if (NIL_P(wday)) { 4069 wday = ref_hash("wday"); 4070 if (!NIL_P(wday)) 4071 if (f_zero_p(wday)) 4072 wday = INT2FIX(7); 4073 } 4074 4075 if (!NIL_P(wday) && 4076 !NIL_P(week = ref_hash("cweek")) && 4077 !NIL_P(year = ref_hash("cwyear"))) { 4078 VALUE jd = rt__valid_commercial_p(year, week, wday, sg); 4079 if (!NIL_P(jd)) 4080 return jd; 4081 } 4082 } 4083 4084 { 4085 VALUE year, week, wday; 4086 4087 wday = ref_hash("wday"); 4088 if (NIL_P(wday)) { 4089 wday = ref_hash("cwday"); 4090 if (!NIL_P(wday)) 4091 if (f_eqeq_p(wday, INT2FIX(7))) 4092 wday = INT2FIX(0); 4093 } 4094 4095 if (!NIL_P(wday) && 4096 !NIL_P(week = ref_hash("wnum0")) && 4097 !NIL_P(year = ref_hash("year"))) { 4098 VALUE jd = rt__valid_weeknum_p(year, week, wday, INT2FIX(0), sg); 4099 if (!NIL_P(jd)) 4100 return jd; 4101 } 4102 } 4103 4104 { 4105 VALUE year, week, wday; 4106 4107 wday = ref_hash("wday"); 4108 if (NIL_P(wday)) 4109 wday = ref_hash("cwday"); 4110 if (!NIL_P(wday)) 4111 wday = f_mod(f_sub(wday, INT2FIX(1)), 4112 INT2FIX(7)); 4113 4114 if (!NIL_P(wday) && 4115 !NIL_P(week = ref_hash("wnum1")) && 4116 !NIL_P(year = ref_hash("year"))) { 4117 VALUE jd = rt__valid_weeknum_p(year, week, wday, INT2FIX(1), sg); 4118 if (!NIL_P(jd)) 4119 return jd; 4120 } 4121 } 4122 return Qnil; 4123} 4124 4125static VALUE 4126d_new_by_frags(VALUE klass, VALUE hash, VALUE sg) 4127{ 4128 VALUE jd; 4129 4130 if (!c_valid_start_p(NUM2DBL(sg))) { 4131 sg = INT2FIX(DEFAULT_SG); 4132 rb_warning("invalid start is ignored"); 4133 } 4134 4135 if (NIL_P(hash)) 4136 rb_raise(rb_eArgError, "invalid date"); 4137 4138 if (NIL_P(ref_hash("jd")) && 4139 NIL_P(ref_hash("yday")) && 4140 !NIL_P(ref_hash("year")) && 4141 !NIL_P(ref_hash("mon")) && 4142 !NIL_P(ref_hash("mday"))) 4143 jd = rt__valid_civil_p(ref_hash("year"), 4144 ref_hash("mon"), 4145 ref_hash("mday"), sg); 4146 else { 4147 hash = rt_rewrite_frags(hash); 4148 hash = rt_complete_frags(klass, hash); 4149 jd = rt__valid_date_frags_p(hash, sg); 4150 } 4151 4152 if (NIL_P(jd)) 4153 rb_raise(rb_eArgError, "invalid date"); 4154 { 4155 VALUE nth; 4156 int rjd; 4157 4158 decode_jd(jd, &nth, &rjd); 4159 return d_simple_new_internal(klass, 4160 nth, rjd, 4161 NUM2DBL(sg), 4162 0, 0, 0, 4163 HAVE_JD); 4164 } 4165} 4166 4167VALUE date__strptime(const char *str, size_t slen, 4168 const char *fmt, size_t flen, VALUE hash); 4169 4170static VALUE 4171date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, 4172 const char *default_fmt) 4173{ 4174 VALUE vstr, vfmt, hash; 4175 const char *str, *fmt; 4176 size_t slen, flen; 4177 4178 rb_scan_args(argc, argv, "11", &vstr, &vfmt); 4179 4180 StringValue(vstr); 4181 if (!rb_enc_str_asciicompat_p(vstr)) 4182 rb_raise(rb_eArgError, 4183 "string should have ASCII compatible encoding"); 4184 str = RSTRING_PTR(vstr); 4185 slen = RSTRING_LEN(vstr); 4186 if (argc < 2) { 4187 fmt = default_fmt; 4188 flen = strlen(default_fmt); 4189 } 4190 else { 4191 StringValue(vfmt); 4192 if (!rb_enc_str_asciicompat_p(vfmt)) 4193 rb_raise(rb_eArgError, 4194 "format should have ASCII compatible encoding"); 4195 fmt = RSTRING_PTR(vfmt); 4196 flen = RSTRING_LEN(vfmt); 4197 } 4198 hash = rb_hash_new(); 4199 if (NIL_P(date__strptime(str, slen, fmt, flen, hash))) 4200 return Qnil; 4201 4202 { 4203 VALUE zone = ref_hash("zone"); 4204 VALUE left = ref_hash("leftover"); 4205 4206 if (!NIL_P(zone)) { 4207 rb_enc_copy(zone, vstr); 4208 OBJ_INFECT(zone, vstr); 4209 set_hash("zone", zone); 4210 } 4211 if (!NIL_P(left)) { 4212 rb_enc_copy(left, vstr); 4213 OBJ_INFECT(left, vstr); 4214 set_hash("leftover", left); 4215 } 4216 } 4217 4218 return hash; 4219} 4220 4221/* 4222 * call-seq: 4223 * Date._strptime(string[, format='%F']) -> hash 4224 * 4225 * Parses the given representation of date and time with the given 4226 * template, and returns a hash of parsed elements. _strptime does 4227 * not support specification of flags and width unlike strftime. 4228 * 4229 * Date._strptime('2001-02-03', '%Y-%m-%d') 4230 * #=> {:year=>2001, :mon=>2, :mday=>3} 4231 * 4232 * See also strptime(3) and strftime. 4233 */ 4234static VALUE 4235date_s__strptime(int argc, VALUE *argv, VALUE klass) 4236{ 4237 return date_s__strptime_internal(argc, argv, klass, "%F"); 4238} 4239 4240/* 4241 * call-seq: 4242 * Date.strptime([string='-4712-01-01'[, format='%F'[, start=ITALY]]]) -> date 4243 * 4244 * Parses the given representation of date and time with the given 4245 * template, and creates a date object. strptime does not support 4246 * specification of flags and width unlike strftime. 4247 * 4248 * Date.strptime('2001-02-03', '%Y-%m-%d') #=> #<Date: 2001-02-03 ...> 4249 * Date.strptime('03-02-2001', '%d-%m-%Y') #=> #<Date: 2001-02-03 ...> 4250 * Date.strptime('2001-034', '%Y-%j') #=> #<Date: 2001-02-03 ...> 4251 * Date.strptime('2001-W05-6', '%G-W%V-%u') #=> #<Date: 2001-02-03 ...> 4252 * Date.strptime('2001 04 6', '%Y %U %w') #=> #<Date: 2001-02-03 ...> 4253 * Date.strptime('2001 05 6', '%Y %W %u') #=> #<Date: 2001-02-03 ...> 4254 * Date.strptime('sat3feb01', '%a%d%b%y') #=> #<Date: 2001-02-03 ...> 4255 * 4256 * See also strptime(3) and strftime. 4257 */ 4258static VALUE 4259date_s_strptime(int argc, VALUE *argv, VALUE klass) 4260{ 4261 VALUE str, fmt, sg; 4262 4263 rb_scan_args(argc, argv, "03", &str, &fmt, &sg); 4264 4265 switch (argc) { 4266 case 0: 4267 str = rb_str_new2("-4712-01-01"); 4268 case 1: 4269 fmt = rb_str_new2("%F"); 4270 case 2: 4271 sg = INT2FIX(DEFAULT_SG); 4272 } 4273 4274 { 4275 VALUE argv2[2], hash; 4276 4277 argv2[0] = str; 4278 argv2[1] = fmt; 4279 hash = date_s__strptime(2, argv2, klass); 4280 return d_new_by_frags(klass, hash, sg); 4281 } 4282} 4283 4284VALUE date__parse(VALUE str, VALUE comp); 4285 4286static VALUE 4287date_s__parse_internal(int argc, VALUE *argv, VALUE klass) 4288{ 4289 VALUE vstr, vcomp, hash; 4290 4291 rb_scan_args(argc, argv, "11", &vstr, &vcomp); 4292 StringValue(vstr); 4293 if (!rb_enc_str_asciicompat_p(vstr)) 4294 rb_raise(rb_eArgError, 4295 "string should have ASCII compatible encoding"); 4296 if (argc < 2) 4297 vcomp = Qtrue; 4298 4299 hash = date__parse(vstr, vcomp); 4300 4301 { 4302 VALUE zone = ref_hash("zone"); 4303 4304 if (!NIL_P(zone)) { 4305 rb_enc_copy(zone, vstr); 4306 OBJ_INFECT(zone, vstr); 4307 set_hash("zone", zone); 4308 } 4309 } 4310 4311 return hash; 4312} 4313 4314/* 4315 * call-seq: 4316 * Date._parse(string[, comp=true]) -> hash 4317 * 4318 * Parses the given representation of date and time, and returns a 4319 * hash of parsed elements. This method does not function as a 4320 * validator. 4321 * 4322 * If the optional second argument is true and the detected year is in 4323 * the range "00" to "99", considers the year a 2-digit form and makes 4324 * it full. 4325 * 4326 * Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3} 4327 */ 4328static VALUE 4329date_s__parse(int argc, VALUE *argv, VALUE klass) 4330{ 4331 return date_s__parse_internal(argc, argv, klass); 4332} 4333 4334/* 4335 * call-seq: 4336 * Date.parse(string='-4712-01-01'[, comp=true[, start=ITALY]]) -> date 4337 * 4338 * Parses the given representation of date and time, and creates a 4339 * date object. This method does not function as a validator. 4340 * 4341 * If the optional second argument is true and the detected year is in 4342 * the range "00" to "99", considers the year a 2-digit form and makes 4343 * it full. 4344 * 4345 * Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...> 4346 * Date.parse('20010203') #=> #<Date: 2001-02-03 ...> 4347 * Date.parse('3rd Feb 2001') #=> #<Date: 2001-02-03 ...> 4348 */ 4349static VALUE 4350date_s_parse(int argc, VALUE *argv, VALUE klass) 4351{ 4352 VALUE str, comp, sg; 4353 4354 rb_scan_args(argc, argv, "03", &str, &comp, &sg); 4355 4356 switch (argc) { 4357 case 0: 4358 str = rb_str_new2("-4712-01-01"); 4359 case 1: 4360 comp = Qtrue; 4361 case 2: 4362 sg = INT2FIX(DEFAULT_SG); 4363 } 4364 4365 { 4366 VALUE argv2[2], hash; 4367 4368 argv2[0] = str; 4369 argv2[1] = comp; 4370 hash = date_s__parse(2, argv2, klass); 4371 return d_new_by_frags(klass, hash, sg); 4372 } 4373} 4374 4375VALUE date__iso8601(VALUE); 4376VALUE date__rfc3339(VALUE); 4377VALUE date__xmlschema(VALUE); 4378VALUE date__rfc2822(VALUE); 4379VALUE date__httpdate(VALUE); 4380VALUE date__jisx0301(VALUE); 4381 4382/* 4383 * call-seq: 4384 * Date._iso8601(string) -> hash 4385 * 4386 * Returns a hash of parsed elements. 4387 */ 4388static VALUE 4389date_s__iso8601(VALUE klass, VALUE str) 4390{ 4391 return date__iso8601(str); 4392} 4393 4394/* 4395 * call-seq: 4396 * Date.iso8601(string='-4712-01-01'[, start=ITALY]) -> date 4397 * 4398 * Creates a new Date object by parsing from a string according to 4399 * some typical ISO 8601 formats. 4400 * 4401 * Date.iso8601('2001-02-03') #=> #<Date: 2001-02-03 ...> 4402 * Date.iso8601('20010203') #=> #<Date: 2001-02-03 ...> 4403 * Date.iso8601('2001-W05-6') #=> #<Date: 2001-02-03 ...> 4404 */ 4405static VALUE 4406date_s_iso8601(int argc, VALUE *argv, VALUE klass) 4407{ 4408 VALUE str, sg; 4409 4410 rb_scan_args(argc, argv, "02", &str, &sg); 4411 4412 switch (argc) { 4413 case 0: 4414 str = rb_str_new2("-4712-01-01"); 4415 case 1: 4416 sg = INT2FIX(DEFAULT_SG); 4417 } 4418 4419 { 4420 VALUE hash = date_s__iso8601(klass, str); 4421 return d_new_by_frags(klass, hash, sg); 4422 } 4423} 4424 4425/* 4426 * call-seq: 4427 * Date._rfc3339(string) -> hash 4428 * 4429 * Returns a hash of parsed elements. 4430 */ 4431static VALUE 4432date_s__rfc3339(VALUE klass, VALUE str) 4433{ 4434 return date__rfc3339(str); 4435} 4436 4437/* 4438 * call-seq: 4439 * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> date 4440 * 4441 * Creates a new Date object by parsing from a string according to 4442 * some typical RFC 3339 formats. 4443 * 4444 * Date.rfc3339('2001-02-03T04:05:06+07:00') #=> #<Date: 2001-02-03 ...> 4445 */ 4446static VALUE 4447date_s_rfc3339(int argc, VALUE *argv, VALUE klass) 4448{ 4449 VALUE str, sg; 4450 4451 rb_scan_args(argc, argv, "02", &str, &sg); 4452 4453 switch (argc) { 4454 case 0: 4455 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 4456 case 1: 4457 sg = INT2FIX(DEFAULT_SG); 4458 } 4459 4460 { 4461 VALUE hash = date_s__rfc3339(klass, str); 4462 return d_new_by_frags(klass, hash, sg); 4463 } 4464} 4465 4466/* 4467 * call-seq: 4468 * Date._xmlschema(string) -> hash 4469 * 4470 * Returns a hash of parsed elements. 4471 */ 4472static VALUE 4473date_s__xmlschema(VALUE klass, VALUE str) 4474{ 4475 return date__xmlschema(str); 4476} 4477 4478/* 4479 * call-seq: 4480 * Date.xmlschema(string='-4712-01-01'[, start=ITALY]) -> date 4481 * 4482 * Creates a new Date object by parsing from a string according to 4483 * some typical XML Schema formats. 4484 * 4485 * Date.xmlschema('2001-02-03') #=> #<Date: 2001-02-03 ...> 4486 */ 4487static VALUE 4488date_s_xmlschema(int argc, VALUE *argv, VALUE klass) 4489{ 4490 VALUE str, sg; 4491 4492 rb_scan_args(argc, argv, "02", &str, &sg); 4493 4494 switch (argc) { 4495 case 0: 4496 str = rb_str_new2("-4712-01-01"); 4497 case 1: 4498 sg = INT2FIX(DEFAULT_SG); 4499 } 4500 4501 { 4502 VALUE hash = date_s__xmlschema(klass, str); 4503 return d_new_by_frags(klass, hash, sg); 4504 } 4505} 4506 4507/* 4508 * call-seq: 4509 * Date._rfc2822(string) -> hash 4510 * Date._rfc822(string) -> hash 4511 * 4512 * Returns a hash of parsed elements. 4513 */ 4514static VALUE 4515date_s__rfc2822(VALUE klass, VALUE str) 4516{ 4517 return date__rfc2822(str); 4518} 4519 4520/* 4521 * call-seq: 4522 * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> date 4523 * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> date 4524 * 4525 * Creates a new Date object by parsing from a string according to 4526 * some typical RFC 2822 formats. 4527 * 4528 * Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000') 4529 * #=> #<Date: 2001-02-03 ...> 4530 */ 4531static VALUE 4532date_s_rfc2822(int argc, VALUE *argv, VALUE klass) 4533{ 4534 VALUE str, sg; 4535 4536 rb_scan_args(argc, argv, "02", &str, &sg); 4537 4538 switch (argc) { 4539 case 0: 4540 str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000"); 4541 case 1: 4542 sg = INT2FIX(DEFAULT_SG); 4543 } 4544 4545 { 4546 VALUE hash = date_s__rfc2822(klass, str); 4547 return d_new_by_frags(klass, hash, sg); 4548 } 4549} 4550 4551/* 4552 * call-seq: 4553 * Date._httpdate(string) -> hash 4554 * 4555 * Returns a hash of parsed elements. 4556 */ 4557static VALUE 4558date_s__httpdate(VALUE klass, VALUE str) 4559{ 4560 return date__httpdate(str); 4561} 4562 4563/* 4564 * call-seq: 4565 * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY]) -> date 4566 * 4567 * Creates a new Date object by parsing from a string according to 4568 * some RFC 2616 format. 4569 * 4570 * Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT') 4571 * #=> #<Date: 2001-02-03 ...> 4572 */ 4573static VALUE 4574date_s_httpdate(int argc, VALUE *argv, VALUE klass) 4575{ 4576 VALUE str, sg; 4577 4578 rb_scan_args(argc, argv, "02", &str, &sg); 4579 4580 switch (argc) { 4581 case 0: 4582 str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT"); 4583 case 1: 4584 sg = INT2FIX(DEFAULT_SG); 4585 } 4586 4587 { 4588 VALUE hash = date_s__httpdate(klass, str); 4589 return d_new_by_frags(klass, hash, sg); 4590 } 4591} 4592 4593/* 4594 * call-seq: 4595 * Date._jisx0301(string) -> hash 4596 * 4597 * Returns a hash of parsed elements. 4598 */ 4599static VALUE 4600date_s__jisx0301(VALUE klass, VALUE str) 4601{ 4602 return date__jisx0301(str); 4603} 4604 4605/* 4606 * call-seq: 4607 * Date.jisx0301(string='-4712-01-01'[, start=ITALY]) -> date 4608 * 4609 * Creates a new Date object by parsing from a string according to 4610 * some typical JIS X 0301 formats. 4611 * 4612 * Date.jisx0301('H13.02.03') #=> #<Date: 2001-02-03 ...> 4613 */ 4614static VALUE 4615date_s_jisx0301(int argc, VALUE *argv, VALUE klass) 4616{ 4617 VALUE str, sg; 4618 4619 rb_scan_args(argc, argv, "02", &str, &sg); 4620 4621 switch (argc) { 4622 case 0: 4623 str = rb_str_new2("-4712-01-01"); 4624 case 1: 4625 sg = INT2FIX(DEFAULT_SG); 4626 } 4627 4628 { 4629 VALUE hash = date_s__jisx0301(klass, str); 4630 return d_new_by_frags(klass, hash, sg); 4631 } 4632} 4633 4634static VALUE 4635dup_obj(VALUE self) 4636{ 4637 get_d1a(self); 4638 4639 if (simple_dat_p(adat)) { 4640 VALUE new = d_lite_s_alloc_simple(rb_obj_class(self)); 4641 { 4642 get_d1b(new); 4643 bdat->s = adat->s; 4644 return new; 4645 } 4646 } 4647 else { 4648 VALUE new = d_lite_s_alloc_complex(rb_obj_class(self)); 4649 { 4650 get_d1b(new); 4651 bdat->c = adat->c; 4652 return new; 4653 } 4654 } 4655} 4656 4657static VALUE 4658dup_obj_as_complex(VALUE self) 4659{ 4660 get_d1a(self); 4661 4662 if (simple_dat_p(adat)) { 4663 VALUE new = d_lite_s_alloc_complex(rb_obj_class(self)); 4664 { 4665 get_d1b(new); 4666 copy_simple_to_complex(&bdat->c, &adat->s); 4667 bdat->c.flags |= HAVE_DF | COMPLEX_DAT; 4668 return new; 4669 } 4670 } 4671 else { 4672 VALUE new = d_lite_s_alloc_complex(rb_obj_class(self)); 4673 { 4674 get_d1b(new); 4675 bdat->c = adat->c; 4676 return new; 4677 } 4678 } 4679} 4680 4681#define val2off(vof,iof) \ 4682{\ 4683 if (!offset_to_sec(vof, &iof)) {\ 4684 iof = 0;\ 4685 rb_warning("invalid offset is ignored");\ 4686 }\ 4687} 4688 4689#ifndef NDEBUG 4690static VALUE 4691d_lite_initialize(int argc, VALUE *argv, VALUE self) 4692{ 4693 VALUE jd, vjd, vdf, sf, vsf, vof, vsg; 4694 int df, of; 4695 double sg; 4696 4697 rb_check_frozen(self); 4698 rb_check_trusted(self); 4699 4700 rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg); 4701 4702 jd = INT2FIX(0); 4703 df = 0; 4704 sf = INT2FIX(0); 4705 of = 0; 4706 sg = DEFAULT_SG; 4707 4708 switch (argc) { 4709 case 5: 4710 val2sg(vsg, sg); 4711 case 4: 4712 val2off(vof, of); 4713 case 3: 4714 sf = vsf; 4715 if (f_lt_p(sf, INT2FIX(0)) || 4716 f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) 4717 rb_raise(rb_eArgError, "invalid second fraction"); 4718 case 2: 4719 df = NUM2INT(vdf); 4720 if (df < 0 || df >= DAY_IN_SECONDS) 4721 rb_raise(rb_eArgError, "invalid day fraction"); 4722 case 1: 4723 jd = vjd; 4724 } 4725 4726 { 4727 VALUE nth; 4728 int rjd; 4729 4730 get_d1(self); 4731 4732 decode_jd(jd, &nth, &rjd); 4733 if (!df && f_zero_p(sf) && !of) { 4734 set_to_simple(&dat->s, nth, rjd, sg, 0, 0, 0, HAVE_JD); 4735 } 4736 else { 4737 if (!complex_dat_p(dat)) 4738 rb_raise(rb_eArgError, 4739 "cannot load complex into simple"); 4740 4741 set_to_complex(&dat->c, nth, rjd, df, sf, of, sg, 4742 0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF | COMPLEX_DAT); 4743 } 4744 } 4745 return self; 4746} 4747#endif 4748 4749/* :nodoc: */ 4750static VALUE 4751d_lite_initialize_copy(VALUE copy, VALUE date) 4752{ 4753 rb_check_frozen(copy); 4754 rb_check_trusted(copy); 4755 4756 if (copy == date) 4757 return copy; 4758 { 4759 get_d2(copy, date); 4760 if (simple_dat_p(bdat)) { 4761 adat->s = bdat->s; 4762 adat->s.flags &= ~COMPLEX_DAT; 4763 } 4764 else { 4765 if (!complex_dat_p(adat)) 4766 rb_raise(rb_eArgError, 4767 "cannot load complex into simple"); 4768 4769 adat->c = bdat->c; 4770 adat->c.flags |= COMPLEX_DAT; 4771 } 4772 } 4773 return copy; 4774} 4775 4776#ifndef NDEBUG 4777static VALUE 4778d_lite_fill(VALUE self) 4779{ 4780 get_d1(self); 4781 4782 if (simple_dat_p(dat)) { 4783 get_s_jd(dat); 4784 get_s_civil(dat); 4785 } 4786 else { 4787 get_c_jd(dat); 4788 get_c_civil(dat); 4789 get_c_df(dat); 4790 get_c_time(dat); 4791 } 4792 return self; 4793} 4794#endif 4795 4796/* 4797 * call-seq: 4798 * d.ajd -> rational 4799 * 4800 * Returns the astronomical Julian day number. This is a fractional 4801 * number, which is not adjusted by the offset. 4802 * 4803 * DateTime.new(2001,2,3,4,5,6,'+7').ajd #=> (11769328217/4800) 4804 * DateTime.new(2001,2,2,14,5,6,'-7').ajd #=> (11769328217/4800) 4805 */ 4806static VALUE 4807d_lite_ajd(VALUE self) 4808{ 4809 get_d1(self); 4810 return m_ajd(dat); 4811} 4812 4813/* 4814 * call-seq: 4815 * d.amjd -> rational 4816 * 4817 * Returns the astronomical modified Julian day number. This is 4818 * a fractional number, which is not adjusted by the offset. 4819 * 4820 * DateTime.new(2001,2,3,4,5,6,'+7').amjd #=> (249325817/4800) 4821 * DateTime.new(2001,2,2,14,5,6,'-7').amjd #=> (249325817/4800) 4822 */ 4823static VALUE 4824d_lite_amjd(VALUE self) 4825{ 4826 get_d1(self); 4827 return m_amjd(dat); 4828} 4829 4830/* 4831 * call-seq: 4832 * d.jd -> integer 4833 * 4834 * Returns the Julian day number. This is a whole number, which is 4835 * adjusted by the offset as the local time. 4836 * 4837 * DateTime.new(2001,2,3,4,5,6,'+7').jd #=> 2451944 4838 * DateTime.new(2001,2,3,4,5,6,'-7').jd #=> 2451944 4839 */ 4840static VALUE 4841d_lite_jd(VALUE self) 4842{ 4843 get_d1(self); 4844 return m_real_local_jd(dat); 4845} 4846 4847/* 4848 * call-seq: 4849 * d.mjd -> integer 4850 * 4851 * Returns the modified Julian day number. This is a whole number, 4852 * which is adjusted by the offset as the local time. 4853 * 4854 * DateTime.new(2001,2,3,4,5,6,'+7').mjd #=> 51943 4855 * DateTime.new(2001,2,3,4,5,6,'-7').mjd #=> 51943 4856 */ 4857static VALUE 4858d_lite_mjd(VALUE self) 4859{ 4860 get_d1(self); 4861 return f_sub(m_real_local_jd(dat), INT2FIX(2400001)); 4862} 4863 4864/* 4865 * call-seq: 4866 * d.ld -> integer 4867 * 4868 * Returns the Lilian day number. This is a whole number, which is 4869 * adjusted by the offset as the local time. 4870 * 4871 * Date.new(2001,2,3).ld #=> 152784 4872 */ 4873static VALUE 4874d_lite_ld(VALUE self) 4875{ 4876 get_d1(self); 4877 return f_sub(m_real_local_jd(dat), INT2FIX(2299160)); 4878} 4879 4880/* 4881 * call-seq: 4882 * d.year -> integer 4883 * 4884 * Returns the year. 4885 * 4886 * Date.new(2001,2,3).year #=> 2001 4887 * (Date.new(1,1,1) - 1).year #=> 0 4888 */ 4889static VALUE 4890d_lite_year(VALUE self) 4891{ 4892 get_d1(self); 4893 return m_real_year(dat); 4894} 4895 4896/* 4897 * call-seq: 4898 * d.yday -> fixnum 4899 * 4900 * Returns the day of the year (1-366). 4901 * 4902 * Date.new(2001,2,3).yday #=> 34 4903 */ 4904static VALUE 4905d_lite_yday(VALUE self) 4906{ 4907 get_d1(self); 4908 return INT2FIX(m_yday(dat)); 4909} 4910 4911/* 4912 * call-seq: 4913 * d.mon -> fixnum 4914 * d.month -> fixnum 4915 * 4916 * Returns the month (1-12). 4917 * 4918 * Date.new(2001,2,3).mon #=> 2 4919 */ 4920static VALUE 4921d_lite_mon(VALUE self) 4922{ 4923 get_d1(self); 4924 return INT2FIX(m_mon(dat)); 4925} 4926 4927/* 4928 * call-seq: 4929 * d.mday -> fixnum 4930 * d.day -> fixnum 4931 * 4932 * Returns the day of the month (1-31). 4933 * 4934 * Date.new(2001,2,3).mday #=> 3 4935 */ 4936static VALUE 4937d_lite_mday(VALUE self) 4938{ 4939 get_d1(self); 4940 return INT2FIX(m_mday(dat)); 4941} 4942 4943/* 4944 * call-seq: 4945 * d.day_fraction -> rational 4946 * 4947 * Returns the fractional part of the day. 4948 * 4949 * DateTime.new(2001,2,3,12).day_fraction #=> (1/2) 4950 */ 4951static VALUE 4952d_lite_day_fraction(VALUE self) 4953{ 4954 get_d1(self); 4955 if (simple_dat_p(dat)) 4956 return INT2FIX(0); 4957 return m_fr(dat); 4958} 4959 4960/* 4961 * call-seq: 4962 * d.cwyear -> integer 4963 * 4964 * Returns the calendar week based year. 4965 * 4966 * Date.new(2001,2,3).cwyear #=> 2001 4967 * Date.new(2000,1,1).cwyear #=> 1999 4968 */ 4969static VALUE 4970d_lite_cwyear(VALUE self) 4971{ 4972 get_d1(self); 4973 return m_real_cwyear(dat); 4974} 4975 4976/* 4977 * call-seq: 4978 * d.cweek -> fixnum 4979 * 4980 * Returns the calendar week number (1-53). 4981 * 4982 * Date.new(2001,2,3).cweek #=> 5 4983 */ 4984static VALUE 4985d_lite_cweek(VALUE self) 4986{ 4987 get_d1(self); 4988 return INT2FIX(m_cweek(dat)); 4989} 4990 4991/* 4992 * call-seq: 4993 * d.cwday -> fixnum 4994 * 4995 * Returns the day of calendar week (1-7, Monday is 1). 4996 * 4997 * Date.new(2001,2,3).cwday #=> 6 4998 */ 4999static VALUE 5000d_lite_cwday(VALUE self) 5001{ 5002 get_d1(self); 5003 return INT2FIX(m_cwday(dat)); 5004} 5005 5006#ifndef NDEBUG 5007static VALUE 5008d_lite_wnum0(VALUE self) 5009{ 5010 get_d1(self); 5011 return INT2FIX(m_wnum0(dat)); 5012} 5013 5014static VALUE 5015d_lite_wnum1(VALUE self) 5016{ 5017 get_d1(self); 5018 return INT2FIX(m_wnum1(dat)); 5019} 5020#endif 5021 5022/* 5023 * call-seq: 5024 * d.wday -> fixnum 5025 * 5026 * Returns the day of week (0-6, Sunday is zero). 5027 * 5028 * Date.new(2001,2,3).wday #=> 6 5029 */ 5030static VALUE 5031d_lite_wday(VALUE self) 5032{ 5033 get_d1(self); 5034 return INT2FIX(m_wday(dat)); 5035} 5036 5037/* 5038 * call-seq: 5039 * d.sunday? -> bool 5040 * 5041 * Returns true if the date is Sunday. 5042 */ 5043static VALUE 5044d_lite_sunday_p(VALUE self) 5045{ 5046 get_d1(self); 5047 return f_boolcast(m_wday(dat) == 0); 5048} 5049 5050/* 5051 * call-seq: 5052 * d.monday? -> bool 5053 * 5054 * Returns true if the date is Monday. 5055 */ 5056static VALUE 5057d_lite_monday_p(VALUE self) 5058{ 5059 get_d1(self); 5060 return f_boolcast(m_wday(dat) == 1); 5061} 5062 5063/* 5064 * call-seq: 5065 * d.tuesday? -> bool 5066 * 5067 * Returns true if the date is Tuesday. 5068 */ 5069static VALUE 5070d_lite_tuesday_p(VALUE self) 5071{ 5072 get_d1(self); 5073 return f_boolcast(m_wday(dat) == 2); 5074} 5075 5076/* 5077 * call-seq: 5078 * d.wednesday? -> bool 5079 * 5080 * Returns true if the date is Wednesday. 5081 */ 5082static VALUE 5083d_lite_wednesday_p(VALUE self) 5084{ 5085 get_d1(self); 5086 return f_boolcast(m_wday(dat) == 3); 5087} 5088 5089/* 5090 * call-seq: 5091 * d.thursday? -> bool 5092 * 5093 * Returns true if the date is Thursday. 5094 */ 5095static VALUE 5096d_lite_thursday_p(VALUE self) 5097{ 5098 get_d1(self); 5099 return f_boolcast(m_wday(dat) == 4); 5100} 5101 5102/* 5103 * call-seq: 5104 * d.friday? -> bool 5105 * 5106 * Returns true if the date is Friday. 5107 */ 5108static VALUE 5109d_lite_friday_p(VALUE self) 5110{ 5111 get_d1(self); 5112 return f_boolcast(m_wday(dat) == 5); 5113} 5114 5115/* 5116 * call-seq: 5117 * d.saturday? -> bool 5118 * 5119 * Returns true if the date is Saturday. 5120 */ 5121static VALUE 5122d_lite_saturday_p(VALUE self) 5123{ 5124 get_d1(self); 5125 return f_boolcast(m_wday(dat) == 6); 5126} 5127 5128#ifndef NDEBUG 5129static VALUE 5130d_lite_nth_kday_p(VALUE self, VALUE n, VALUE k) 5131{ 5132 int rjd, ns; 5133 5134 get_d1(self); 5135 5136 if (NUM2INT(k) != m_wday(dat)) 5137 return Qfalse; 5138 5139 c_nth_kday_to_jd(m_year(dat), m_mon(dat), 5140 NUM2INT(n), NUM2INT(k), m_virtual_sg(dat), /* !=m_sg() */ 5141 &rjd, &ns); 5142 if (m_local_jd(dat) != rjd) 5143 return Qfalse; 5144 return Qtrue; 5145} 5146#endif 5147 5148/* 5149 * call-seq: 5150 * d.hour -> fixnum 5151 * 5152 * Returns the hour (0-23). 5153 * 5154 * DateTime.new(2001,2,3,4,5,6).hour #=> 4 5155 */ 5156static VALUE 5157d_lite_hour(VALUE self) 5158{ 5159 get_d1(self); 5160 return INT2FIX(m_hour(dat)); 5161} 5162 5163/* 5164 * call-seq: 5165 * d.min -> fixnum 5166 * d.minute -> fixnum 5167 * 5168 * Returns the minute (0-59). 5169 * 5170 * DateTime.new(2001,2,3,4,5,6).min #=> 5 5171 */ 5172static VALUE 5173d_lite_min(VALUE self) 5174{ 5175 get_d1(self); 5176 return INT2FIX(m_min(dat)); 5177} 5178 5179/* 5180 * call-seq: 5181 * d.sec -> fixnum 5182 * d.second -> fixnum 5183 * 5184 * Returns the second (0-59). 5185 * 5186 * DateTime.new(2001,2,3,4,5,6).sec #=> 6 5187 */ 5188static VALUE 5189d_lite_sec(VALUE self) 5190{ 5191 get_d1(self); 5192 return INT2FIX(m_sec(dat)); 5193} 5194 5195/* 5196 * call-seq: 5197 * d.sec_fraction -> rational 5198 * d.second_fraction -> rational 5199 * 5200 * Returns the fractional part of the second. 5201 * 5202 * DateTime.new(2001,2,3,4,5,6.5).sec_fraction #=> (1/2) 5203 */ 5204static VALUE 5205d_lite_sec_fraction(VALUE self) 5206{ 5207 get_d1(self); 5208 return m_sf_in_sec(dat); 5209} 5210 5211/* 5212 * call-seq: 5213 * d.offset -> rational 5214 * 5215 * Returns the offset. 5216 * 5217 * DateTime.parse('04pm+0730').offset #=> (5/16) 5218 */ 5219static VALUE 5220d_lite_offset(VALUE self) 5221{ 5222 get_d1(self); 5223 return m_of_in_day(dat); 5224} 5225 5226/* 5227 * call-seq: 5228 * d.zone -> string 5229 * 5230 * Returns the timezone. 5231 * 5232 * DateTime.parse('04pm+0730').zone #=> "+07:30" 5233 */ 5234static VALUE 5235d_lite_zone(VALUE self) 5236{ 5237 get_d1(self); 5238 return m_zone(dat); 5239} 5240 5241/* 5242 * call-seq: 5243 * d.julian? -> bool 5244 * 5245 * Retruns true if the date is before the day of calendar reform. 5246 * 5247 * Date.new(1582,10,15).julian? #=> false 5248 * (Date.new(1582,10,15) - 1).julian? #=> true 5249 */ 5250static VALUE 5251d_lite_julian_p(VALUE self) 5252{ 5253 get_d1(self); 5254 return f_boolcast(m_julian_p(dat)); 5255} 5256 5257/* 5258 * call-seq: 5259 * d.gregorian? -> bool 5260 * 5261 * Retunrs true if the date is on or after the day of calendar reform. 5262 * 5263 * Date.new(1582,10,15).gregorian? #=> true 5264 * (Date.new(1582,10,15) - 1).gregorian? #=> false 5265 */ 5266static VALUE 5267d_lite_gregorian_p(VALUE self) 5268{ 5269 get_d1(self); 5270 return f_boolcast(m_gregorian_p(dat)); 5271} 5272 5273/* 5274 * call-seq: 5275 * d.leap? -> bool 5276 * 5277 * Returns true if the year is a leap year. 5278 * 5279 * Date.new(2000).leap? #=> true 5280 * Date.new(2001).leap? #=> false 5281 */ 5282static VALUE 5283d_lite_leap_p(VALUE self) 5284{ 5285 int rjd, ns, ry, rm, rd; 5286 5287 get_d1(self); 5288 if (m_gregorian_p(dat)) 5289 return f_boolcast(c_gregorian_leap_p(m_year(dat))); 5290 5291 c_civil_to_jd(m_year(dat), 3, 1, m_virtual_sg(dat), 5292 &rjd, &ns); 5293 c_jd_to_civil(rjd - 1, m_virtual_sg(dat), &ry, &rm, &rd); 5294 return f_boolcast(rd == 29); 5295} 5296 5297/* 5298 * call-seq: 5299 * d.start -> float 5300 * 5301 * Returns the Julian day number denoting the day of calendar reform. 5302 * 5303 * Date.new(2001,2,3).start #=> 2299161.0 5304 * Date.new(2001,2,3,Date::GREGORIAN).start #=> -Infinity 5305 */ 5306static VALUE 5307d_lite_start(VALUE self) 5308{ 5309 get_d1(self); 5310 return DBL2NUM(m_sg(dat)); 5311} 5312 5313static void 5314clear_civil(union DateData *x) 5315{ 5316 if (simple_dat_p(x)) { 5317 x->s.year = 0; 5318#ifndef USE_PACK 5319 x->s.mon = 0; 5320 x->s.mday = 0; 5321#else 5322 x->s.pc = 0; 5323#endif 5324 x->s.flags &= ~HAVE_CIVIL; 5325 } 5326 else { 5327 x->c.year = 0; 5328#ifndef USE_PACK 5329 x->c.mon = 0; 5330 x->c.mday = 0; 5331 x->c.hour = 0; 5332 x->c.min = 0; 5333 x->c.sec = 0; 5334#else 5335 x->c.pc = 0; 5336#endif 5337 x->c.flags &= ~(HAVE_CIVIL | HAVE_TIME); 5338 } 5339} 5340 5341static void 5342set_sg(union DateData *x, double sg) 5343{ 5344 if (simple_dat_p(x)) { 5345 get_s_jd(x); 5346 clear_civil(x); 5347 x->s.sg = (date_sg_t)sg; 5348 } else { 5349 get_c_jd(x); 5350 get_c_df(x); 5351 clear_civil(x); 5352 x->c.sg = (date_sg_t)sg; 5353 } 5354} 5355 5356static VALUE 5357dup_obj_with_new_start(VALUE obj, double sg) 5358{ 5359 volatile VALUE dup = dup_obj(obj); 5360 { 5361 get_d1(dup); 5362 set_sg(dat, sg); 5363 } 5364 return dup; 5365} 5366 5367/* 5368 * call-seq: 5369 * d.new_start([start=Date::ITALY]) -> date 5370 * 5371 * Duplicates self and resets its the day of calendar reform. 5372 * 5373 * d = Date.new(1582,10,15) 5374 * d.new_start(Date::JULIAN) #=> #<Date: 1582-10-05 ...> 5375 */ 5376static VALUE 5377d_lite_new_start(int argc, VALUE *argv, VALUE self) 5378{ 5379 VALUE vsg; 5380 double sg; 5381 5382 rb_scan_args(argc, argv, "01", &vsg); 5383 5384 sg = DEFAULT_SG; 5385 if (argc >= 1) 5386 val2sg(vsg, sg); 5387 5388 return dup_obj_with_new_start(self, sg); 5389} 5390 5391/* 5392 * call-seq: 5393 * d.italy -> date 5394 * 5395 * This method is equivalent to new_start(Date::ITALY). 5396 */ 5397static VALUE 5398d_lite_italy(VALUE self) 5399{ 5400 return dup_obj_with_new_start(self, ITALY); 5401} 5402 5403/* 5404 * call-seq: 5405 * d.england -> date 5406 * 5407 * This method is equivalent to new_start(Date::ENGLAND). 5408 */ 5409static VALUE 5410d_lite_england(VALUE self) 5411{ 5412 return dup_obj_with_new_start(self, ENGLAND); 5413} 5414 5415/* 5416 * call-seq: 5417 * d.julian -> date 5418 * 5419 * This method is equivalent to new_start(Date::JULIAN). 5420 */ 5421static VALUE 5422d_lite_julian(VALUE self) 5423{ 5424 return dup_obj_with_new_start(self, JULIAN); 5425} 5426 5427/* 5428 * call-seq: 5429 * d.gregorian -> date 5430 * 5431 * This method is equivalent to new_start(Date::GREGORIAN). 5432 */ 5433static VALUE 5434d_lite_gregorian(VALUE self) 5435{ 5436 return dup_obj_with_new_start(self, GREGORIAN); 5437} 5438 5439static void 5440set_of(union DateData *x, int of) 5441{ 5442 assert(complex_dat_p(x)); 5443 get_c_jd(x); 5444 get_c_df(x); 5445 clear_civil(x); 5446 x->c.of = of; 5447} 5448 5449static VALUE 5450dup_obj_with_new_offset(VALUE obj, int of) 5451{ 5452 volatile VALUE dup = dup_obj_as_complex(obj); 5453 { 5454 get_d1(dup); 5455 set_of(dat, of); 5456 } 5457 return dup; 5458} 5459 5460/* 5461 * call-seq: 5462 * d.new_offset([offset=0]) -> date 5463 * 5464 * Duplicates self and resets its offset. 5465 * 5466 * d = DateTime.new(2001,2,3,4,5,6,'-02:00') 5467 * #=> #<DateTime: 2001-02-03T04:05:06-02:00 ...> 5468 * d.new_offset('+09:00') #=> #<DateTime: 2001-02-03T15:05:06+09:00 ...> 5469 */ 5470static VALUE 5471d_lite_new_offset(int argc, VALUE *argv, VALUE self) 5472{ 5473 VALUE vof; 5474 int rof; 5475 5476 rb_scan_args(argc, argv, "01", &vof); 5477 5478 rof = 0; 5479 if (argc >= 1) 5480 val2off(vof, rof); 5481 5482 return dup_obj_with_new_offset(self, rof); 5483} 5484 5485/* 5486 * call-seq: 5487 * d + other -> date 5488 * 5489 * Returns a date object pointing other days after self. The other 5490 * should be a numeric value. If the other is flonum, assumes its 5491 * precision is at most nanosecond. 5492 * 5493 * Date.new(2001,2,3) + 1 #=> #<Date: 2001-02-04 ...> 5494 * DateTime.new(2001,2,3) + Rational(1,2) 5495 * #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...> 5496 * DateTime.new(2001,2,3) + Rational(-1,2) 5497 * #=> #<DateTime: 2001-02-02T12:00:00+00:00 ...> 5498 * DateTime.jd(0,12) + DateTime.new(2001,2,3).ajd 5499 * #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> 5500 */ 5501static VALUE 5502d_lite_plus(VALUE self, VALUE other) 5503{ 5504 get_d1(self); 5505 5506 switch (TYPE(other)) { 5507 case T_FIXNUM: 5508 { 5509 VALUE nth; 5510 long t; 5511 int jd; 5512 5513 nth = m_nth(dat); 5514 t = FIX2LONG(other); 5515 if (DIV(t, CM_PERIOD)) { 5516 nth = f_add(nth, INT2FIX(DIV(t, CM_PERIOD))); 5517 t = MOD(t, CM_PERIOD); 5518 } 5519 5520 if (!t) 5521 jd = m_jd(dat); 5522 else { 5523 jd = m_jd(dat) + (int)t; 5524 canonicalize_jd(nth, jd); 5525 } 5526 5527 if (simple_dat_p(dat)) 5528 return d_simple_new_internal(rb_obj_class(self), 5529 nth, jd, 5530 dat->s.sg, 5531 0, 0, 0, 5532 (dat->s.flags | HAVE_JD) & 5533 ~HAVE_CIVIL); 5534 else 5535 return d_complex_new_internal(rb_obj_class(self), 5536 nth, jd, 5537 dat->c.df, dat->c.sf, 5538 dat->c.of, dat->c.sg, 5539 0, 0, 0, 5540#ifndef USE_PACK 5541 dat->c.hour, 5542 dat->c.min, 5543 dat->c.sec, 5544#else 5545 EX_HOUR(dat->c.pc), 5546 EX_MIN(dat->c.pc), 5547 EX_SEC(dat->c.pc), 5548#endif 5549 (dat->c.flags | HAVE_JD) & 5550 ~HAVE_CIVIL); 5551 } 5552 break; 5553 case T_BIGNUM: 5554 { 5555 VALUE nth; 5556 int jd, s; 5557 5558 if (f_positive_p(other)) 5559 s = +1; 5560 else { 5561 s = -1; 5562 other = f_negate(other); 5563 } 5564 5565 nth = f_idiv(other, INT2FIX(CM_PERIOD)); 5566 jd = FIX2INT(f_mod(other, INT2FIX(CM_PERIOD))); 5567 5568 if (s < 0) { 5569 nth = f_negate(nth); 5570 jd = -jd; 5571 } 5572 5573 if (!jd) 5574 jd = m_jd(dat); 5575 else { 5576 jd = m_jd(dat) + jd; 5577 canonicalize_jd(nth, jd); 5578 } 5579 5580 if (f_zero_p(nth)) 5581 nth = m_nth(dat); 5582 else 5583 nth = f_add(m_nth(dat), nth); 5584 5585 if (simple_dat_p(dat)) 5586 return d_simple_new_internal(rb_obj_class(self), 5587 nth, jd, 5588 dat->s.sg, 5589 0, 0, 0, 5590 (dat->s.flags | HAVE_JD) & 5591 ~HAVE_CIVIL); 5592 else 5593 return d_complex_new_internal(rb_obj_class(self), 5594 nth, jd, 5595 dat->c.df, dat->c.sf, 5596 dat->c.of, dat->c.sg, 5597 0, 0, 0, 5598#ifndef USE_PACK 5599 dat->c.hour, 5600 dat->c.min, 5601 dat->c.sec, 5602#else 5603 EX_HOUR(dat->c.pc), 5604 EX_MIN(dat->c.pc), 5605 EX_SEC(dat->c.pc), 5606#endif 5607 (dat->c.flags | HAVE_JD) & 5608 ~HAVE_CIVIL); 5609 } 5610 break; 5611 case T_FLOAT: 5612 { 5613 double jd, o, tmp; 5614 int s, df; 5615 VALUE nth, sf; 5616 5617 o = RFLOAT_VALUE(other); 5618 5619 if (o > 0) 5620 s = +1; 5621 else { 5622 s = -1; 5623 o = -o; 5624 } 5625 5626 o = modf(o, &tmp); 5627 5628 if (!floor(tmp / CM_PERIOD)) { 5629 nth = INT2FIX(0); 5630 jd = (int)tmp; 5631 } 5632 else { 5633 double i, f; 5634 5635 f = modf(tmp / CM_PERIOD, &i); 5636 nth = f_floor(DBL2NUM(i)); 5637 jd = (int)(f * CM_PERIOD); 5638 } 5639 5640 o *= DAY_IN_SECONDS; 5641 o = modf(o, &tmp); 5642 df = (int)tmp; 5643 o *= SECOND_IN_NANOSECONDS; 5644 sf = INT2FIX((int)round(o)); 5645 5646 if (s < 0) { 5647 jd = -jd; 5648 df = -df; 5649 sf = f_negate(sf); 5650 } 5651 5652 if (f_zero_p(sf)) 5653 sf = m_sf(dat); 5654 else { 5655 sf = f_add(m_sf(dat), sf); 5656 if (f_lt_p(sf, INT2FIX(0))) { 5657 df -= 1; 5658 sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5659 } 5660 else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) { 5661 df += 1; 5662 sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5663 } 5664 } 5665 5666 if (!df) 5667 df = m_df(dat); 5668 else { 5669 df = m_df(dat) + df; 5670 if (df < 0) { 5671 jd -= 1; 5672 df += DAY_IN_SECONDS; 5673 } 5674 else if (df >= DAY_IN_SECONDS) { 5675 jd += 1; 5676 df -= DAY_IN_SECONDS; 5677 } 5678 } 5679 5680 if (!jd) 5681 jd = m_jd(dat); 5682 else { 5683 jd = m_jd(dat) + jd; 5684 canonicalize_jd(nth, jd); 5685 } 5686 5687 if (f_zero_p(nth)) 5688 nth = m_nth(dat); 5689 else 5690 nth = f_add(m_nth(dat), nth); 5691 5692 if (!df && f_zero_p(sf) && !m_of(dat)) 5693 return d_simple_new_internal(rb_obj_class(self), 5694 nth, (int)jd, 5695 m_sg(dat), 5696 0, 0, 0, 5697 (dat->s.flags | HAVE_JD) & 5698 ~(HAVE_CIVIL | HAVE_TIME | 5699 COMPLEX_DAT)); 5700 else 5701 return d_complex_new_internal(rb_obj_class(self), 5702 nth, (int)jd, 5703 df, sf, 5704 m_of(dat), m_sg(dat), 5705 0, 0, 0, 5706 0, 0, 0, 5707 (dat->c.flags | 5708 HAVE_JD | HAVE_DF) & 5709 ~(HAVE_CIVIL | HAVE_TIME)); 5710 } 5711 break; 5712 default: 5713 if (!k_numeric_p(other)) 5714 rb_raise(rb_eTypeError, "expected numeric"); 5715 other = f_to_r(other); 5716#ifdef CANONICALIZATION_FOR_MATHN 5717 if (!k_rational_p(other)) 5718 return d_lite_plus(self, other); 5719#endif 5720 /* fall through */ 5721 case T_RATIONAL: 5722 { 5723 VALUE nth, sf, t; 5724 int jd, df, s; 5725 5726 if (wholenum_p(other)) 5727 return d_lite_plus(self, RRATIONAL(other)->num); 5728 5729 if (f_positive_p(other)) 5730 s = +1; 5731 else { 5732 s = -1; 5733 other = f_negate(other); 5734 } 5735 5736 nth = f_idiv(other, INT2FIX(CM_PERIOD)); 5737 t = f_mod(other, INT2FIX(CM_PERIOD)); 5738 5739 jd = FIX2INT(f_idiv(t, INT2FIX(1))); 5740 t = f_mod(t, INT2FIX(1)); 5741 5742 t = f_mul(t, INT2FIX(DAY_IN_SECONDS)); 5743 df = FIX2INT(f_idiv(t, INT2FIX(1))); 5744 t = f_mod(t, INT2FIX(1)); 5745 5746 sf = f_mul(t, INT2FIX(SECOND_IN_NANOSECONDS)); 5747 5748 if (s < 0) { 5749 nth = f_negate(nth); 5750 jd = -jd; 5751 df = -df; 5752 sf = f_negate(sf); 5753 } 5754 5755 if (f_zero_p(sf)) 5756 sf = m_sf(dat); 5757 else { 5758 sf = f_add(m_sf(dat), sf); 5759 if (f_lt_p(sf, INT2FIX(0))) { 5760 df -= 1; 5761 sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5762 } 5763 else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) { 5764 df += 1; 5765 sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5766 } 5767 } 5768 5769 if (!df) 5770 df = m_df(dat); 5771 else { 5772 df = m_df(dat) + df; 5773 if (df < 0) { 5774 jd -= 1; 5775 df += DAY_IN_SECONDS; 5776 } 5777 else if (df >= DAY_IN_SECONDS) { 5778 jd += 1; 5779 df -= DAY_IN_SECONDS; 5780 } 5781 } 5782 5783 if (!jd) 5784 jd = m_jd(dat); 5785 else { 5786 jd = m_jd(dat) + jd; 5787 canonicalize_jd(nth, jd); 5788 } 5789 5790 if (f_zero_p(nth)) 5791 nth = m_nth(dat); 5792 else 5793 nth = f_add(m_nth(dat), nth); 5794 5795 if (!df && f_zero_p(sf) && !m_of(dat)) 5796 return d_simple_new_internal(rb_obj_class(self), 5797 nth, jd, 5798 m_sg(dat), 5799 0, 0, 0, 5800 (dat->s.flags | HAVE_JD) & 5801 ~(HAVE_CIVIL | HAVE_TIME | 5802 COMPLEX_DAT)); 5803 else 5804 return d_complex_new_internal(rb_obj_class(self), 5805 nth, jd, 5806 df, sf, 5807 m_of(dat), m_sg(dat), 5808 0, 0, 0, 5809 0, 0, 0, 5810 (dat->c.flags | 5811 HAVE_JD | HAVE_DF) & 5812 ~(HAVE_CIVIL | HAVE_TIME)); 5813 } 5814 break; 5815 } 5816} 5817 5818static VALUE 5819minus_dd(VALUE self, VALUE other) 5820{ 5821 get_d2(self, other); 5822 5823 { 5824 int d, df; 5825 VALUE n, sf, r; 5826 5827 n = f_sub(m_nth(adat), m_nth(bdat)); 5828 d = m_jd(adat) - m_jd(bdat); 5829 df = m_df(adat) - m_df(bdat); 5830 sf = f_sub(m_sf(adat), m_sf(bdat)); 5831 canonicalize_jd(n, d); 5832 5833 if (df < 0) { 5834 d -= 1; 5835 df += DAY_IN_SECONDS; 5836 } 5837 else if (df >= DAY_IN_SECONDS) { 5838 d += 1; 5839 df -= DAY_IN_SECONDS; 5840 } 5841 5842 if (f_lt_p(sf, INT2FIX(0))) { 5843 df -= 1; 5844 sf = f_add(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5845 } 5846 else if (f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) { 5847 df += 1; 5848 sf = f_sub(sf, INT2FIX(SECOND_IN_NANOSECONDS)); 5849 } 5850 5851 if (f_zero_p(n)) 5852 r = INT2FIX(0); 5853 else 5854 r = f_mul(n, INT2FIX(CM_PERIOD)); 5855 5856 if (d) 5857 r = f_add(r, rb_rational_new1(INT2FIX(d))); 5858 if (df) 5859 r = f_add(r, isec_to_day(df)); 5860 if (f_nonzero_p(sf)) 5861 r = f_add(r, ns_to_day(sf)); 5862 5863 if (TYPE(r) == T_RATIONAL) 5864 return r; 5865 return rb_rational_new1(r); 5866 } 5867} 5868 5869/* 5870 * call-seq: 5871 * d - other -> date or rational 5872 * 5873 * Returns the difference between the two dates if the other is a date 5874 * object. If the other is a numeric value, returns a date object 5875 * pointing other days before self. If the other is flonum, assumes 5876 * its precision is at most nanosecond. 5877 * 5878 * Date.new(2001,2,3) - 1 #=> #<Date: 2001-02-02 ...> 5879 * DateTime.new(2001,2,3) - Rational(1,2) 5880 * #=> #<DateTime: 2001-02-02T12:00:00+00:00 ...> 5881 * Date.new(2001,2,3) - Date.new(2001) 5882 * #=> (33/1) 5883 * DateTime.new(2001,2,3) - DateTime.new(2001,2,2,12) 5884 * #=> (1/2) 5885 */ 5886static VALUE 5887d_lite_minus(VALUE self, VALUE other) 5888{ 5889 if (k_date_p(other)) 5890 return minus_dd(self, other); 5891 5892 switch (TYPE(other)) { 5893 case T_FIXNUM: 5894 return d_lite_plus(self, LONG2NUM(-FIX2LONG(other))); 5895 case T_FLOAT: 5896 return d_lite_plus(self, DBL2NUM(-RFLOAT_VALUE(other))); 5897 default: 5898 if (!k_numeric_p(other)) 5899 rb_raise(rb_eTypeError, "expected numeric"); 5900 /* fall through */ 5901 case T_BIGNUM: 5902 case T_RATIONAL: 5903 return d_lite_plus(self, f_negate(other)); 5904 } 5905} 5906 5907/* 5908 * call-seq: 5909 * d.next_day([n=1]) -> date 5910 * 5911 * This method is equivalent to d + n. 5912 */ 5913static VALUE 5914d_lite_next_day(int argc, VALUE *argv, VALUE self) 5915{ 5916 VALUE n; 5917 5918 rb_scan_args(argc, argv, "01", &n); 5919 if (argc < 1) 5920 n = INT2FIX(1); 5921 return d_lite_plus(self, n); 5922} 5923 5924/* 5925 * call-seq: 5926 * d.prev_day([n=1]) -> date 5927 * 5928 * This method is equivalent to d - n. 5929 */ 5930static VALUE 5931d_lite_prev_day(int argc, VALUE *argv, VALUE self) 5932{ 5933 VALUE n; 5934 5935 rb_scan_args(argc, argv, "01", &n); 5936 if (argc < 1) 5937 n = INT2FIX(1); 5938 return d_lite_minus(self, n); 5939} 5940 5941/* 5942 * call-seq: 5943 * d.next -> date 5944 * 5945 * Returns a date object denoting the following day. 5946 */ 5947static VALUE 5948d_lite_next(VALUE self) 5949{ 5950 return d_lite_next_day(0, (VALUE *)NULL, self); 5951} 5952 5953/* 5954 * call-seq: 5955 * d >> n -> date 5956 * 5957 * Returns a date object pointing n months after self. The n should 5958 * be a numeric value. 5959 * 5960 * Date.new(2001,2,3) >> 1 #=> #<Date: 2001-03-03 ...> 5961 * Date.new(2001,1,31) >> 1 #=> #<Date: 2001-02-28 ...> 5962 * Date.new(2001,2,3) >> -2 #=> #<Date: 2000-12-03 ...> 5963 */ 5964static VALUE 5965d_lite_rshift(VALUE self, VALUE other) 5966{ 5967 VALUE t, y, nth, rjd2; 5968 int m, d, rjd; 5969 double sg; 5970 5971 get_d1(self); 5972 t = f_add3(f_mul(m_real_year(dat), INT2FIX(12)), 5973 INT2FIX(m_mon(dat) - 1), 5974 other); 5975 if (FIXNUM_P(t)) { 5976 long it = FIX2LONG(t); 5977 y = LONG2NUM(DIV(it, 12)); 5978 it = MOD(it, 12); 5979 m = (int)it + 1; 5980 } 5981 else { 5982 y = f_idiv(t, INT2FIX(12)); 5983 t = f_mod(t, INT2FIX(12)); 5984 m = FIX2INT(t) + 1; 5985 } 5986 d = m_mday(dat); 5987 sg = m_sg(dat); 5988 5989 while (1) { 5990 int ry, rm, rd, ns; 5991 5992 if (valid_civil_p(y, m, d, sg, 5993 &nth, &ry, 5994 &rm, &rd, &rjd, &ns)) 5995 break; 5996 if (--d < 1) 5997 rb_raise(rb_eArgError, "invalid date"); 5998 } 5999 encode_jd(nth, rjd, &rjd2); 6000 return d_lite_plus(self, f_sub(rjd2, m_real_local_jd(dat))); 6001} 6002 6003/* 6004 * call-seq: 6005 * d << n -> date 6006 * 6007 * Returns a date object pointing n months before self. The n should 6008 * be a numeric value. 6009 * 6010 * Date.new(2001,2,3) << 1 #=> #<Date: 2001-01-03 ...> 6011 * Date.new(2001,1,31) << 11 #=> #<Date: 2000-02-29 ...> 6012 * Date.new(2001,2,3) << -1 #=> #<Date: 2001-03-03 ...> 6013 */ 6014static VALUE 6015d_lite_lshift(VALUE self, VALUE other) 6016{ 6017 return d_lite_rshift(self, f_negate(other)); 6018} 6019 6020/* 6021 * call-seq: 6022 * d.next_month([n=1]) -> date 6023 * 6024 * This method is equivalent to d >> n 6025 */ 6026static VALUE 6027d_lite_next_month(int argc, VALUE *argv, VALUE self) 6028{ 6029 VALUE n; 6030 6031 rb_scan_args(argc, argv, "01", &n); 6032 if (argc < 1) 6033 n = INT2FIX(1); 6034 return d_lite_rshift(self, n); 6035} 6036 6037/* 6038 * call-seq: 6039 * d.prev_month([n=1]) -> date 6040 * 6041 * This method is equivalent to d << n 6042 */ 6043static VALUE 6044d_lite_prev_month(int argc, VALUE *argv, VALUE self) 6045{ 6046 VALUE n; 6047 6048 rb_scan_args(argc, argv, "01", &n); 6049 if (argc < 1) 6050 n = INT2FIX(1); 6051 return d_lite_lshift(self, n); 6052} 6053 6054/* 6055 * call-seq: 6056 * d.next_year([n=1]) -> date 6057 * 6058 * This method is equivalent to d >> (n * 12) 6059 */ 6060static VALUE 6061d_lite_next_year(int argc, VALUE *argv, VALUE self) 6062{ 6063 VALUE n; 6064 6065 rb_scan_args(argc, argv, "01", &n); 6066 if (argc < 1) 6067 n = INT2FIX(1); 6068 return d_lite_rshift(self, f_mul(n, INT2FIX(12))); 6069} 6070 6071/* 6072 * call-seq: 6073 * d.prev_year([n=1]) -> date 6074 * 6075 * This method is equivalent to d << (n * 12) 6076 */ 6077static VALUE 6078d_lite_prev_year(int argc, VALUE *argv, VALUE self) 6079{ 6080 VALUE n; 6081 6082 rb_scan_args(argc, argv, "01", &n); 6083 if (argc < 1) 6084 n = INT2FIX(1); 6085 return d_lite_lshift(self, f_mul(n, INT2FIX(12))); 6086} 6087 6088static VALUE d_lite_cmp(VALUE, VALUE); 6089 6090/* 6091 * call-seq: 6092 * d.step(limit[, step=1]) -> enumerator 6093 * d.step(limit[, step=1]){|date| ...} -> self 6094 * 6095 * Iterates evaluation of the given block, which takes a date object. 6096 * The limit should be a date object. 6097 * 6098 * Date.new(2001).step(Date.new(2001,-1,-1)).select{|d| d.sunday?}.size 6099 * #=> 52 6100 */ 6101static VALUE 6102d_lite_step(int argc, VALUE *argv, VALUE self) 6103{ 6104 VALUE limit, step, date; 6105 6106 rb_scan_args(argc, argv, "11", &limit, &step); 6107 6108 if (argc < 2) 6109 step = INT2FIX(1); 6110 6111#if 0 6112 if (f_zero_p(step)) 6113 rb_raise(rb_eArgError, "step can't be 0"); 6114#endif 6115 6116 RETURN_ENUMERATOR(self, argc, argv); 6117 6118 date = self; 6119 switch (FIX2INT(f_cmp(step, INT2FIX(0)))) { 6120 case -1: 6121 while (FIX2INT(d_lite_cmp(date, limit)) >= 0) { 6122 rb_yield(date); 6123 date = d_lite_plus(date, step); 6124 } 6125 break; 6126 case 0: 6127 while (1) 6128 rb_yield(date); 6129 break; 6130 case 1: 6131 while (FIX2INT(d_lite_cmp(date, limit)) <= 0) { 6132 rb_yield(date); 6133 date = d_lite_plus(date, step); 6134 } 6135 break; 6136 default: 6137 abort(); 6138 } 6139 return self; 6140} 6141 6142/* 6143 * call-seq: 6144 * d.upto(max) -> enumerator 6145 * d.upto(max){|date| ...} -> self 6146 * 6147 * This method is equivalent to step(max, 1){|date| ...}. 6148 */ 6149static VALUE 6150d_lite_upto(VALUE self, VALUE max) 6151{ 6152 VALUE date; 6153 6154 RETURN_ENUMERATOR(self, 1, &max); 6155 6156 date = self; 6157 while (FIX2INT(d_lite_cmp(date, max)) <= 0) { 6158 rb_yield(date); 6159 date = d_lite_plus(date, INT2FIX(1)); 6160 } 6161 return self; 6162} 6163 6164/* 6165 * call-seq: 6166 * d.downto(min) -> enumerator 6167 * d.downto(min){|date| ...} -> self 6168 * 6169 * This method is equivalent to step(min, -1){|date| ...}. 6170 */ 6171static VALUE 6172d_lite_downto(VALUE self, VALUE min) 6173{ 6174 VALUE date; 6175 6176 RETURN_ENUMERATOR(self, 1, &min); 6177 6178 date = self; 6179 while (FIX2INT(d_lite_cmp(date, min)) >= 0) { 6180 rb_yield(date); 6181 date = d_lite_plus(date, INT2FIX(-1)); 6182 } 6183 return self; 6184} 6185 6186static VALUE 6187cmp_gen(VALUE self, VALUE other) 6188{ 6189 get_d1(self); 6190 6191 if (k_numeric_p(other)) 6192 return f_cmp(m_ajd(dat), other); 6193 else if (k_date_p(other)) 6194 return f_cmp(m_ajd(dat), f_ajd(other)); 6195 return rb_num_coerce_cmp(self, other, rb_intern("<=>")); 6196} 6197 6198static VALUE 6199cmp_dd(VALUE self, VALUE other) 6200{ 6201 get_d2(self, other); 6202 6203 { 6204 VALUE a_nth, b_nth, 6205 a_sf, b_sf; 6206 int a_jd, b_jd, 6207 a_df, b_df; 6208 6209 m_canonicalize_jd(adat); 6210 m_canonicalize_jd(bdat); 6211 a_nth = m_nth(adat); 6212 b_nth = m_nth(bdat); 6213 if (f_eqeq_p(a_nth, b_nth)) { 6214 a_jd = m_jd(adat); 6215 b_jd = m_jd(bdat); 6216 if (a_jd == b_jd) { 6217 a_df = m_df(adat); 6218 b_df = m_df(bdat); 6219 if (a_df == b_df) { 6220 a_sf = m_sf(adat); 6221 b_sf = m_sf(bdat); 6222 if (f_eqeq_p(a_sf, b_sf)) { 6223 return INT2FIX(0); 6224 } 6225 else if (f_lt_p(a_sf, b_sf)) { 6226 return INT2FIX(-1); 6227 } 6228 else { 6229 return INT2FIX(1); 6230 } 6231 } 6232 else if (a_df < b_df) { 6233 return INT2FIX(-1); 6234 } 6235 else { 6236 return INT2FIX(1); 6237 } 6238 } 6239 else if (a_jd < b_jd) { 6240 return INT2FIX(-1); 6241 } 6242 else { 6243 return INT2FIX(1); 6244 } 6245 } 6246 else if (f_lt_p(a_nth, b_nth)) { 6247 return INT2FIX(-1); 6248 } 6249 else { 6250 return INT2FIX(1); 6251 } 6252 } 6253} 6254 6255/* 6256 * call-seq: 6257 * d <=> other -> -1, 0, +1 or nil 6258 * 6259 * Compares the two dates and returns -1, zero, 1 or nil. The other 6260 * should be a date object or a numeric value as an astronomical 6261 * Julian day number. 6262 * 6263 * Date.new(2001,2,3) <=> Date.new(2001,2,4) #=> -1 6264 * Date.new(2001,2,3) <=> Date.new(2001,2,3) #=> 0 6265 * Date.new(2001,2,3) <=> Date.new(2001,2,2) #=> 1 6266 * Date.new(2001,2,3) <=> Object.new #=> nil 6267 * Date.new(2001,2,3) <=> Rational(4903887,2)#=> 0 6268 * 6269 * See also Comparable. 6270 */ 6271static VALUE 6272d_lite_cmp(VALUE self, VALUE other) 6273{ 6274 if (!k_date_p(other)) 6275 return cmp_gen(self, other); 6276 6277 { 6278 get_d2(self, other); 6279 6280 if (!(simple_dat_p(adat) && simple_dat_p(bdat) && 6281 m_gregorian_p(adat) == m_gregorian_p(bdat))) 6282 return cmp_dd(self, other); 6283 6284 if (have_jd_p(adat) && 6285 have_jd_p(bdat)) { 6286 VALUE a_nth, b_nth; 6287 int a_jd, b_jd; 6288 6289 m_canonicalize_jd(adat); 6290 m_canonicalize_jd(bdat); 6291 a_nth = m_nth(adat); 6292 b_nth = m_nth(bdat); 6293 if (f_eqeq_p(a_nth, b_nth)) { 6294 a_jd = m_jd(adat); 6295 b_jd = m_jd(bdat); 6296 if (a_jd == b_jd) { 6297 return INT2FIX(0); 6298 } 6299 else if (a_jd < b_jd) { 6300 return INT2FIX(-1); 6301 } 6302 else { 6303 return INT2FIX(1); 6304 } 6305 } 6306 else if (a_nth < b_nth) { 6307 return INT2FIX(-1); 6308 } 6309 else { 6310 return INT2FIX(1); 6311 } 6312 } 6313 else { 6314#ifndef USE_PACK 6315 VALUE a_nth, b_nth; 6316 int a_year, b_year, 6317 a_mon, b_mon, 6318 a_mday, b_mday; 6319#else 6320 VALUE a_nth, b_nth; 6321 int a_year, b_year, 6322 a_pd, b_pd; 6323#endif 6324 6325 m_canonicalize_jd(adat); 6326 m_canonicalize_jd(bdat); 6327 a_nth = m_nth(adat); 6328 b_nth = m_nth(bdat); 6329 if (f_eqeq_p(a_nth, b_nth)) { 6330 a_year = m_year(adat); 6331 b_year = m_year(bdat); 6332 if (a_year == b_year) { 6333#ifndef USE_PACK 6334 a_mon = m_mon(adat); 6335 b_mon = m_mon(bdat); 6336 if (a_mon == b_mon) { 6337 a_mday = m_mday(adat); 6338 b_mday = m_mday(bdat); 6339 if (a_mday == b_mday) { 6340 return INT2FIX(0); 6341 } 6342 else if (a_mday < b_mday) { 6343 return INT2FIX(-1); 6344 } 6345 else { 6346 return INT2FIX(1); 6347 } 6348 } 6349 else if (a_mon < b_mon) { 6350 return INT2FIX(-1); 6351 } 6352 else { 6353 return INT2FIX(1); 6354 } 6355#else 6356 a_pd = m_pc(adat); 6357 b_pd = m_pc(bdat); 6358 if (a_pd == b_pd) { 6359 return INT2FIX(0); 6360 } 6361 else if (a_pd < b_pd) { 6362 return INT2FIX(-1); 6363 } 6364 else { 6365 return INT2FIX(1); 6366 } 6367#endif 6368 } 6369 else if (a_year < b_year) { 6370 return INT2FIX(-1); 6371 } 6372 else { 6373 return INT2FIX(1); 6374 } 6375 } 6376 else if (f_lt_p(a_nth, b_nth)) { 6377 return INT2FIX(-1); 6378 } 6379 else { 6380 return INT2FIX(1); 6381 } 6382 } 6383 } 6384} 6385 6386static VALUE 6387equal_gen(VALUE self, VALUE other) 6388{ 6389 get_d1(self); 6390 6391 if (k_numeric_p(other)) 6392 return f_eqeq_p(m_real_local_jd(dat), other); 6393 else if (k_date_p(other)) 6394 return f_eqeq_p(m_real_local_jd(dat), f_jd(other)); 6395 return rb_num_coerce_cmp(self, other, rb_intern("==")); 6396} 6397 6398/* 6399 * call-seq: 6400 * d === other -> bool 6401 * 6402 * Returns true if they are the same day. 6403 * 6404 * Date.new(2001,2,3) === Date.new(2001,2,3) 6405 * #=> true 6406 * Date.new(2001,2,3) === Date.new(2001,2,4) 6407 * #=> false 6408 * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,12) 6409 * #=> true 6410 * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,0,0,0,'+24:00') 6411 * #=> true 6412 * DateTime.new(2001,2,3) === DateTime.new(2001,2,4,0,0,0,'+24:00') 6413 * #=> false 6414 */ 6415static VALUE 6416d_lite_equal(VALUE self, VALUE other) 6417{ 6418 if (!k_date_p(other)) 6419 return equal_gen(self, other); 6420 6421 { 6422 get_d2(self, other); 6423 6424 if (!(m_gregorian_p(adat) == m_gregorian_p(bdat))) 6425 return equal_gen(self, other); 6426 6427 if (have_jd_p(adat) && 6428 have_jd_p(bdat)) { 6429 VALUE a_nth, b_nth; 6430 int a_jd, b_jd; 6431 6432 m_canonicalize_jd(adat); 6433 m_canonicalize_jd(bdat); 6434 a_nth = m_nth(adat); 6435 b_nth = m_nth(bdat); 6436 a_jd = m_local_jd(adat); 6437 b_jd = m_local_jd(bdat); 6438 if (f_eqeq_p(a_nth, b_nth) && 6439 a_jd == b_jd) 6440 return Qtrue; 6441 return Qfalse; 6442 } 6443 else { 6444#ifndef USE_PACK 6445 VALUE a_nth, b_nth; 6446 int a_year, b_year, 6447 a_mon, b_mon, 6448 a_mday, b_mday; 6449#else 6450 VALUE a_nth, b_nth; 6451 int a_year, b_year, 6452 a_pd, b_pd; 6453#endif 6454 6455 m_canonicalize_jd(adat); 6456 m_canonicalize_jd(bdat); 6457 a_nth = m_nth(adat); 6458 b_nth = m_nth(bdat); 6459 if (f_eqeq_p(a_nth, b_nth)) { 6460 a_year = m_year(adat); 6461 b_year = m_year(bdat); 6462 if (a_year == b_year) { 6463#ifndef USE_PACK 6464 a_mon = m_mon(adat); 6465 b_mon = m_mon(bdat); 6466 if (a_mon == b_mon) { 6467 a_mday = m_mday(adat); 6468 b_mday = m_mday(bdat); 6469 if (a_mday == b_mday) 6470 return Qtrue; 6471 } 6472#else 6473 /* mon and mday only */ 6474 a_pd = (m_pc(adat) >> MDAY_SHIFT); 6475 b_pd = (m_pc(bdat) >> MDAY_SHIFT); 6476 if (a_pd == b_pd) { 6477 return Qtrue; 6478 } 6479#endif 6480 } 6481 } 6482 return Qfalse; 6483 } 6484 } 6485} 6486 6487/* :nodoc: */ 6488static VALUE 6489d_lite_eql_p(VALUE self, VALUE other) 6490{ 6491 if (!k_date_p(other)) 6492 return Qfalse; 6493 return f_zero_p(d_lite_cmp(self, other)); 6494} 6495 6496/* :nodoc: */ 6497static VALUE 6498d_lite_hash(VALUE self) 6499{ 6500 st_index_t v, h[4]; 6501 6502 get_d1(self); 6503 h[0] = m_nth(dat); 6504 h[1] = m_jd(dat); 6505 h[2] = m_df(dat); 6506 h[3] = m_sf(dat); 6507 v = rb_memhash(h, sizeof(h)); 6508 return LONG2FIX(v); 6509} 6510 6511#include "date_tmx.h" 6512static void set_tmx(VALUE, struct tmx *); 6513static VALUE strftimev(const char *, VALUE, 6514 void (*)(VALUE, struct tmx *)); 6515 6516/* 6517 * call-seq: 6518 * d.to_s -> string 6519 * 6520 * Returns a string in an ISO 8601 format (This method doesn't use the 6521 * expanded representations). 6522 * 6523 * Date.new(2001,2,3).to_s #=> "2001-02-03" 6524 */ 6525static VALUE 6526d_lite_to_s(VALUE self) 6527{ 6528 return strftimev("%Y-%m-%d", self, set_tmx); 6529} 6530 6531#ifndef NDEBUG 6532static VALUE 6533mk_inspect_flags(union DateData *x) 6534{ 6535 return rb_enc_sprintf(rb_usascii_encoding(), 6536 "%c%c%c%c%c", 6537 (x->flags & COMPLEX_DAT) ? 'C' : 'S', 6538 (x->flags & HAVE_JD) ? 'j' : '-', 6539 (x->flags & HAVE_DF) ? 'd' : '-', 6540 (x->flags & HAVE_CIVIL) ? 'c' : '-', 6541 (x->flags & HAVE_TIME) ? 't' : '-'); 6542} 6543 6544static VALUE 6545mk_inspect_raw(union DateData *x, const char *klass) 6546{ 6547 if (simple_dat_p(x)) { 6548 VALUE nth, flags; 6549 6550 RB_GC_GUARD(nth) = f_inspect(x->s.nth); 6551 RB_GC_GUARD(flags) = mk_inspect_flags(x); 6552 6553 return rb_enc_sprintf(rb_usascii_encoding(), 6554 "#<%s: " 6555 "(%sth,%dj),+0s,%.0fj; " 6556 "%dy%dm%dd; %s>", 6557 klass ? klass : "?", 6558 RSTRING_PTR(nth), x->s.jd, x->s.sg, 6559#ifndef USE_PACK 6560 x->s.year, x->s.mon, x->s.mday, 6561#else 6562 x->s.year, 6563 EX_MON(x->s.pc), EX_MDAY(x->s.pc), 6564#endif 6565 RSTRING_PTR(flags)); 6566 } 6567 else { 6568 VALUE nth, sf, flags; 6569 6570 RB_GC_GUARD(nth) = f_inspect(x->c.nth); 6571 RB_GC_GUARD(sf) = f_inspect(x->c.sf); 6572 RB_GC_GUARD(flags) = mk_inspect_flags(x); 6573 6574 return rb_enc_sprintf(rb_usascii_encoding(), 6575 "#<%s: " 6576 "(%sth,%dj,%ds,%sn),%+ds,%.0fj; " 6577 "%dy%dm%dd %dh%dm%ds; %s>", 6578 klass ? klass : "?", 6579 RSTRING_PTR(nth), x->c.jd, x->c.df, 6580 RSTRING_PTR(sf), 6581 x->c.of, x->c.sg, 6582#ifndef USE_PACK 6583 x->c.year, x->c.mon, x->c.mday, 6584 x->c.hour, x->c.min, x->c.sec, 6585#else 6586 x->c.year, 6587 EX_MON(x->c.pc), EX_MDAY(x->c.pc), 6588 EX_HOUR(x->c.pc), EX_MIN(x->c.pc), 6589 EX_SEC(x->c.pc), 6590#endif 6591 RSTRING_PTR(flags)); 6592 } 6593} 6594 6595static VALUE 6596d_lite_inspect_raw(VALUE self) 6597{ 6598 get_d1(self); 6599 return mk_inspect_raw(dat, rb_obj_classname(self)); 6600} 6601#endif 6602 6603static VALUE 6604mk_inspect(union DateData *x, const char *klass, const char *to_s) 6605{ 6606 VALUE jd, sf; 6607 6608 RB_GC_GUARD(jd) = f_inspect(m_real_jd(x)); 6609 RB_GC_GUARD(sf) = f_inspect(m_sf(x)); 6610 6611 return rb_enc_sprintf(rb_usascii_encoding(), 6612 "#<%s: %s ((%sj,%ds,%sn),%+ds,%.0fj)>", 6613 klass ? klass : "?", 6614 to_s ? to_s : "?", 6615 RSTRING_PTR(jd), m_df(x), RSTRING_PTR(sf), 6616 m_of(x), m_sg(x)); 6617} 6618 6619/* 6620 * call-seq: 6621 * d.inspect -> string 6622 * 6623 * Returns the value as a string for inspection. 6624 * 6625 * Date.new(2001,2,3).inspect 6626 * #=> "#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>" 6627 * DateTime.new(2001,2,3,4,5,6,'-7').inspect 6628 * #=> "#<DateTime: 2001-02-03T04:05:06-07:00 ((2451944j,39906s,0n),-25200s,2299161j)>" 6629 */ 6630static VALUE 6631d_lite_inspect(VALUE self) 6632{ 6633 get_d1(self); 6634 { 6635 VALUE to_s; 6636 6637 RB_GC_GUARD(to_s) = f_to_s(self); 6638 return mk_inspect(dat, rb_obj_classname(self), RSTRING_PTR(to_s)); 6639 } 6640} 6641 6642#include <errno.h> 6643#include "date_tmx.h" 6644 6645size_t date_strftime(char *s, size_t maxsize, const char *format, 6646 const struct tmx *tmx); 6647 6648#define SMALLBUF 100 6649static size_t 6650date_strftime_alloc(char **buf, const char *format, 6651 struct tmx *tmx) 6652{ 6653 size_t size, len, flen; 6654 6655 (*buf)[0] = '\0'; 6656 flen = strlen(format); 6657 if (flen == 0) { 6658 return 0; 6659 } 6660 errno = 0; 6661 len = date_strftime(*buf, SMALLBUF, format, tmx); 6662 if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len; 6663 for (size=1024; ; size*=2) { 6664 *buf = xmalloc(size); 6665 (*buf)[0] = '\0'; 6666 len = date_strftime(*buf, size, format, tmx); 6667 /* 6668 * buflen can be zero EITHER because there's not enough 6669 * room in the string, or because the control command 6670 * goes to the empty string. Make a reasonable guess that 6671 * if the buffer is 1024 times bigger than the length of the 6672 * format string, it's not failing for lack of room. 6673 */ 6674 if (len > 0) break; 6675 xfree(*buf); 6676 if (size >= 1024 * flen) { 6677 rb_sys_fail(format); 6678 break; 6679 } 6680 } 6681 return len; 6682} 6683 6684static VALUE 6685tmx_m_secs(union DateData *x) 6686{ 6687 VALUE s; 6688 int df; 6689 6690 s = day_to_sec(f_sub(m_real_jd(x), 6691 UNIX_EPOCH_IN_CJD)); 6692 if (simple_dat_p(x)) 6693 return s; 6694 df = m_df(x); 6695 if (df) 6696 s = f_add(s, INT2FIX(df)); 6697 return s; 6698} 6699 6700#define MILLISECOND_IN_NANOSECONDS 1000000 6701 6702static VALUE 6703tmx_m_msecs(union DateData *x) 6704{ 6705 VALUE s, sf; 6706 6707 s = sec_to_ms(tmx_m_secs(x)); 6708 if (simple_dat_p(x)) 6709 return s; 6710 sf = m_sf(x); 6711 if (f_nonzero_p(sf)) 6712 s = f_add(s, f_div(sf, INT2FIX(MILLISECOND_IN_NANOSECONDS))); 6713 return s; 6714} 6715 6716static int 6717tmx_m_of(union DateData *x) 6718{ 6719 return m_of(x); 6720} 6721 6722static char * 6723tmx_m_zone(union DateData *x) 6724{ 6725 return RSTRING_PTR(m_zone(x)); 6726} 6727 6728static struct tmx_funcs tmx_funcs = { 6729 (VALUE (*)(void *))m_real_year, 6730 (int (*)(void *))m_yday, 6731 (int (*)(void *))m_mon, 6732 (int (*)(void *))m_mday, 6733 (VALUE (*)(void *))m_real_cwyear, 6734 (int (*)(void *))m_cweek, 6735 (int (*)(void *))m_cwday, 6736 (int (*)(void *))m_wnum0, 6737 (int (*)(void *))m_wnum1, 6738 (int (*)(void *))m_wday, 6739 (int (*)(void *))m_hour, 6740 (int (*)(void *))m_min, 6741 (int (*)(void *))m_sec, 6742 (VALUE (*)(void *))m_sf_in_sec, 6743 (VALUE (*)(void *))tmx_m_secs, 6744 (VALUE (*)(void *))tmx_m_msecs, 6745 (int (*)(void *))tmx_m_of, 6746 (char *(*)(void *))tmx_m_zone 6747}; 6748 6749static void 6750set_tmx(VALUE self, struct tmx *tmx) 6751{ 6752 get_d1(self); 6753 tmx->dat = (void *)dat; 6754 tmx->funcs = &tmx_funcs; 6755} 6756 6757static VALUE 6758date_strftime_internal(int argc, VALUE *argv, VALUE self, 6759 const char *default_fmt, 6760 void (*func)(VALUE, struct tmx *)) 6761{ 6762 VALUE vfmt; 6763 const char *fmt; 6764 long len; 6765 char buffer[SMALLBUF], *buf = buffer; 6766 struct tmx tmx; 6767 VALUE str; 6768 6769 rb_scan_args(argc, argv, "01", &vfmt); 6770 6771 if (argc < 1) 6772 vfmt = rb_usascii_str_new2(default_fmt); 6773 else { 6774 StringValue(vfmt); 6775 if (!rb_enc_str_asciicompat_p(vfmt)) { 6776 rb_raise(rb_eArgError, 6777 "format should have ASCII compatible encoding"); 6778 } 6779 } 6780 fmt = RSTRING_PTR(vfmt); 6781 len = RSTRING_LEN(vfmt); 6782 (*func)(self, &tmx); 6783 if (memchr(fmt, '\0', len)) { 6784 /* Ruby string may contain \0's. */ 6785 const char *p = fmt, *pe = fmt + len; 6786 6787 str = rb_str_new(0, 0); 6788 while (p < pe) { 6789 len = date_strftime_alloc(&buf, p, &tmx); 6790 rb_str_cat(str, buf, len); 6791 p += strlen(p); 6792 if (buf != buffer) { 6793 xfree(buf); 6794 buf = buffer; 6795 } 6796 for (fmt = p; p < pe && !*p; ++p); 6797 if (p > fmt) rb_str_cat(str, fmt, p - fmt); 6798 } 6799 rb_enc_copy(str, vfmt); 6800 OBJ_INFECT(str, vfmt); 6801 return str; 6802 } 6803 else 6804 len = date_strftime_alloc(&buf, fmt, &tmx); 6805 6806 str = rb_str_new(buf, len); 6807 if (buf != buffer) xfree(buf); 6808 rb_enc_copy(str, vfmt); 6809 OBJ_INFECT(str, vfmt); 6810 return str; 6811} 6812 6813/* 6814 * call-seq: 6815 * d.strftime([format='%F']) -> string 6816 * 6817 * Formats date according to the directives in the given format 6818 * string. 6819 * The directives begins with a percent (%) character. 6820 * Any text not listed as a directive will be passed through to the 6821 * output string. 6822 * 6823 * The directive consists of a percent (%) character, 6824 * zero or more flags, optional minimum field width, 6825 * optional modifier and a conversion specifier 6826 * as follows. 6827 * 6828 * %<flags><width><modifier><conversion> 6829 * 6830 * Flags: 6831 * - don't pad a numerical output. 6832 * _ use spaces for padding. 6833 * 0 use zeros for padding. 6834 * ^ upcase the result string. 6835 * # change case. 6836 * 6837 * The minimum field width specifies the minimum width. 6838 * 6839 * The modifiers are "E", "O", ":", "::" and ":::". 6840 * "E" and "O" are ignored. No effect to result currently. 6841 * 6842 * Format directives: 6843 * 6844 * Date (Year, Month, Day): 6845 * %Y - Year with century (can be negative, 4 digits at least) 6846 * -0001, 0000, 1995, 2009, 14292, etc. 6847 * %C - year / 100 (round down. 20 in 2009) 6848 * %y - year % 100 (00..99) 6849 * 6850 * %m - Month of the year, zero-padded (01..12) 6851 * %_m blank-padded ( 1..12) 6852 * %-m no-padded (1..12) 6853 * %B - The full month name (``January'') 6854 * %^B uppercased (``JANUARY'') 6855 * %b - The abbreviated month name (``Jan'') 6856 * %^b uppercased (``JAN'') 6857 * %h - Equivalent to %b 6858 * 6859 * %d - Day of the month, zero-padded (01..31) 6860 * %-d no-padded (1..31) 6861 * %e - Day of the month, blank-padded ( 1..31) 6862 * 6863 * %j - Day of the year (001..366) 6864 * 6865 * Time (Hour, Minute, Second, Subsecond): 6866 * %H - Hour of the day, 24-hour clock, zero-padded (00..23) 6867 * %k - Hour of the day, 24-hour clock, blank-padded ( 0..23) 6868 * %I - Hour of the day, 12-hour clock, zero-padded (01..12) 6869 * %l - Hour of the day, 12-hour clock, blank-padded ( 1..12) 6870 * %P - Meridian indicator, lowercase (``am'' or ``pm'') 6871 * %p - Meridian indicator, uppercase (``AM'' or ``PM'') 6872 * 6873 * %M - Minute of the hour (00..59) 6874 * 6875 * %S - Second of the minute (00..59) 6876 * 6877 * %L - Millisecond of the second (000..999) 6878 * %N - Fractional seconds digits, default is 9 digits (nanosecond) 6879 * %3N millisecond (3 digits) %15N femtosecond (15 digits) 6880 * %6N microsecond (6 digits) %18N attosecond (18 digits) 6881 * %9N nanosecond (9 digits) %21N zeptosecond (21 digits) 6882 * %12N picosecond (12 digits) %24N yoctosecond (24 digits) 6883 * 6884 * Time zone: 6885 * %z - Time zone as hour and minute offset from UTC (e.g. +0900) 6886 * %:z - hour and minute offset from UTC with a colon (e.g. +09:00) 6887 * %::z - hour, minute and second offset from UTC (e.g. +09:00:00) 6888 * %:::z - hour, minute and second offset from UTC 6889 * (e.g. +09, +09:30, +09:30:30) 6890 * %Z - Time zone abbreviation name or something similar information. 6891 * 6892 * Weekday: 6893 * %A - The full weekday name (``Sunday'') 6894 * %^A uppercased (``SUNDAY'') 6895 * %a - The abbreviated name (``Sun'') 6896 * %^a uppercased (``SUN'') 6897 * %u - Day of the week (Monday is 1, 1..7) 6898 * %w - Day of the week (Sunday is 0, 0..6) 6899 * 6900 * ISO 8601 week-based year and week number: 6901 * The week 1 of YYYY starts with a Monday and includes YYYY-01-04. 6902 * The days in the year before the first week are in the last week of 6903 * the previous year. 6904 * %G - The week-based year 6905 * %g - The last 2 digits of the week-based year (00..99) 6906 * %V - Week number of the week-based year (01..53) 6907 * 6908 * Week number: 6909 * The week 1 of YYYY starts with a Sunday or Monday (according to %U 6910 * or %W). The days in the year before the first week are in week 0. 6911 * %U - Week number of the year. The week starts with Sunday. (00..53) 6912 * %W - Week number of the year. The week starts with Monday. (00..53) 6913 * 6914 * Seconds since the Unix Epoch: 6915 * %s - Number of seconds since 1970-01-01 00:00:00 UTC. 6916 * %Q - Number of milliseconds since 1970-01-01 00:00:00 UTC. 6917 * 6918 * Literal string: 6919 * %n - Newline character (\n) 6920 * %t - Tab character (\t) 6921 * %% - Literal ``%'' character 6922 * 6923 * Combination: 6924 * %c - date and time (%a %b %e %T %Y) 6925 * %D - Date (%m/%d/%y) 6926 * %F - The ISO 8601 date format (%Y-%m-%d) 6927 * %v - VMS date (%e-%b-%Y) 6928 * %x - Same as %D 6929 * %X - Same as %T 6930 * %r - 12-hour time (%I:%M:%S %p) 6931 * %R - 24-hour time (%H:%M) 6932 * %T - 24-hour time (%H:%M:%S) 6933 * %+ - date(1) (%a %b %e %H:%M:%S %Z %Y) 6934 * 6935 * This method is similar to strftime() function defined in ISO C and POSIX. 6936 * Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z) 6937 * are locale dependent in the function. 6938 * However this method is locale independent. 6939 * So, the result may differ even if a same format string is used in other 6940 * systems such as C. 6941 * It is good practice to avoid %x and %X because there are corresponding 6942 * locale independent representations, %D and %T. 6943 * 6944 * Examples: 6945 * 6946 * d = DateTime.new(2007,11,19,8,37,48,"-06:00") 6947 * #=> #<DateTime: 2007-11-19T08:37:48-0600 ...> 6948 * d.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007" 6949 * d.strftime("at %I:%M%p") #=> "at 08:37AM" 6950 * 6951 * Various ISO 8601 formats: 6952 * %Y%m%d => 20071119 Calendar date (basic) 6953 * %F => 2007-11-19 Calendar date (extended) 6954 * %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month 6955 * %Y => 2007 Calendar date, reduced accuracy, specific year 6956 * %C => 20 Calendar date, reduced accuracy, specific century 6957 * %Y%j => 2007323 Ordinal date (basic) 6958 * %Y-%j => 2007-323 Ordinal date (extended) 6959 * %GW%V%u => 2007W471 Week date (basic) 6960 * %G-W%V-%u => 2007-W47-1 Week date (extended) 6961 * %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic) 6962 * %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended) 6963 * %H%M%S => 083748 Local time (basic) 6964 * %T => 08:37:48 Local time (extended) 6965 * %H%M => 0837 Local time, reduced accuracy, specific minute (basic) 6966 * %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended) 6967 * %H => 08 Local time, reduced accuracy, specific hour 6968 * %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic) 6969 * %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended) 6970 * %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic) 6971 * %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended) 6972 * %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic) 6973 * %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended) 6974 * %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic) 6975 * %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended) 6976 * %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic) 6977 * %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended) 6978 * %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic) 6979 * %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended) 6980 * %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic) 6981 * %FT%R => 2007-11-19T08:37 Calendar date and local time (extended) 6982 * %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic) 6983 * %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended) 6984 * %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic) 6985 * %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended) 6986 * 6987 * See also strftime(3) and strptime. 6988 */ 6989static VALUE 6990d_lite_strftime(int argc, VALUE *argv, VALUE self) 6991{ 6992 return date_strftime_internal(argc, argv, self, 6993 "%Y-%m-%d", set_tmx); 6994} 6995 6996static VALUE 6997strftimev(const char *fmt, VALUE self, 6998 void (*func)(VALUE, struct tmx *)) 6999{ 7000 char buffer[SMALLBUF], *buf = buffer; 7001 struct tmx tmx; 7002 long len; 7003 VALUE str; 7004 7005 (*func)(self, &tmx); 7006 len = date_strftime_alloc(&buf, fmt, &tmx); 7007 str = rb_usascii_str_new(buf, len); 7008 if (buf != buffer) xfree(buf); 7009 return str; 7010} 7011 7012/* 7013 * call-seq: 7014 * d.asctime -> string 7015 * d.ctime -> string 7016 * 7017 * Returns a string in asctime(3) format (but without "\n\0" at the 7018 * end). This method is equivalent to strftime('%c'). 7019 * 7020 * See also asctime(3) or ctime(3). 7021 */ 7022static VALUE 7023d_lite_asctime(VALUE self) 7024{ 7025 return strftimev("%a %b %e %H:%M:%S %Y", self, set_tmx); 7026} 7027 7028/* 7029 * call-seq: 7030 * d.iso8601 -> string 7031 * d.xmlschema -> string 7032 * 7033 * This method is equivalent to strftime('%F'). 7034 */ 7035static VALUE 7036d_lite_iso8601(VALUE self) 7037{ 7038 return strftimev("%Y-%m-%d", self, set_tmx); 7039} 7040 7041/* 7042 * call-seq: 7043 * d.rfc3339 -> string 7044 * 7045 * This method is equivalent to strftime('%FT%T%:z'). 7046 */ 7047static VALUE 7048d_lite_rfc3339(VALUE self) 7049{ 7050 return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx); 7051} 7052 7053/* 7054 * call-seq: 7055 * d.rfc2822 -> string 7056 * d.rfc822 -> string 7057 * 7058 * This method is equivalent to strftime('%a, %-d %b %Y %T %z'). 7059 */ 7060static VALUE 7061d_lite_rfc2822(VALUE self) 7062{ 7063 return strftimev("%a, %-d %b %Y %T %z", self, set_tmx); 7064} 7065 7066/* 7067 * call-seq: 7068 * d.httpdate -> string 7069 * 7070 * This method is equivalent to strftime('%a, %d %b %Y %T GMT'). 7071 * See also RFC 2616. 7072 */ 7073static VALUE 7074d_lite_httpdate(VALUE self) 7075{ 7076 volatile VALUE dup = dup_obj_with_new_offset(self, 0); 7077 return strftimev("%a, %d %b %Y %T GMT", dup, set_tmx); 7078} 7079 7080static VALUE 7081jisx0301_date(VALUE jd, VALUE y) 7082{ 7083 VALUE a[2]; 7084 7085 if (f_lt_p(jd, INT2FIX(2405160))) 7086 return rb_usascii_str_new2("%Y-%m-%d"); 7087 if (f_lt_p(jd, INT2FIX(2419614))) { 7088 a[0] = rb_usascii_str_new2("M%02d" ".%%m.%%d"); 7089 a[1] = f_sub(y, INT2FIX(1867)); 7090 } 7091 else if (f_lt_p(jd, INT2FIX(2424875))) { 7092 a[0] = rb_usascii_str_new2("T%02d" ".%%m.%%d"); 7093 a[1] = f_sub(y, INT2FIX(1911)); 7094 } 7095 else if (f_lt_p(jd, INT2FIX(2447535))) { 7096 a[0] = rb_usascii_str_new2("S%02d" ".%%m.%%d"); 7097 a[1] = f_sub(y, INT2FIX(1925)); 7098 } 7099 else { 7100 a[0] = rb_usascii_str_new2("H%02d" ".%%m.%%d"); 7101 a[1] = f_sub(y, INT2FIX(1988)); 7102 } 7103 return rb_f_sprintf(2, a); 7104} 7105 7106/* 7107 * call-seq: 7108 * d.jisx0301 -> string 7109 * 7110 * Returns a string in a JIS X 0301 format. 7111 * 7112 * Date.new(2001,2,3).jisx0301 #=> "H13.02.03" 7113 */ 7114static VALUE 7115d_lite_jisx0301(VALUE self) 7116{ 7117 VALUE s; 7118 7119 get_d1(self); 7120 s = jisx0301_date(m_real_local_jd(dat), 7121 m_real_year(dat)); 7122 return strftimev(RSTRING_PTR(s), self, set_tmx); 7123} 7124 7125#ifndef NDEBUG 7126static VALUE 7127d_lite_marshal_dump_old(VALUE self) 7128{ 7129 VALUE a; 7130 7131 get_d1(self); 7132 7133 a = rb_ary_new3(3, 7134 m_ajd(dat), 7135 m_of_in_day(dat), 7136 DBL2NUM(m_sg(dat))); 7137 7138 if (FL_TEST(self, FL_EXIVAR)) { 7139 rb_copy_generic_ivar(a, self); 7140 FL_SET(a, FL_EXIVAR); 7141 } 7142 7143 return a; 7144} 7145#endif 7146 7147/* :nodoc: */ 7148static VALUE 7149d_lite_marshal_dump(VALUE self) 7150{ 7151 VALUE a; 7152 7153 get_d1(self); 7154 7155 a = rb_ary_new3(6, 7156 m_nth(dat), 7157 INT2FIX(m_jd(dat)), 7158 INT2FIX(m_df(dat)), 7159 m_sf(dat), 7160 INT2FIX(m_of(dat)), 7161 DBL2NUM(m_sg(dat))); 7162 7163 if (FL_TEST(self, FL_EXIVAR)) { 7164 rb_copy_generic_ivar(a, self); 7165 FL_SET(a, FL_EXIVAR); 7166 } 7167 7168 return a; 7169} 7170 7171/* :nodoc: */ 7172static VALUE 7173d_lite_marshal_load(VALUE self, VALUE a) 7174{ 7175 get_d1(self); 7176 7177 rb_check_frozen(self); 7178 rb_check_trusted(self); 7179 7180 if (TYPE(a) != T_ARRAY) 7181 rb_raise(rb_eTypeError, "expected an array"); 7182 7183 switch (RARRAY_LEN(a)) { 7184 case 2: /* 1.6.x */ 7185 case 3: /* 1.8.x, 1.9.2 */ 7186 { 7187 VALUE ajd, of, sg, nth, sf; 7188 int jd, df, rof; 7189 double rsg; 7190 7191 7192 if (RARRAY_LEN(a) == 2) { 7193 ajd = f_sub(RARRAY_PTR(a)[0], half_days_in_day); 7194 of = INT2FIX(0); 7195 sg = RARRAY_PTR(a)[1]; 7196 if (!k_numeric_p(sg)) 7197 sg = DBL2NUM(RTEST(sg) ? GREGORIAN : JULIAN); 7198 } 7199 else { 7200 ajd = RARRAY_PTR(a)[0]; 7201 of = RARRAY_PTR(a)[1]; 7202 sg = RARRAY_PTR(a)[2]; 7203 } 7204 7205 old_to_new(ajd, of, sg, 7206 &nth, &jd, &df, &sf, &rof, &rsg); 7207 7208 if (!df && f_zero_p(sf) && !rof) { 7209 set_to_simple(&dat->s, nth, jd, rsg, 0, 0, 0, HAVE_JD); 7210 } else { 7211 if (!complex_dat_p(dat)) 7212 rb_raise(rb_eArgError, 7213 "cannot load complex into simple"); 7214 7215 set_to_complex(&dat->c, nth, jd, df, sf, rof, rsg, 7216 0, 0, 0, 0, 0, 0, 7217 HAVE_JD | HAVE_DF | COMPLEX_DAT); 7218 } 7219 } 7220 break; 7221 case 6: 7222 { 7223 VALUE nth, sf; 7224 int jd, df, of; 7225 double sg; 7226 7227 nth = RARRAY_PTR(a)[0]; 7228 jd = NUM2INT(RARRAY_PTR(a)[1]); 7229 df = NUM2INT(RARRAY_PTR(a)[2]); 7230 sf = RARRAY_PTR(a)[3]; 7231 of = NUM2INT(RARRAY_PTR(a)[4]); 7232 sg = NUM2DBL(RARRAY_PTR(a)[5]); 7233 if (!df && f_zero_p(sf) && !of) { 7234 set_to_simple(&dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD); 7235 } else { 7236 if (!complex_dat_p(dat)) 7237 rb_raise(rb_eArgError, 7238 "cannot load complex into simple"); 7239 7240 set_to_complex(&dat->c, nth, jd, df, sf, of, sg, 7241 0, 0, 0, 0, 0, 0, 7242 HAVE_JD | HAVE_DF | COMPLEX_DAT); 7243 } 7244 } 7245 break; 7246 default: 7247 rb_raise(rb_eTypeError, "invalid size"); 7248 break; 7249 } 7250 7251 if (FL_TEST(a, FL_EXIVAR)) { 7252 rb_copy_generic_ivar(self, a); 7253 FL_SET(self, FL_EXIVAR); 7254 } 7255 7256 return self; 7257} 7258 7259/* :nodoc: */ 7260static VALUE 7261date_s__load(VALUE klass, VALUE s) 7262{ 7263 VALUE a, obj; 7264 7265 a = rb_marshal_load(s); 7266 obj = d_lite_s_alloc(klass); 7267 return d_lite_marshal_load(obj, a); 7268} 7269 7270/* datetime */ 7271 7272/* 7273 * call-seq: 7274 * DateTime.jd([jd=0[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]) -> datetime 7275 * 7276 * Creates a datetime object denoting the given chronological Julian 7277 * day number. 7278 * 7279 * DateTime.jd(2451944) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> 7280 * DateTime.jd(2451945) #=> #<DateTime: 2001-02-04T00:00:00+00:00 ...> 7281 * DateTime.jd(Rational('0.5')) 7282 * #=> #<DateTime: -4712-01-01T12:00:00+00:00 ...> 7283 */ 7284static VALUE 7285datetime_s_jd(int argc, VALUE *argv, VALUE klass) 7286{ 7287 VALUE vjd, vh, vmin, vs, vof, vsg, jd, fr, fr2, ret; 7288 int h, min, s, rof; 7289 double sg; 7290 7291 rb_scan_args(argc, argv, "06", &vjd, &vh, &vmin, &vs, &vof, &vsg); 7292 7293 jd = INT2FIX(0); 7294 7295 h = min = s = 0; 7296 fr2 = INT2FIX(0); 7297 rof = 0; 7298 sg = DEFAULT_SG; 7299 7300 switch (argc) { 7301 case 6: 7302 val2sg(vsg, sg); 7303 case 5: 7304 val2off(vof, rof); 7305 case 4: 7306 num2int_with_frac(s, positive_inf); 7307 case 3: 7308 num2int_with_frac(min, 3); 7309 case 2: 7310 num2int_with_frac(h, 2); 7311 case 1: 7312 num2num_with_frac(jd, 1); 7313 } 7314 7315 { 7316 VALUE nth; 7317 int rh, rmin, rs, rjd, rjd2; 7318 7319 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7320 rb_raise(rb_eArgError, "invalid date"); 7321 canon24oc(); 7322 7323 decode_jd(jd, &nth, &rjd); 7324 rjd2 = jd_local_to_utc(rjd, 7325 time_to_df(rh, rmin, rs), 7326 rof); 7327 7328 ret = d_complex_new_internal(klass, 7329 nth, rjd2, 7330 0, INT2FIX(0), 7331 rof, sg, 7332 0, 0, 0, 7333 rh, rmin, rs, 7334 HAVE_JD | HAVE_TIME); 7335 } 7336 add_frac(); 7337 return ret; 7338} 7339 7340/* 7341 * call-seq: 7342 * DateTime.ordinal([year=-4712[, yday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]) -> datetime 7343 * 7344 * Creates a date-time object denoting the given ordinal date. 7345 * 7346 * DateTime.ordinal(2001,34) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> 7347 * DateTime.ordinal(2001,34,4,5,6,'+7') 7348 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7349 * DateTime.ordinal(2001,-332,-20,-55,-54,'+7') 7350 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7351 */ 7352static VALUE 7353datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) 7354{ 7355 VALUE vy, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; 7356 int d, h, min, s, rof; 7357 double sg; 7358 7359 rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg); 7360 7361 y = INT2FIX(-4712); 7362 d = 1; 7363 7364 h = min = s = 0; 7365 fr2 = INT2FIX(0); 7366 rof = 0; 7367 sg = DEFAULT_SG; 7368 7369 switch (argc) { 7370 case 7: 7371 val2sg(vsg, sg); 7372 case 6: 7373 val2off(vof, rof); 7374 case 5: 7375 num2int_with_frac(s, positive_inf); 7376 case 4: 7377 num2int_with_frac(min, 4); 7378 case 3: 7379 num2int_with_frac(h, 3); 7380 case 2: 7381 num2int_with_frac(d, 2); 7382 case 1: 7383 y = vy; 7384 } 7385 7386 { 7387 VALUE nth; 7388 int ry, rd, rh, rmin, rs, rjd, rjd2, ns; 7389 7390 if (!valid_ordinal_p(y, d, sg, 7391 &nth, &ry, 7392 &rd, &rjd, 7393 &ns)) 7394 rb_raise(rb_eArgError, "invalid date"); 7395 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7396 rb_raise(rb_eArgError, "invalid date"); 7397 canon24oc(); 7398 7399 rjd2 = jd_local_to_utc(rjd, 7400 time_to_df(rh, rmin, rs), 7401 rof); 7402 7403 ret = d_complex_new_internal(klass, 7404 nth, rjd2, 7405 0, INT2FIX(0), 7406 rof, sg, 7407 0, 0, 0, 7408 rh, rmin, rs, 7409 HAVE_JD | HAVE_TIME); 7410 } 7411 add_frac(); 7412 return ret; 7413} 7414 7415/* 7416 * call-seq: 7417 * DateTime.civil([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime 7418 * DateTime.new([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime 7419 * 7420 * Creates a date-time object denoting the given calendar date. 7421 * 7422 * DateTime.new(2001,2,3) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> 7423 * DateTime.new(2001,2,3,4,5,6,'+7') 7424 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7425 * DateTime.new(2001,-11,-26,-20,-55,-54,'+7') 7426 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7427 */ 7428static VALUE 7429datetime_s_civil(int argc, VALUE *argv, VALUE klass) 7430{ 7431 VALUE vy, vm, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; 7432 int m, d, h, min, s, rof; 7433 double sg; 7434 7435 rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg); 7436 7437 y = INT2FIX(-4712); 7438 m = 1; 7439 d = 1; 7440 7441 h = min = s = 0; 7442 fr2 = INT2FIX(0); 7443 rof = 0; 7444 sg = DEFAULT_SG; 7445 7446 switch (argc) { 7447 case 8: 7448 val2sg(vsg, sg); 7449 case 7: 7450 val2off(vof, rof); 7451 case 6: 7452 num2int_with_frac(s, positive_inf); 7453 case 5: 7454 num2int_with_frac(min, 5); 7455 case 4: 7456 num2int_with_frac(h, 4); 7457 case 3: 7458 num2int_with_frac(d, 3); 7459 case 2: 7460 m = NUM2INT(vm); 7461 case 1: 7462 y = vy; 7463 } 7464 7465 if (guess_style(y, sg) < 0) { 7466 VALUE nth; 7467 int ry, rm, rd, rh, rmin, rs; 7468 7469 if (!valid_gregorian_p(y, m, d, 7470 &nth, &ry, 7471 &rm, &rd)) 7472 rb_raise(rb_eArgError, "invalid date"); 7473 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7474 rb_raise(rb_eArgError, "invalid date"); 7475 canon24oc(); 7476 7477 ret = d_complex_new_internal(klass, 7478 nth, 0, 7479 0, INT2FIX(0), 7480 rof, sg, 7481 ry, rm, rd, 7482 rh, rmin, rs, 7483 HAVE_CIVIL | HAVE_TIME); 7484 } 7485 else { 7486 VALUE nth; 7487 int ry, rm, rd, rh, rmin, rs, rjd, rjd2, ns; 7488 7489 if (!valid_civil_p(y, m, d, sg, 7490 &nth, &ry, 7491 &rm, &rd, &rjd, 7492 &ns)) 7493 rb_raise(rb_eArgError, "invalid date"); 7494 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7495 rb_raise(rb_eArgError, "invalid date"); 7496 canon24oc(); 7497 7498 rjd2 = jd_local_to_utc(rjd, 7499 time_to_df(rh, rmin, rs), 7500 rof); 7501 7502 ret = d_complex_new_internal(klass, 7503 nth, rjd2, 7504 0, INT2FIX(0), 7505 rof, sg, 7506 ry, rm, rd, 7507 rh, rmin, rs, 7508 HAVE_JD | HAVE_CIVIL | HAVE_TIME); 7509 } 7510 add_frac(); 7511 return ret; 7512} 7513 7514/* 7515 * call-seq: 7516 * DateTime.commercial([cwyear=-4712[, cweek=1[, cwday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime 7517 * 7518 * Creates a date-time object denoting the given week date. 7519 * 7520 * DateTime.commercial(2001) #=> #<DateTime: 2001-01-01T00:00:00+00:00 ...> 7521 * DateTime.commercial(2002) #=> #<DateTime: 2001-12-31T00:00:00+00:00 ...> 7522 * DateTime.commercial(2001,5,6,4,5,6,'+7') 7523 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7524 */ 7525static VALUE 7526datetime_s_commercial(int argc, VALUE *argv, VALUE klass) 7527{ 7528 VALUE vy, vw, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; 7529 int w, d, h, min, s, rof; 7530 double sg; 7531 7532 rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg); 7533 7534 y = INT2FIX(-4712); 7535 w = 1; 7536 d = 1; 7537 7538 h = min = s = 0; 7539 fr2 = INT2FIX(0); 7540 rof = 0; 7541 sg = DEFAULT_SG; 7542 7543 switch (argc) { 7544 case 8: 7545 val2sg(vsg, sg); 7546 case 7: 7547 val2off(vof, rof); 7548 case 6: 7549 num2int_with_frac(s, positive_inf); 7550 case 5: 7551 num2int_with_frac(min, 5); 7552 case 4: 7553 num2int_with_frac(h, 4); 7554 case 3: 7555 num2int_with_frac(d, 3); 7556 case 2: 7557 w = NUM2INT(vw); 7558 case 1: 7559 y = vy; 7560 } 7561 7562 { 7563 VALUE nth; 7564 int ry, rw, rd, rh, rmin, rs, rjd, rjd2, ns; 7565 7566 if (!valid_commercial_p(y, w, d, sg, 7567 &nth, &ry, 7568 &rw, &rd, &rjd, 7569 &ns)) 7570 rb_raise(rb_eArgError, "invalid date"); 7571 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7572 rb_raise(rb_eArgError, "invalid date"); 7573 canon24oc(); 7574 7575 rjd2 = jd_local_to_utc(rjd, 7576 time_to_df(rh, rmin, rs), 7577 rof); 7578 7579 ret = d_complex_new_internal(klass, 7580 nth, rjd2, 7581 0, INT2FIX(0), 7582 rof, sg, 7583 0, 0, 0, 7584 rh, rmin, rs, 7585 HAVE_JD | HAVE_TIME); 7586 } 7587 add_frac(); 7588 return ret; 7589} 7590 7591#ifndef NDEBUG 7592static VALUE 7593datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) 7594{ 7595 VALUE vy, vw, vd, vf, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; 7596 int w, d, f, h, min, s, rof; 7597 double sg; 7598 7599 rb_scan_args(argc, argv, "09", &vy, &vw, &vd, &vf, 7600 &vh, &vmin, &vs, &vof, &vsg); 7601 7602 y = INT2FIX(-4712); 7603 w = 0; 7604 d = 1; 7605 f = 0; 7606 7607 h = min = s = 0; 7608 fr2 = INT2FIX(0); 7609 rof = 0; 7610 sg = DEFAULT_SG; 7611 7612 switch (argc) { 7613 case 9: 7614 val2sg(vsg, sg); 7615 case 8: 7616 val2off(vof, rof); 7617 case 7: 7618 num2int_with_frac(s, positive_inf); 7619 case 6: 7620 num2int_with_frac(min, 6); 7621 case 5: 7622 num2int_with_frac(h, 5); 7623 case 4: 7624 f = NUM2INT(vf); 7625 case 3: 7626 num2int_with_frac(d, 4); 7627 case 2: 7628 w = NUM2INT(vw); 7629 case 1: 7630 y = vy; 7631 } 7632 7633 { 7634 VALUE nth; 7635 int ry, rw, rd, rh, rmin, rs, rjd, rjd2, ns; 7636 7637 if (!valid_weeknum_p(y, w, d, f, sg, 7638 &nth, &ry, 7639 &rw, &rd, &rjd, 7640 &ns)) 7641 rb_raise(rb_eArgError, "invalid date"); 7642 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7643 rb_raise(rb_eArgError, "invalid date"); 7644 canon24oc(); 7645 7646 rjd2 = jd_local_to_utc(rjd, 7647 time_to_df(rh, rmin, rs), 7648 rof); 7649 ret = d_complex_new_internal(klass, 7650 nth, rjd2, 7651 0, INT2FIX(0), 7652 rof, sg, 7653 0, 0, 0, 7654 rh, rmin, rs, 7655 HAVE_JD | HAVE_TIME); 7656 } 7657 add_frac(); 7658 return ret; 7659} 7660 7661static VALUE 7662datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass) 7663{ 7664 VALUE vy, vm, vn, vk, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; 7665 int m, n, k, h, min, s, rof; 7666 double sg; 7667 7668 rb_scan_args(argc, argv, "09", &vy, &vm, &vn, &vk, 7669 &vh, &vmin, &vs, &vof, &vsg); 7670 7671 y = INT2FIX(-4712); 7672 m = 1; 7673 n = 1; 7674 k = 1; 7675 7676 h = min = s = 0; 7677 fr2 = INT2FIX(0); 7678 rof = 0; 7679 sg = DEFAULT_SG; 7680 7681 switch (argc) { 7682 case 9: 7683 val2sg(vsg, sg); 7684 case 8: 7685 val2off(vof, rof); 7686 case 7: 7687 num2int_with_frac(s, positive_inf); 7688 case 6: 7689 num2int_with_frac(min, 6); 7690 case 5: 7691 num2int_with_frac(h, 5); 7692 case 4: 7693 num2int_with_frac(k, 4); 7694 case 3: 7695 n = NUM2INT(vn); 7696 case 2: 7697 m = NUM2INT(vm); 7698 case 1: 7699 y = vy; 7700 } 7701 7702 { 7703 VALUE nth; 7704 int ry, rm, rn, rk, rh, rmin, rs, rjd, rjd2, ns; 7705 7706 if (!valid_nth_kday_p(y, m, n, k, sg, 7707 &nth, &ry, 7708 &rm, &rn, &rk, &rjd, 7709 &ns)) 7710 rb_raise(rb_eArgError, "invalid date"); 7711 if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) 7712 rb_raise(rb_eArgError, "invalid date"); 7713 canon24oc(); 7714 7715 rjd2 = jd_local_to_utc(rjd, 7716 time_to_df(rh, rmin, rs), 7717 rof); 7718 ret = d_complex_new_internal(klass, 7719 nth, rjd2, 7720 0, INT2FIX(0), 7721 rof, sg, 7722 0, 0, 0, 7723 rh, rmin, rs, 7724 HAVE_JD | HAVE_TIME); 7725 } 7726 add_frac(); 7727 return ret; 7728} 7729#endif 7730 7731/* 7732 * call-seq: 7733 * DateTime.now([start=Date::ITALY]) -> datetime 7734 * 7735 * Creates a date-time object denoting the present time. 7736 * 7737 * DateTime.now #=> #<DateTime: 2011-06-11T21:20:44+09:00 ...> 7738 */ 7739static VALUE 7740datetime_s_now(int argc, VALUE *argv, VALUE klass) 7741{ 7742 VALUE vsg, nth, ret; 7743 double sg; 7744#ifdef HAVE_CLOCK_GETTIME 7745 struct timespec ts; 7746#else 7747 struct timeval tv; 7748#endif 7749 time_t sec; 7750 struct tm tm; 7751 long sf, of; 7752 int y, ry, m, d, h, min, s; 7753 7754 rb_scan_args(argc, argv, "01", &vsg); 7755 7756 if (argc < 1) 7757 sg = DEFAULT_SG; 7758 else 7759 sg = NUM2DBL(vsg); 7760 7761#ifdef HAVE_CLOCK_GETTIME 7762 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) 7763 rb_sys_fail("clock_gettime"); 7764 sec = ts.tv_sec; 7765#else 7766 if (gettimeofday(&tv, NULL) == -1) 7767 rb_sys_fail("gettimeofday"); 7768 sec = tv.tv_sec; 7769#endif 7770 tzset(); 7771 if (!localtime_r(&sec, &tm)) 7772 rb_sys_fail("localtime"); 7773 7774 y = tm.tm_year + 1900; 7775 m = tm.tm_mon + 1; 7776 d = tm.tm_mday; 7777 h = tm.tm_hour; 7778 min = tm.tm_min; 7779 s = tm.tm_sec; 7780 if (s == 60) 7781 s = 59; 7782#ifdef HAVE_STRUCT_TM_TM_GMTOFF 7783 of = tm.tm_gmtoff; 7784#elif defined(HAVE_VAR_TIMEZONE) 7785#ifdef HAVE_VAR_ALTZONE 7786 of = (long)-((tm.tm_isdst > 0) ? altzone : timezone); 7787#else 7788 of = (long)-timezone; 7789 if (tm.tm_isdst) { 7790 time_t sec2; 7791 7792 tm.tm_isdst = 0; 7793 sec2 = mktime(&tm); 7794 of += (long)difftime(sec2, sec); 7795 } 7796#endif 7797#elif defined(HAVE_TIMEGM) 7798 { 7799 time_t sec2; 7800 7801 sec2 = timegm(&tm); 7802 of = (long)difftime(sec2, sec); 7803 } 7804#else 7805 { 7806 struct tm tm2; 7807 time_t sec2; 7808 7809 if (!gmtime_r(&sec, &tm2)) 7810 rb_sys_fail("gmtime"); 7811 tm2.tm_isdst = tm.tm_isdst; 7812 sec2 = mktime(&tm2); 7813 of = (long)difftime(sec, sec2); 7814 } 7815#endif 7816#ifdef HAVE_CLOCK_GETTIME 7817 sf = ts.tv_nsec; 7818#else 7819 sf = tv.tv_usec * 1000; 7820#endif 7821 7822 if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS) { 7823 of = 0; 7824 rb_warning("invalid offset is ignored"); 7825 } 7826 7827 decode_year(INT2FIX(y), -1, &nth, &ry); 7828 7829 ret = d_complex_new_internal(klass, 7830 nth, 0, 7831 0, LONG2NUM(sf), 7832 (int)of, GREGORIAN, 7833 ry, m, d, 7834 h, min, s, 7835 HAVE_CIVIL | HAVE_TIME); 7836 { 7837 get_d1(ret); 7838 set_sg(dat, sg); 7839 } 7840 return ret; 7841} 7842 7843static VALUE 7844dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) 7845{ 7846 VALUE jd, sf, t; 7847 int df, of; 7848 7849 if (!c_valid_start_p(NUM2DBL(sg))) { 7850 sg = INT2FIX(DEFAULT_SG); 7851 rb_warning("invalid start is ignored"); 7852 } 7853 7854 if (NIL_P(hash)) 7855 rb_raise(rb_eArgError, "invalid date"); 7856 7857 if (NIL_P(ref_hash("jd")) && 7858 NIL_P(ref_hash("yday")) && 7859 !NIL_P(ref_hash("year")) && 7860 !NIL_P(ref_hash("mon")) && 7861 !NIL_P(ref_hash("mday"))) { 7862 jd = rt__valid_civil_p(ref_hash("year"), 7863 ref_hash("mon"), 7864 ref_hash("mday"), sg); 7865 7866 if (NIL_P(ref_hash("hour"))) 7867 set_hash("hour", INT2FIX(0)); 7868 if (NIL_P(ref_hash("min"))) 7869 set_hash("min", INT2FIX(0)); 7870 if (NIL_P(ref_hash("sec"))) 7871 set_hash("sec", INT2FIX(0)); 7872 else if (f_eqeq_p(ref_hash("sec"), INT2FIX(60))) 7873 set_hash("sec", INT2FIX(59)); 7874 } 7875 else { 7876 hash = rt_rewrite_frags(hash); 7877 hash = rt_complete_frags(klass, hash); 7878 jd = rt__valid_date_frags_p(hash, sg); 7879 } 7880 7881 if (NIL_P(jd)) 7882 rb_raise(rb_eArgError, "invalid date"); 7883 7884 { 7885 int rh, rmin, rs; 7886 7887 if (!c_valid_time_p(NUM2INT(ref_hash("hour")), 7888 NUM2INT(ref_hash("min")), 7889 NUM2INT(ref_hash("sec")), 7890 &rh, &rmin, &rs)) 7891 rb_raise(rb_eArgError, "invalid date"); 7892 7893 df = time_to_df(rh, rmin, rs); 7894 } 7895 7896 t = ref_hash("sec_fraction"); 7897 if (NIL_P(t)) 7898 sf = INT2FIX(0); 7899 else 7900 sf = sec_to_ns(t); 7901 7902 t = ref_hash("offset"); 7903 if (NIL_P(t)) 7904 of = 0; 7905 else { 7906 of = NUM2INT(t); 7907 if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS) { 7908 of = 0; 7909 rb_warning("invalid offset is ignored"); 7910 } 7911 } 7912 { 7913 VALUE nth; 7914 int rjd, rjd2; 7915 7916 decode_jd(jd, &nth, &rjd); 7917 rjd2 = jd_local_to_utc(rjd, df, of); 7918 df = df_local_to_utc(df, of); 7919 7920 return d_complex_new_internal(klass, 7921 nth, rjd2, 7922 df, sf, 7923 of, NUM2DBL(sg), 7924 0, 0, 0, 7925 0, 0, 0, 7926 HAVE_JD | HAVE_DF); 7927 } 7928} 7929 7930/* 7931 * call-seq: 7932 * DateTime._strptime(string[, format='%FT%T%z']) -> hash 7933 * 7934 * Parses the given representation of date and time with the given 7935 * template, and returns a hash of parsed elements. _strptime does 7936 * not support specification of flags and width unlike strftime. 7937 * 7938 * See also strptime(3) and strftime. 7939 */ 7940static VALUE 7941datetime_s__strptime(int argc, VALUE *argv, VALUE klass) 7942{ 7943 return date_s__strptime_internal(argc, argv, klass, "%FT%T%z"); 7944} 7945 7946/* 7947 * call-seq: 7948 * DateTime.strptime([string='-4712-01-01T00:00:00+00:00'[, format='%FT%T%z'[ ,start=ITALY]]]) -> datetime 7949 * 7950 * Parses the given representation of date and time with the given 7951 * template, and creates a date object. strptime does not support 7952 * specification of flags and width unlike strftime. 7953 * 7954 * DateTime.strptime('2001-02-03T04:05:06+07:00', '%Y-%m-%dT%H:%M:%S%z') 7955 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7956 * DateTime.strptime('03-02-2001 04:05:06 PM', '%d-%m-%Y %I:%M:%S %p') 7957 * #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...> 7958 * DateTime.strptime('2001-W05-6T04:05:06+07:00', '%G-W%V-%uT%H:%M:%S%z') 7959 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7960 * DateTime.strptime('2001 04 6 04 05 06 +7', '%Y %U %w %H %M %S %z') 7961 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7962 * DateTime.strptime('2001 05 6 04 05 06 +7', '%Y %W %u %H %M %S %z') 7963 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 7964 * DateTime.strptime('-1', '%s') 7965 * #=> #<DateTime: 1969-12-31T23:59:59+00:00 ...> 7966 * DateTime.strptime('-1000', '%Q') 7967 * #=> #<DateTime: 1969-12-31T23:59:59+00:00 ...> 7968 * DateTime.strptime('sat3feb014pm+7', '%a%d%b%y%H%p%z') 7969 * #=> #<DateTime: 2001-02-03T16:00:00+07:00 ...> 7970 * 7971 * See also strptime(3) and strftime. 7972 */ 7973static VALUE 7974datetime_s_strptime(int argc, VALUE *argv, VALUE klass) 7975{ 7976 VALUE str, fmt, sg; 7977 7978 rb_scan_args(argc, argv, "03", &str, &fmt, &sg); 7979 7980 switch (argc) { 7981 case 0: 7982 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 7983 case 1: 7984 fmt = rb_str_new2("%FT%T%z"); 7985 case 2: 7986 sg = INT2FIX(DEFAULT_SG); 7987 } 7988 7989 { 7990 VALUE argv2[2], hash; 7991 7992 argv2[0] = str; 7993 argv2[1] = fmt; 7994 hash = date_s__strptime(2, argv2, klass); 7995 return dt_new_by_frags(klass, hash, sg); 7996 } 7997} 7998 7999/* 8000 * call-seq: 8001 * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=ITALY]]) -> datetime 8002 * 8003 * Parses the given representation of date and time, and creates a 8004 * date object. This method does not function as a validator. 8005 * 8006 * If the optional second argument is true and the detected year is in 8007 * the range "00" to "99", makes it full. 8008 * 8009 * DateTime.parse('2001-02-03T04:05:06+07:00') 8010 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8011 * DateTime.parse('20010203T040506+0700') 8012 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8013 * DateTime.parse('3rd Feb 2001 04:05:06 PM') 8014 * #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...> 8015 */ 8016static VALUE 8017datetime_s_parse(int argc, VALUE *argv, VALUE klass) 8018{ 8019 VALUE str, comp, sg; 8020 8021 rb_scan_args(argc, argv, "03", &str, &comp, &sg); 8022 8023 switch (argc) { 8024 case 0: 8025 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 8026 case 1: 8027 comp = Qtrue; 8028 case 2: 8029 sg = INT2FIX(DEFAULT_SG); 8030 } 8031 8032 { 8033 VALUE argv2[2], hash; 8034 8035 argv2[0] = str; 8036 argv2[1] = comp; 8037 hash = date_s__parse(2, argv2, klass); 8038 return dt_new_by_frags(klass, hash, sg); 8039 } 8040} 8041 8042/* 8043 * call-seq: 8044 * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime 8045 * 8046 * Creates a new Date object by parsing from a string according to 8047 * some typical ISO 8601 formats. 8048 * 8049 * DateTime.iso8601('2001-02-03T04:05:06+07:00') 8050 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8051 * DateTime.iso8601('20010203T040506+0700') 8052 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8053 * DateTime.iso8601('2001-W05-6T04:05:06+07:00') 8054 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8055 */ 8056static VALUE 8057datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) 8058{ 8059 VALUE str, sg; 8060 8061 rb_scan_args(argc, argv, "02", &str, &sg); 8062 8063 switch (argc) { 8064 case 0: 8065 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 8066 case 1: 8067 sg = INT2FIX(DEFAULT_SG); 8068 } 8069 8070 { 8071 VALUE hash = date_s__iso8601(klass, str); 8072 return dt_new_by_frags(klass, hash, sg); 8073 } 8074} 8075 8076/* 8077 * call-seq: 8078 * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime 8079 * 8080 * Creates a new Date object by parsing from a string according to 8081 * some typical RFC 3339 formats. 8082 * 8083 * DateTime.rfc3339('2001-02-03T04:05:06+07:00') 8084 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8085 */ 8086static VALUE 8087datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) 8088{ 8089 VALUE str, sg; 8090 8091 rb_scan_args(argc, argv, "02", &str, &sg); 8092 8093 switch (argc) { 8094 case 0: 8095 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 8096 case 1: 8097 sg = INT2FIX(DEFAULT_SG); 8098 } 8099 8100 { 8101 VALUE hash = date_s__rfc3339(klass, str); 8102 return dt_new_by_frags(klass, hash, sg); 8103 } 8104} 8105 8106/* 8107 * call-seq: 8108 * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime 8109 * 8110 * Creates a new Date object by parsing from a string according to 8111 * some typical XML Schema formats. 8112 * 8113 * DateTime.xmlschema('2001-02-03T04:05:06+07:00') 8114 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8115 */ 8116static VALUE 8117datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) 8118{ 8119 VALUE str, sg; 8120 8121 rb_scan_args(argc, argv, "02", &str, &sg); 8122 8123 switch (argc) { 8124 case 0: 8125 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 8126 case 1: 8127 sg = INT2FIX(DEFAULT_SG); 8128 } 8129 8130 { 8131 VALUE hash = date_s__xmlschema(klass, str); 8132 return dt_new_by_frags(klass, hash, sg); 8133 } 8134} 8135 8136/* 8137 * call-seq: 8138 * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> datetime 8139 * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> datetime 8140 * 8141 * Creates a new Date object by parsing from a string according to 8142 * some typical RFC 2822 formats. 8143 * 8144 * DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700') 8145 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8146 */ 8147static VALUE 8148datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) 8149{ 8150 VALUE str, sg; 8151 8152 rb_scan_args(argc, argv, "02", &str, &sg); 8153 8154 switch (argc) { 8155 case 0: 8156 str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000"); 8157 case 1: 8158 sg = INT2FIX(DEFAULT_SG); 8159 } 8160 8161 { 8162 VALUE hash = date_s__rfc2822(klass, str); 8163 return dt_new_by_frags(klass, hash, sg); 8164 } 8165} 8166 8167/* 8168 * call-seq: 8169 * DateTime.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY]) -> datetime 8170 * 8171 * Creates a new Date object by parsing from a string according to 8172 * some RFC 2616 format. 8173 * 8174 * DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT') 8175 * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> 8176 */ 8177static VALUE 8178datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) 8179{ 8180 VALUE str, sg; 8181 8182 rb_scan_args(argc, argv, "02", &str, &sg); 8183 8184 switch (argc) { 8185 case 0: 8186 str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT"); 8187 case 1: 8188 sg = INT2FIX(DEFAULT_SG); 8189 } 8190 8191 { 8192 VALUE hash = date_s__httpdate(klass, str); 8193 return dt_new_by_frags(klass, hash, sg); 8194 } 8195} 8196 8197/* 8198 * call-seq: 8199 * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime 8200 * 8201 * Creates a new Date object by parsing from a string according to 8202 * some typical JIS X 0301 formats. 8203 * 8204 * DateTime.jisx0301('H13.02.03T04:05:06+07:00') 8205 * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> 8206 */ 8207static VALUE 8208datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) 8209{ 8210 VALUE str, sg; 8211 8212 rb_scan_args(argc, argv, "02", &str, &sg); 8213 8214 switch (argc) { 8215 case 0: 8216 str = rb_str_new2("-4712-01-01T00:00:00+00:00"); 8217 case 1: 8218 sg = INT2FIX(DEFAULT_SG); 8219 } 8220 8221 { 8222 VALUE hash = date_s__jisx0301(klass, str); 8223 return dt_new_by_frags(klass, hash, sg); 8224 } 8225} 8226 8227/* 8228 * call-seq: 8229 * dt.to_s -> string 8230 * 8231 * Returns a string in an ISO 8601 format (This method doesn't use the 8232 * expanded representations). 8233 * 8234 * DateTime.new(2001,2,3,4,5,6,'-7').to_s 8235 * #=> "2001-02-03T04:05:06-07:00" 8236 */ 8237static VALUE 8238dt_lite_to_s(VALUE self) 8239{ 8240 return strftimev("%Y-%m-%dT%H:%M:%S%:z", self, set_tmx); 8241} 8242 8243/* 8244 * call-seq: 8245 * dt.strftime([format='%FT%T%:z']) -> string 8246 * 8247 * Formats date according to the directives in the given format 8248 * string. 8249 * The directives begins with a percent (%) character. 8250 * Any text not listed as a directive will be passed through to the 8251 * output string. 8252 * 8253 * The directive consists of a percent (%) character, 8254 * zero or more flags, optional minimum field width, 8255 * optional modifier and a conversion specifier 8256 * as follows. 8257 * 8258 * %<flags><width><modifier><conversion> 8259 * 8260 * Flags: 8261 * - don't pad a numerical output. 8262 * _ use spaces for padding. 8263 * 0 use zeros for padding. 8264 * ^ upcase the result string. 8265 * # change case. 8266 * : use colons for %z. 8267 * 8268 * The minimum field width specifies the minimum width. 8269 * 8270 * The modifier is "E" and "O". 8271 * They are ignored. 8272 * 8273 * Format directives: 8274 * 8275 * Date (Year, Month, Day): 8276 * %Y - Year with century (can be negative, 4 digits at least) 8277 * -0001, 0000, 1995, 2009, 14292, etc. 8278 * %C - year / 100 (round down. 20 in 2009) 8279 * %y - year % 100 (00..99) 8280 * 8281 * %m - Month of the year, zero-padded (01..12) 8282 * %_m blank-padded ( 1..12) 8283 * %-m no-padded (1..12) 8284 * %B - The full month name (``January'') 8285 * %^B uppercased (``JANUARY'') 8286 * %b - The abbreviated month name (``Jan'') 8287 * %^b uppercased (``JAN'') 8288 * %h - Equivalent to %b 8289 * 8290 * %d - Day of the month, zero-padded (01..31) 8291 * %-d no-padded (1..31) 8292 * %e - Day of the month, blank-padded ( 1..31) 8293 * 8294 * %j - Day of the year (001..366) 8295 * 8296 * Time (Hour, Minute, Second, Subsecond): 8297 * %H - Hour of the day, 24-hour clock, zero-padded (00..23) 8298 * %k - Hour of the day, 24-hour clock, blank-padded ( 0..23) 8299 * %I - Hour of the day, 12-hour clock, zero-padded (01..12) 8300 * %l - Hour of the day, 12-hour clock, blank-padded ( 1..12) 8301 * %P - Meridian indicator, lowercase (``am'' or ``pm'') 8302 * %p - Meridian indicator, uppercase (``AM'' or ``PM'') 8303 * 8304 * %M - Minute of the hour (00..59) 8305 * 8306 * %S - Second of the minute (00..59) 8307 * 8308 * %L - Millisecond of the second (000..999) 8309 * %N - Fractional seconds digits, default is 9 digits (nanosecond) 8310 * %3N millisecond (3 digits) %15N femtosecond (15 digits) 8311 * %6N microsecond (6 digits) %18N attosecond (18 digits) 8312 * %9N nanosecond (9 digits) %21N zeptosecond (21 digits) 8313 * %12N picosecond (12 digits) %24N yoctosecond (24 digits) 8314 * 8315 * Time zone: 8316 * %z - Time zone as hour and minute offset from UTC (e.g. +0900) 8317 * %:z - hour and minute offset from UTC with a colon (e.g. +09:00) 8318 * %::z - hour, minute and second offset from UTC (e.g. +09:00:00) 8319 * %:::z - hour, minute and second offset from UTC 8320 * (e.g. +09, +09:30, +09:30:30) 8321 * %Z - Time zone abbreviation name or something similar information. 8322 * 8323 * Weekday: 8324 * %A - The full weekday name (``Sunday'') 8325 * %^A uppercased (``SUNDAY'') 8326 * %a - The abbreviated name (``Sun'') 8327 * %^a uppercased (``SUN'') 8328 * %u - Day of the week (Monday is 1, 1..7) 8329 * %w - Day of the week (Sunday is 0, 0..6) 8330 * 8331 * ISO 8601 week-based year and week number: 8332 * The week 1 of YYYY starts with a Monday and includes YYYY-01-04. 8333 * The days in the year before the first week are in the last week of 8334 * the previous year. 8335 * %G - The week-based year 8336 * %g - The last 2 digits of the week-based year (00..99) 8337 * %V - Week number of the week-based year (01..53) 8338 * 8339 * Week number: 8340 * The week 1 of YYYY starts with a Sunday or Monday (according to %U 8341 * or %W). The days in the year before the first week are in week 0. 8342 * %U - Week number of the year. The week starts with Sunday. (00..53) 8343 * %W - Week number of the year. The week starts with Monday. (00..53) 8344 * 8345 * Seconds since the Unix Epoch: 8346 * %s - Number of seconds since 1970-01-01 00:00:00 UTC. 8347 * %Q - Number of milliseconds since 1970-01-01 00:00:00 UTC. 8348 * 8349 * Literal string: 8350 * %n - Newline character (\n) 8351 * %t - Tab character (\t) 8352 * %% - Literal ``%'' character 8353 * 8354 * Combination: 8355 * %c - date and time (%a %b %e %T %Y) 8356 * %D - Date (%m/%d/%y) 8357 * %F - The ISO 8601 date format (%Y-%m-%d) 8358 * %v - VMS date (%e-%b-%Y) 8359 * %x - Same as %D 8360 * %X - Same as %T 8361 * %r - 12-hour time (%I:%M:%S %p) 8362 * %R - 24-hour time (%H:%M) 8363 * %T - 24-hour time (%H:%M:%S) 8364 * %+ - date(1) (%a %b %e %H:%M:%S %Z %Y) 8365 * 8366 * This method is similar to strftime() function defined in ISO C and POSIX. 8367 * Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z) 8368 * are locale dependent in the function. 8369 * However this method is locale independent. 8370 * So, the result may differ even if a same format string is used in other 8371 * systems such as C. 8372 * It is good practice to avoid %x and %X because there are corresponding 8373 * locale independent representations, %D and %T. 8374 * 8375 * Examples: 8376 * 8377 * d = DateTime.new(2007,11,19,8,37,48,"-06:00") 8378 * #=> #<DateTime: 2007-11-19T08:37:48-0600 ...> 8379 * d.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007" 8380 * d.strftime("at %I:%M%p") #=> "at 08:37AM" 8381 * 8382 * Various ISO 8601 formats: 8383 * %Y%m%d => 20071119 Calendar date (basic) 8384 * %F => 2007-11-19 Calendar date (extended) 8385 * %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month 8386 * %Y => 2007 Calendar date, reduced accuracy, specific year 8387 * %C => 20 Calendar date, reduced accuracy, specific century 8388 * %Y%j => 2007323 Ordinal date (basic) 8389 * %Y-%j => 2007-323 Ordinal date (extended) 8390 * %GW%V%u => 2007W471 Week date (basic) 8391 * %G-W%V-%u => 2007-W47-1 Week date (extended) 8392 * %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic) 8393 * %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended) 8394 * %H%M%S => 083748 Local time (basic) 8395 * %T => 08:37:48 Local time (extended) 8396 * %H%M => 0837 Local time, reduced accuracy, specific minute (basic) 8397 * %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended) 8398 * %H => 08 Local time, reduced accuracy, specific hour 8399 * %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic) 8400 * %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended) 8401 * %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic) 8402 * %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended) 8403 * %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic) 8404 * %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended) 8405 * %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic) 8406 * %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended) 8407 * %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic) 8408 * %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended) 8409 * %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic) 8410 * %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended) 8411 * %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic) 8412 * %FT%R => 2007-11-19T08:37 Calendar date and local time (extended) 8413 * %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic) 8414 * %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended) 8415 * %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic) 8416 * %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended) 8417 * 8418 * See also strftime(3) and strptime. 8419 */ 8420static VALUE 8421dt_lite_strftime(int argc, VALUE *argv, VALUE self) 8422{ 8423 return date_strftime_internal(argc, argv, self, 8424 "%Y-%m-%dT%H:%M:%S%:z", set_tmx); 8425} 8426 8427static VALUE 8428iso8601_timediv(VALUE self, VALUE n) 8429{ 8430 VALUE fmt; 8431 8432 n = to_integer(n); 8433 fmt = rb_usascii_str_new2("T%H:%M:%S"); 8434 if (f_gt_p(n, INT2FIX(0))) { 8435 VALUE argv[3]; 8436 8437 get_d1(self); 8438 8439 argv[0] = rb_usascii_str_new2(".%0*d"); 8440 argv[1] = n; 8441 argv[2] = f_round(f_quo(m_sf_in_sec(dat), 8442 f_quo(INT2FIX(1), 8443 f_expt(INT2FIX(10), n)))); 8444 rb_str_append(fmt, rb_f_sprintf(3, argv)); 8445 } 8446 rb_str_append(fmt, rb_usascii_str_new2("%:z")); 8447 return strftimev(RSTRING_PTR(fmt), self, set_tmx); 8448} 8449 8450/* 8451 * call-seq: 8452 * dt.iso8601([n=0]) -> string 8453 * dt.xmlschema([n=0]) -> string 8454 * 8455 * This method is equivalent to strftime('%FT%T'). The optional 8456 * argument n is length of fractional seconds. 8457 * 8458 * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9) 8459 * #=> "2001-02-03T04:05:06.123456789+07:00" 8460 */ 8461static VALUE 8462dt_lite_iso8601(int argc, VALUE *argv, VALUE self) 8463{ 8464 VALUE n; 8465 8466 rb_scan_args(argc, argv, "01", &n); 8467 8468 if (argc < 1) 8469 n = INT2FIX(0); 8470 8471 return f_add(strftimev("%Y-%m-%d", self, set_tmx), 8472 iso8601_timediv(self, n)); 8473} 8474 8475/* 8476 * call-seq: 8477 * dt.rfc3339([n=0]) -> string 8478 * 8479 * This method is equivalent to strftime('%FT%T'). The optional 8480 * argument n is length of fractional seconds. 8481 * 8482 * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').rfc3339(9) 8483 * #=> "2001-02-03T04:05:06.123456789+07:00" 8484 */ 8485static VALUE 8486dt_lite_rfc3339(int argc, VALUE *argv, VALUE self) 8487{ 8488 return dt_lite_iso8601(argc, argv, self); 8489} 8490 8491/* 8492 * call-seq: 8493 * dt.jisx0301([n=0]) -> string 8494 * 8495 * Returns a string in a JIS X 0301 format. The optional argument n 8496 * is length of fractional seconds. 8497 * 8498 * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').jisx0301(9) 8499 * #=> "H13.02.03T04:05:06.123456789+07:00" 8500 */ 8501static VALUE 8502dt_lite_jisx0301(int argc, VALUE *argv, VALUE self) 8503{ 8504 VALUE n, s; 8505 8506 rb_scan_args(argc, argv, "01", &n); 8507 8508 if (argc < 1) 8509 n = INT2FIX(0); 8510 8511 { 8512 get_d1(self); 8513 s = jisx0301_date(m_real_local_jd(dat), 8514 m_real_year(dat)); 8515 return rb_str_append(strftimev(RSTRING_PTR(s), self, set_tmx), 8516 iso8601_timediv(self, n)); 8517 } 8518} 8519 8520/* conversions */ 8521 8522#define f_getlocal(x) rb_funcall(x, rb_intern("getlocal"), 0) 8523#define f_subsec(x) rb_funcall(x, rb_intern("subsec"), 0) 8524#define f_utc_offset(x) rb_funcall(x, rb_intern("utc_offset"), 0) 8525#define f_local3(x,y,m,d) rb_funcall(x, rb_intern("local"), 3, y, m, d) 8526#define f_utc6(x,y,m,d,h,min,s) rb_funcall(x, rb_intern("utc"), 6,\ 8527 y, m, d, h, min, s) 8528 8529/* 8530 * call-seq: 8531 * t.to_time -> time 8532 * 8533 * Returns a copy of self as local mode. 8534 */ 8535static VALUE 8536time_to_time(VALUE self) 8537{ 8538 return f_getlocal(self); 8539} 8540 8541/* 8542 * call-seq: 8543 * t.to_date -> date 8544 * 8545 * Returns a Date object which denotes self. 8546 */ 8547static VALUE 8548time_to_date(VALUE self) 8549{ 8550 VALUE y, nth, ret; 8551 int ry, m, d; 8552 8553 y = f_year(self); 8554 m = FIX2INT(f_mon(self)); 8555 d = FIX2INT(f_mday(self)); 8556 8557 decode_year(y, -1, &nth, &ry); 8558 8559 ret = d_simple_new_internal(cDate, 8560 nth, 0, 8561 GREGORIAN, 8562 ry, m, d, 8563 HAVE_CIVIL); 8564 { 8565 get_d1(ret); 8566 set_sg(dat, DEFAULT_SG); 8567 } 8568 return ret; 8569} 8570 8571/* 8572 * call-seq: 8573 * t.to_datetime -> datetime 8574 * 8575 * Returns a DateTime object which denotes self. 8576 */ 8577static VALUE 8578time_to_datetime(VALUE self) 8579{ 8580 VALUE y, sf, nth, ret; 8581 int ry, m, d, h, min, s, of; 8582 8583 y = f_year(self); 8584 m = FIX2INT(f_mon(self)); 8585 d = FIX2INT(f_mday(self)); 8586 8587 h = FIX2INT(f_hour(self)); 8588 min = FIX2INT(f_min(self)); 8589 s = FIX2INT(f_sec(self)); 8590 if (s == 60) 8591 s = 59; 8592 8593 sf = sec_to_ns(f_subsec(self)); 8594 of = FIX2INT(f_utc_offset(self)); 8595 8596 decode_year(y, -1, &nth, &ry); 8597 8598 ret = d_complex_new_internal(cDateTime, 8599 nth, 0, 8600 0, sf, 8601 of, DEFAULT_SG, 8602 ry, m, d, 8603 h, min, s, 8604 HAVE_CIVIL | HAVE_TIME); 8605 { 8606 get_d1(ret); 8607 set_sg(dat, DEFAULT_SG); 8608 } 8609 return ret; 8610} 8611 8612/* 8613 * call-seq: 8614 * d.to_time -> time 8615 * 8616 * Returns a Time object which denotes self. 8617 */ 8618static VALUE 8619date_to_time(VALUE self) 8620{ 8621 get_d1(self); 8622 8623 return f_local3(rb_cTime, 8624 m_real_year(dat), 8625 INT2FIX(m_mon(dat)), 8626 INT2FIX(m_mday(dat))); 8627} 8628 8629/* 8630 * call-seq: 8631 * d.to_date -> self 8632 * 8633 * Returns self; 8634 */ 8635static VALUE 8636date_to_date(VALUE self) 8637{ 8638 return self; 8639} 8640 8641/* 8642 * call-seq: 8643 * d.to_datetime -> datetime 8644 * 8645 * Returns a DateTime object which denotes self. 8646 */ 8647static VALUE 8648date_to_datetime(VALUE self) 8649{ 8650 get_d1a(self); 8651 8652 if (simple_dat_p(adat)) { 8653 VALUE new = d_lite_s_alloc_simple(cDateTime); 8654 { 8655 get_d1b(new); 8656 bdat->s = adat->s; 8657 return new; 8658 } 8659 } 8660 else { 8661 VALUE new = d_lite_s_alloc_complex(cDateTime); 8662 { 8663 get_d1b(new); 8664 bdat->c = adat->c; 8665 bdat->c.df = 0; 8666 bdat->c.sf = INT2FIX(0); 8667#ifndef USE_PACK 8668 bdat->c.hour = 0; 8669 bdat->c.min = 0; 8670 bdat->c.sec = 0; 8671#else 8672 bdat->c.pc = PACK5(EX_MON(adat->c.pc), EX_MDAY(adat->c.pc), 8673 0, 0, 0); 8674 bdat->c.flags |= HAVE_DF | HAVE_TIME; 8675#endif 8676 return new; 8677 } 8678 } 8679} 8680 8681/* 8682 * call-seq: 8683 * dt.to_time -> time 8684 * 8685 * Returns a Time object which denotes self. 8686 */ 8687static VALUE 8688datetime_to_time(VALUE self) 8689{ 8690 volatile VALUE dup = dup_obj_with_new_offset(self, 0); 8691 { 8692 VALUE t; 8693 8694 get_d1(dup); 8695 8696 t = f_utc6(rb_cTime, 8697 m_real_year(dat), 8698 INT2FIX(m_mon(dat)), 8699 INT2FIX(m_mday(dat)), 8700 INT2FIX(m_hour(dat)), 8701 INT2FIX(m_min(dat)), 8702 f_add(INT2FIX(m_sec(dat)), 8703 m_sf_in_sec(dat))); 8704 return f_getlocal(t); 8705 } 8706} 8707 8708/* 8709 * call-seq: 8710 * dt.to_date -> date 8711 * 8712 * Returns a Date object which denotes self. 8713 */ 8714static VALUE 8715datetime_to_date(VALUE self) 8716{ 8717 get_d1a(self); 8718 8719 if (simple_dat_p(adat)) { 8720 VALUE new = d_lite_s_alloc_simple(cDate); 8721 { 8722 get_d1b(new); 8723 bdat->s = adat->s; 8724 bdat->s.jd = m_local_jd(adat); 8725 return new; 8726 } 8727 } 8728 else { 8729 VALUE new = d_lite_s_alloc_simple(cDate); 8730 { 8731 get_d1b(new); 8732 copy_complex_to_simple(&bdat->s, &adat->c) 8733 bdat->s.jd = m_local_jd(adat); 8734 bdat->s.flags &= ~(HAVE_DF | HAVE_TIME | COMPLEX_DAT); 8735 return new; 8736 } 8737 } 8738} 8739 8740/* 8741 * call-seq: 8742 * dt.to_datetime -> self 8743 * 8744 * Returns self. 8745 */ 8746static VALUE 8747datetime_to_datetime(VALUE self) 8748{ 8749 return self; 8750} 8751 8752#ifndef NDEBUG 8753/* tests */ 8754 8755#define MIN_YEAR -4713 8756#define MAX_YEAR 1000000 8757#define MIN_JD -327 8758#define MAX_JD 366963925 8759 8760static int 8761test_civil(int from, int to, double sg) 8762{ 8763 int j; 8764 8765 fprintf(stderr, "test_civil: %d...%d (%d) - %.0f\n", 8766 from, to, to - from, sg); 8767 for (j = from; j <= to; j++) { 8768 int y, m, d, rj, ns; 8769 8770 c_jd_to_civil(j, sg, &y, &m, &d); 8771 c_civil_to_jd(y, m, d, sg, &rj, &ns); 8772 if (j != rj) { 8773 fprintf(stderr, "%d != %d\n", j, rj); 8774 return 0; 8775 } 8776 } 8777 return 1; 8778} 8779 8780static VALUE 8781date_s_test_civil(VALUE klass) 8782{ 8783 if (!test_civil(MIN_JD, MIN_JD + 366, GREGORIAN)) 8784 return Qfalse; 8785 if (!test_civil(2305814, 2598007, GREGORIAN)) 8786 return Qfalse; 8787 if (!test_civil(MAX_JD - 366, MAX_JD, GREGORIAN)) 8788 return Qfalse; 8789 8790 if (!test_civil(MIN_JD, MIN_JD + 366, ITALY)) 8791 return Qfalse; 8792 if (!test_civil(2305814, 2598007, ITALY)) 8793 return Qfalse; 8794 if (!test_civil(MAX_JD - 366, MAX_JD, ITALY)) 8795 return Qfalse; 8796 8797 return Qtrue; 8798} 8799 8800static int 8801test_ordinal(int from, int to, double sg) 8802{ 8803 int j; 8804 8805 fprintf(stderr, "test_ordinal: %d...%d (%d) - %.0f\n", 8806 from, to, to - from, sg); 8807 for (j = from; j <= to; j++) { 8808 int y, d, rj, ns; 8809 8810 c_jd_to_ordinal(j, sg, &y, &d); 8811 c_ordinal_to_jd(y, d, sg, &rj, &ns); 8812 if (j != rj) { 8813 fprintf(stderr, "%d != %d\n", j, rj); 8814 return 0; 8815 } 8816 } 8817 return 1; 8818} 8819 8820static VALUE 8821date_s_test_ordinal(VALUE klass) 8822{ 8823 if (!test_ordinal(MIN_JD, MIN_JD + 366, GREGORIAN)) 8824 return Qfalse; 8825 if (!test_ordinal(2305814, 2598007, GREGORIAN)) 8826 return Qfalse; 8827 if (!test_ordinal(MAX_JD - 366, MAX_JD, GREGORIAN)) 8828 return Qfalse; 8829 8830 if (!test_ordinal(MIN_JD, MIN_JD + 366, ITALY)) 8831 return Qfalse; 8832 if (!test_ordinal(2305814, 2598007, ITALY)) 8833 return Qfalse; 8834 if (!test_ordinal(MAX_JD - 366, MAX_JD, ITALY)) 8835 return Qfalse; 8836 8837 return Qtrue; 8838} 8839 8840static int 8841test_commercial(int from, int to, double sg) 8842{ 8843 int j; 8844 8845 fprintf(stderr, "test_commercial: %d...%d (%d) - %.0f\n", 8846 from, to, to - from, sg); 8847 for (j = from; j <= to; j++) { 8848 int y, w, d, rj, ns; 8849 8850 c_jd_to_commercial(j, sg, &y, &w, &d); 8851 c_commercial_to_jd(y, w, d, sg, &rj, &ns); 8852 if (j != rj) { 8853 fprintf(stderr, "%d != %d\n", j, rj); 8854 return 0; 8855 } 8856 } 8857 return 1; 8858} 8859 8860static VALUE 8861date_s_test_commercial(VALUE klass) 8862{ 8863 if (!test_commercial(MIN_JD, MIN_JD + 366, GREGORIAN)) 8864 return Qfalse; 8865 if (!test_commercial(2305814, 2598007, GREGORIAN)) 8866 return Qfalse; 8867 if (!test_commercial(MAX_JD - 366, MAX_JD, GREGORIAN)) 8868 return Qfalse; 8869 8870 if (!test_commercial(MIN_JD, MIN_JD + 366, ITALY)) 8871 return Qfalse; 8872 if (!test_commercial(2305814, 2598007, ITALY)) 8873 return Qfalse; 8874 if (!test_commercial(MAX_JD - 366, MAX_JD, ITALY)) 8875 return Qfalse; 8876 8877 return Qtrue; 8878} 8879 8880static int 8881test_weeknum(int from, int to, int f, double sg) 8882{ 8883 int j; 8884 8885 fprintf(stderr, "test_weeknum: %d...%d (%d) - %.0f\n", 8886 from, to, to - from, sg); 8887 for (j = from; j <= to; j++) { 8888 int y, w, d, rj, ns; 8889 8890 c_jd_to_weeknum(j, f, sg, &y, &w, &d); 8891 c_weeknum_to_jd(y, w, d, f, sg, &rj, &ns); 8892 if (j != rj) { 8893 fprintf(stderr, "%d != %d\n", j, rj); 8894 return 0; 8895 } 8896 } 8897 return 1; 8898} 8899 8900static VALUE 8901date_s_test_weeknum(VALUE klass) 8902{ 8903 int f; 8904 8905 for (f = 0; f <= 1; f++) { 8906 if (!test_weeknum(MIN_JD, MIN_JD + 366, f, GREGORIAN)) 8907 return Qfalse; 8908 if (!test_weeknum(2305814, 2598007, f, GREGORIAN)) 8909 return Qfalse; 8910 if (!test_weeknum(MAX_JD - 366, MAX_JD, f, GREGORIAN)) 8911 return Qfalse; 8912 8913 if (!test_weeknum(MIN_JD, MIN_JD + 366, f, ITALY)) 8914 return Qfalse; 8915 if (!test_weeknum(2305814, 2598007, f, ITALY)) 8916 return Qfalse; 8917 if (!test_weeknum(MAX_JD - 366, MAX_JD, f, ITALY)) 8918 return Qfalse; 8919 } 8920 8921 return Qtrue; 8922} 8923 8924static int 8925test_nth_kday(int from, int to, double sg) 8926{ 8927 int j; 8928 8929 fprintf(stderr, "test_nth_kday: %d...%d (%d) - %.0f\n", 8930 from, to, to - from, sg); 8931 for (j = from; j <= to; j++) { 8932 int y, m, n, k, rj, ns; 8933 8934 c_jd_to_nth_kday(j, sg, &y, &m, &n, &k); 8935 c_nth_kday_to_jd(y, m, n, k, sg, &rj, &ns); 8936 if (j != rj) { 8937 fprintf(stderr, "%d != %d\n", j, rj); 8938 return 0; 8939 } 8940 } 8941 return 1; 8942} 8943 8944static VALUE 8945date_s_test_nth_kday(VALUE klass) 8946{ 8947 if (!test_nth_kday(MIN_JD, MIN_JD + 366, GREGORIAN)) 8948 return Qfalse; 8949 if (!test_nth_kday(2305814, 2598007, GREGORIAN)) 8950 return Qfalse; 8951 if (!test_nth_kday(MAX_JD - 366, MAX_JD, GREGORIAN)) 8952 return Qfalse; 8953 8954 if (!test_nth_kday(MIN_JD, MIN_JD + 366, ITALY)) 8955 return Qfalse; 8956 if (!test_nth_kday(2305814, 2598007, ITALY)) 8957 return Qfalse; 8958 if (!test_nth_kday(MAX_JD - 366, MAX_JD, ITALY)) 8959 return Qfalse; 8960 8961 return Qtrue; 8962} 8963 8964static int 8965test_unit_v2v(VALUE i, 8966 VALUE (* conv1)(VALUE), 8967 VALUE (* conv2)(VALUE)) 8968{ 8969 VALUE c, o; 8970 c = (*conv1)(i); 8971 o = (*conv2)(c); 8972 return f_eqeq_p(o, i); 8973} 8974 8975static int 8976test_unit_v2v_iter2(VALUE (* conv1)(VALUE), 8977 VALUE (* conv2)(VALUE)) 8978{ 8979 if (!test_unit_v2v(INT2FIX(0), conv1, conv2)) 8980 return 0; 8981 if (!test_unit_v2v(INT2FIX(1), conv1, conv2)) 8982 return 0; 8983 if (!test_unit_v2v(INT2FIX(2), conv1, conv2)) 8984 return 0; 8985 if (!test_unit_v2v(INT2FIX(3), conv1, conv2)) 8986 return 0; 8987 if (!test_unit_v2v(INT2FIX(11), conv1, conv2)) 8988 return 0; 8989 if (!test_unit_v2v(INT2FIX(65535), conv1, conv2)) 8990 return 0; 8991 if (!test_unit_v2v(INT2FIX(1073741823), conv1, conv2)) 8992 return 0; 8993 if (!test_unit_v2v(INT2NUM(1073741824), conv1, conv2)) 8994 return 0; 8995 if (!test_unit_v2v(rb_rational_new2(INT2FIX(0), INT2FIX(1)), conv1, conv2)) 8996 return 0; 8997 if (!test_unit_v2v(rb_rational_new2(INT2FIX(1), INT2FIX(1)), conv1, conv2)) 8998 return 0; 8999 if (!test_unit_v2v(rb_rational_new2(INT2FIX(1), INT2FIX(2)), conv1, conv2)) 9000 return 0; 9001 if (!test_unit_v2v(rb_rational_new2(INT2FIX(2), INT2FIX(3)), conv1, conv2)) 9002 return 0; 9003 return 1; 9004} 9005 9006static int 9007test_unit_v2v_iter(VALUE (* conv1)(VALUE), 9008 VALUE (* conv2)(VALUE)) 9009{ 9010 if (!test_unit_v2v_iter2(conv1, conv2)) 9011 return 0; 9012 if (!test_unit_v2v_iter2(conv2, conv1)) 9013 return 0; 9014 return 1; 9015} 9016 9017static VALUE 9018date_s_test_unit_conv(VALUE klass) 9019{ 9020 if (!test_unit_v2v_iter(sec_to_day, day_to_sec)) 9021 return Qfalse; 9022 if (!test_unit_v2v_iter(ms_to_sec, sec_to_ms)) 9023 return Qfalse; 9024 if (!test_unit_v2v_iter(ns_to_day, day_to_ns)) 9025 return Qfalse; 9026 if (!test_unit_v2v_iter(ns_to_sec, sec_to_ns)) 9027 return Qfalse; 9028 return Qtrue; 9029} 9030 9031static VALUE 9032date_s_test_all(VALUE klass) 9033{ 9034 if (date_s_test_civil(klass) == Qfalse) 9035 return Qfalse; 9036 if (date_s_test_ordinal(klass) == Qfalse) 9037 return Qfalse; 9038 if (date_s_test_commercial(klass) == Qfalse) 9039 return Qfalse; 9040 if (date_s_test_weeknum(klass) == Qfalse) 9041 return Qfalse; 9042 if (date_s_test_nth_kday(klass) == Qfalse) 9043 return Qfalse; 9044 if (date_s_test_unit_conv(klass) == Qfalse) 9045 return Qfalse; 9046 return Qtrue; 9047} 9048#endif 9049 9050static const char *monthnames[] = { 9051 NULL, 9052 "January", "February", "March", 9053 "April", "May", "June", 9054 "July", "August", "September", 9055 "October", "November", "December" 9056}; 9057 9058static const char *abbr_monthnames[] = { 9059 NULL, 9060 "Jan", "Feb", "Mar", "Apr", 9061 "May", "Jun", "Jul", "Aug", 9062 "Sep", "Oct", "Nov", "Dec" 9063}; 9064 9065static const char *daynames[] = { 9066 "Sunday", "Monday", "Tuesday", "Wednesday", 9067 "Thursday", "Friday", "Saturday" 9068}; 9069 9070static const char *abbr_daynames[] = { 9071 "Sun", "Mon", "Tue", "Wed", 9072 "Thu", "Fri", "Sat" 9073}; 9074 9075static VALUE 9076mk_ary_of_str(long len, const char *a[]) 9077{ 9078 VALUE o; 9079 long i; 9080 9081 o = rb_ary_new2(len); 9082 for (i = 0; i < len; i++) { 9083 VALUE e; 9084 9085 if (!a[i]) 9086 e = Qnil; 9087 else { 9088 e = rb_usascii_str_new2(a[i]); 9089 rb_obj_freeze(e); 9090 } 9091 rb_ary_push(o, e); 9092 } 9093 rb_obj_freeze(o); 9094 return o; 9095} 9096 9097void 9098Init_date_core(void) 9099{ 9100#undef rb_intern 9101#define rb_intern(str) rb_intern_const(str) 9102 9103 assert(fprintf(stderr, "assert() is now active\n")); 9104 9105 id_cmp = rb_intern("<=>"); 9106 id_le_p = rb_intern("<="); 9107 id_ge_p = rb_intern(">="); 9108 id_eqeq_p = rb_intern("=="); 9109 9110 half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2)); 9111 9112#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS 9113 day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS * 9114 SECOND_IN_NANOSECONDS); 9115#elif defined HAVE_LONG_LONG 9116 day_in_nanoseconds = LL2NUM((LONG_LONG)DAY_IN_SECONDS * 9117 SECOND_IN_NANOSECONDS); 9118#else 9119 day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS), 9120 INT2FIX(SECOND_IN_NANOSECONDS)); 9121#endif 9122 9123 rb_gc_register_mark_object(half_days_in_day); 9124 rb_gc_register_mark_object(day_in_nanoseconds); 9125 9126 positive_inf = +INFINITY; 9127 negative_inf = -INFINITY; 9128 9129 /* 9130 * date and datetime class - Tadayoshi Funaba 1998-2011 9131 * 9132 * 'date' provides two classes Date and DateTime. 9133 * 9134 * == Terms and definitions 9135 * 9136 * Some terms and definitions are based on ISO 8601 and JIS X 0301. 9137 * 9138 * === calendar date 9139 * 9140 * The calendar date is a particular day of a calendar year, 9141 * identified by its ordinal number within a calendar month within 9142 * that year. 9143 * 9144 * In those classes, this is so-called "civil". 9145 * 9146 * === ordinal date 9147 * 9148 * The ordinal date is a particular day of a calendar year identified 9149 * by its ordinal number within the year. 9150 * 9151 * In those classes, this is so-called "ordinal". 9152 * 9153 * === week date 9154 * 9155 * The week date is a date identified by calendar week and day numbers. 9156 * 9157 * The calendar week is a seven day period within a calendar year, 9158 * starting on a Monday and identified by its ordinal number within 9159 * the year; the first calendar week of the year is the one that 9160 * includes the first Thursday of that year. In the Gregorian 9161 * calendar, this is equivalent to the week which includes January 4. 9162 * 9163 * In those classes, this so-called "commercial". 9164 * 9165 * === julian day number 9166 * 9167 * The Julian day number is in elapsed days since noon (Greenwich mean 9168 * time) on January 1, 4713 BCE (in the Julian calendar). 9169 * 9170 * In this document, the astronomical Julian day number is same as the 9171 * original Julian day number. And the chronological Julian day 9172 * number is a variation of the Julian day number. Its days begin at 9173 * midnight on local time. 9174 * 9175 * In this document, when the term "Julian day number" simply appears, 9176 * it just refers to "chronological Julian day number", not the 9177 * original. 9178 * 9179 * In those classes, those are so-called "ajd" and "jd". 9180 * 9181 * === modified julian day number 9182 * 9183 * The modified Julian day number is in elapsed days since midnight 9184 * (Coordinated universal time) on November 17, 1858 CE (in the 9185 * Gregorian calendar). 9186 * 9187 * In this document, the astronomical modified Julian day number is 9188 * same as the original modified Julian day number. And the 9189 * chronological modified Julian day number is a variation of the 9190 * modified Julian day number. Its days begin at midnight on local 9191 * time. 9192 * 9193 * In this document, when the term "modified Julian day number" simply 9194 * appears, it just refers to "chronological modified Julian day 9195 * number", not the original. 9196 * 9197 * In those classes, this is so-called "mjd". 9198 * 9199 * 9200 * == Date 9201 * 9202 * A subclass of Object includes Comparable module, easily handles 9203 * date. 9204 * 9205 * Date object is created with Date::new, Date::jd, Date::ordinal, 9206 * Date::commercial, Date::parse, Date::strptime, Date::today, 9207 * Time#to_date or etc. 9208 * 9209 * require 'date' 9210 * 9211 * Date.new(2001,2,3) #=> #<Date: 2001-02-03 ...> 9212 * Date.jd(2451944) #=> #<Date: 2001-02-03 ...> 9213 * Date.ordinal(2001,34) #=> #<Date: 2001-02-03 ...> 9214 * Date.commercial(2001,5,6) #=> #<Date: 2001-02-03 ...> 9215 * Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...> 9216 * Date.strptime('03-02-2001', '%d-%m-%Y') 9217 * #=> #<Date: 2001-02-03 ...> 9218 * Time.new(2001,2,3).to_date #=> #<Date: 2001-02-03 ...> 9219 * 9220 * All date objects are immutable; hence cannot modify themselves. 9221 * 9222 * The concept of this date object can be represented as a tuple 9223 * of the day count, the offset and the day of calendar reform. 9224 * 9225 * The day count denotes the absolute position of a temporal 9226 * dimension. The offset is relative adjustment, which determines 9227 * decoded local time with the day count. The day of calendar 9228 * reform denotes the start day of the new style. The old style 9229 * of the West is the Julian calendar which was adopted by 9230 * Caersar. The new style is the Gregorian calendar, which is the 9231 * current civil calendar of many countries. 9232 * 9233 * The day count is virtually the astronomical Julian day number. 9234 * The offset in this class is usually zero, and cannot be 9235 * specified directly. 9236 * 9237 * An optional argument the day of calendar reform (start) as a 9238 * Julian day number, which should be 2298874 to 2426355 or -/+oo. 9239 * The default value is Date::ITALY (2299161=1582-10-15). See 9240 * also sample/cal.rb. 9241 * 9242 * $ ruby sample/cal.rb -c it 10 1582 9243 * October 1582 9244 * S M Tu W Th F S 9245 * 1 2 3 4 15 16 9246 * 17 18 19 20 21 22 23 9247 * 24 25 26 27 28 29 30 9248 * 31 9249 * 9250 * $ ruby sample/cal.rb -c gb 9 1752 9251 * September 1752 9252 * S M Tu W Th F S 9253 * 1 2 14 15 16 9254 * 17 18 19 20 21 22 23 9255 * 24 25 26 27 28 29 30 9256 * 9257 * Date object has various methods. See each reference. 9258 * 9259 * d = Date.parse('3rd Feb 2001') 9260 * #=> #<Date: 2001-02-03 ...> 9261 * d.year #=> 2001 9262 * d.mon #=> 2 9263 * d.mday #=> 3 9264 * d.wday #=> 6 9265 * d += 1 #=> #<Date: 2001-02-04 ...> 9266 * d.strftime('%a %d %b %Y') #=> "Sun 04 Feb 2001" 9267 * 9268 * 9269 * == DateTime 9270 * 9271 * A subclass of Date easily handles date, hour, minute, second and 9272 * offset. 9273 * 9274 * DateTime does not consider any leapseconds, does not track 9275 * any summer time rules. 9276 * 9277 * DateTime object is created with DateTime::new, DateTime::jd, 9278 * DateTime::ordinal, DateTime::commercial, DateTime::parse, 9279 * DateTime::strptime, DateTime::now, Time#to_datetime or etc. 9280 * 9281 * require 'date' 9282 * 9283 * DateTime.new(2001,2,3,4,5,6) 9284 * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> 9285 * 9286 * The last element of day, hour, minute or senond can be 9287 * fractional number. The fractional number's precision is assumed 9288 * at most nanosecond. 9289 * 9290 * DateTime.new(2001,2,3.5) 9291 * #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...> 9292 * 9293 * An optional argument the offset indicates the difference 9294 * between the local time and UTC. For example, Rational(3,24) 9295 * represents ahead of 3 hours of UTC, Rational(-5,24) represents 9296 * behind of 5 hours of UTC. The offset should be -1 to +1, and 9297 * its precision is assumed at most second. The default value is 9298 * zero (equals to UTC). 9299 * 9300 * DateTime.new(2001,2,3,4,5,6,Rational(3,24)) 9301 * #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...> 9302 * also accepts string form. 9303 * 9304 * DateTime.new(2001,2,3,4,5,6,'+03:00') 9305 * #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...> 9306 * 9307 * An optional argument the day of calendar reform (start) denotes 9308 * a Julian day number, which should be 2298874 to 2426355 or 9309 * -/+oo. The default value is Date::ITALY (2299161=1582-10-15). 9310 * 9311 * DateTime object has various methods. See each reference. 9312 * 9313 * d = DateTime.parse('3rd Feb 2001 04:05:06+03:30') 9314 * #=> #<DateTime: 2001-02-03T04:05:06+03:30 ...> 9315 * d.hour #=> 4 9316 * d.min #=> 5 9317 * d.sec #=> 6 9318 * d.offset #=> (7/48) 9319 * d.zone #=> "+03:30" 9320 * d += Rational('1.5') 9321 * #=> #<DateTime: 2001-02-04%16:05:06+03:30 ...> 9322 * d = d.new_offset('+09:00') 9323 * #=> #<DateTime: 2001-02-04%21:35:06+09:00 ...> 9324 * d.strftime('%I:%M:%S %p') 9325 * #=> "09:35:06 PM" 9326 * d > DateTime.new(1999) 9327 * #=> true 9328 */ 9329 cDate = rb_define_class("Date", rb_cObject); 9330 9331 rb_include_module(cDate, rb_mComparable); 9332 9333 /* An array of stirng of full month name in English. The first 9334 * element is nil. 9335 */ 9336 rb_define_const(cDate, "MONTHNAMES", mk_ary_of_str(13, monthnames)); 9337 9338 /* An array of string of abbreviated month name in English. The 9339 * first element is nil. 9340 */ 9341 rb_define_const(cDate, "ABBR_MONTHNAMES", 9342 mk_ary_of_str(13, abbr_monthnames)); 9343 9344 /* An array of string of full name of days of the week in English. 9345 * The first is "Sunday". 9346 */ 9347 rb_define_const(cDate, "DAYNAMES", mk_ary_of_str(7, daynames)); 9348 9349 /* An array of string of abbreviated day name in English. The 9350 * first is "Sun". 9351 */ 9352 rb_define_const(cDate, "ABBR_DAYNAMES", mk_ary_of_str(7, abbr_daynames)); 9353 9354 /* The Julian day number of the day of calendar reform for Italy 9355 * and some catholic countries. 9356 */ 9357 rb_define_const(cDate, "ITALY", INT2FIX(ITALY)); 9358 9359 /* The Julian day number of the day of calendar reform for England 9360 * and her colonies. 9361 */ 9362 rb_define_const(cDate, "ENGLAND", INT2FIX(ENGLAND)); 9363 9364 /* The Julian day number of the day of calendar reform for the 9365 * proleptic Julian calendar 9366 */ 9367 rb_define_const(cDate, "JULIAN", DBL2NUM(JULIAN)); 9368 9369 /* The Julian day number of the day of calendar reform for the 9370 * proleptic Gregorian calendar 9371 */ 9372 rb_define_const(cDate, "GREGORIAN", DBL2NUM(GREGORIAN)); 9373 9374 rb_define_alloc_func(cDate, d_lite_s_alloc); 9375 9376#ifndef NDEBUG 9377#define de_define_private_method rb_define_private_method 9378 de_define_private_method(CLASS_OF(cDate), "_valid_jd?", 9379 date_s__valid_jd_p, -1); 9380 de_define_private_method(CLASS_OF(cDate), "_valid_ordinal?", 9381 date_s__valid_ordinal_p, -1); 9382 de_define_private_method(CLASS_OF(cDate), "_valid_civil?", 9383 date_s__valid_civil_p, -1); 9384 de_define_private_method(CLASS_OF(cDate), "_valid_date?", 9385 date_s__valid_civil_p, -1); 9386 de_define_private_method(CLASS_OF(cDate), "_valid_commercial?", 9387 date_s__valid_commercial_p, -1); 9388 de_define_private_method(CLASS_OF(cDate), "_valid_weeknum?", 9389 date_s__valid_weeknum_p, -1); 9390 de_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?", 9391 date_s__valid_nth_kday_p, -1); 9392#endif 9393 9394 rb_define_singleton_method(cDate, "valid_jd?", date_s_valid_jd_p, -1); 9395 rb_define_singleton_method(cDate, "valid_ordinal?", 9396 date_s_valid_ordinal_p, -1); 9397 rb_define_singleton_method(cDate, "valid_civil?", date_s_valid_civil_p, -1); 9398 rb_define_singleton_method(cDate, "valid_date?", date_s_valid_civil_p, -1); 9399 rb_define_singleton_method(cDate, "valid_commercial?", 9400 date_s_valid_commercial_p, -1); 9401 9402#ifndef NDEBUG 9403 de_define_private_method(CLASS_OF(cDate), "valid_weeknum?", 9404 date_s_valid_weeknum_p, -1); 9405 de_define_private_method(CLASS_OF(cDate), "valid_nth_kday?", 9406 date_s_valid_nth_kday_p, -1); 9407 de_define_private_method(CLASS_OF(cDate), "zone_to_diff", 9408 date_s_zone_to_diff, 1); 9409#endif 9410 9411 rb_define_singleton_method(cDate, "julian_leap?", date_s_julian_leap_p, 1); 9412 rb_define_singleton_method(cDate, "gregorian_leap?", 9413 date_s_gregorian_leap_p, 1); 9414 rb_define_singleton_method(cDate, "leap?", 9415 date_s_gregorian_leap_p, 1); 9416 9417#ifndef NDEBUG 9418#define de_define_singleton_method rb_define_singleton_method 9419#define de_define_alias rb_define_alias 9420 de_define_singleton_method(cDate, "new!", date_s_new_bang, -1); 9421 de_define_alias(rb_singleton_class(cDate), "new_l!", "new"); 9422#endif 9423 9424 rb_define_singleton_method(cDate, "jd", date_s_jd, -1); 9425 rb_define_singleton_method(cDate, "ordinal", date_s_ordinal, -1); 9426 rb_define_singleton_method(cDate, "civil", date_s_civil, -1); 9427 rb_define_singleton_method(cDate, "new", date_s_civil, -1); 9428 rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1); 9429 9430#ifndef NDEBUG 9431 de_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1); 9432 de_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1); 9433#endif 9434 9435 rb_define_singleton_method(cDate, "today", date_s_today, -1); 9436 rb_define_singleton_method(cDate, "_strptime", date_s__strptime, -1); 9437 rb_define_singleton_method(cDate, "strptime", date_s_strptime, -1); 9438 rb_define_singleton_method(cDate, "_parse", date_s__parse, -1); 9439 rb_define_singleton_method(cDate, "parse", date_s_parse, -1); 9440 rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, 1); 9441 rb_define_singleton_method(cDate, "iso8601", date_s_iso8601, -1); 9442 rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, 1); 9443 rb_define_singleton_method(cDate, "rfc3339", date_s_rfc3339, -1); 9444 rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, 1); 9445 rb_define_singleton_method(cDate, "xmlschema", date_s_xmlschema, -1); 9446 rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, 1); 9447 rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, 1); 9448 rb_define_singleton_method(cDate, "rfc2822", date_s_rfc2822, -1); 9449 rb_define_singleton_method(cDate, "rfc822", date_s_rfc2822, -1); 9450 rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, 1); 9451 rb_define_singleton_method(cDate, "httpdate", date_s_httpdate, -1); 9452 rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, 1); 9453 rb_define_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1); 9454 9455#ifndef NDEBUG 9456#define de_define_method rb_define_method 9457 de_define_method(cDate, "initialize", d_lite_initialize, -1); 9458#endif 9459 rb_define_method(cDate, "initialize_copy", d_lite_initialize_copy, 1); 9460 9461#ifndef NDEBUG 9462 de_define_method(cDate, "fill", d_lite_fill, 0); 9463#endif 9464 9465 rb_define_method(cDate, "ajd", d_lite_ajd, 0); 9466 rb_define_method(cDate, "amjd", d_lite_amjd, 0); 9467 rb_define_method(cDate, "jd", d_lite_jd, 0); 9468 rb_define_method(cDate, "mjd", d_lite_mjd, 0); 9469 rb_define_method(cDate, "ld", d_lite_ld, 0); 9470 9471 rb_define_method(cDate, "year", d_lite_year, 0); 9472 rb_define_method(cDate, "yday", d_lite_yday, 0); 9473 rb_define_method(cDate, "mon", d_lite_mon, 0); 9474 rb_define_method(cDate, "month", d_lite_mon, 0); 9475 rb_define_method(cDate, "mday", d_lite_mday, 0); 9476 rb_define_method(cDate, "day", d_lite_mday, 0); 9477 rb_define_method(cDate, "day_fraction", d_lite_day_fraction, 0); 9478 9479 rb_define_method(cDate, "cwyear", d_lite_cwyear, 0); 9480 rb_define_method(cDate, "cweek", d_lite_cweek, 0); 9481 rb_define_method(cDate, "cwday", d_lite_cwday, 0); 9482 9483#ifndef NDEBUG 9484 de_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); 9485 de_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); 9486#endif 9487 9488 rb_define_method(cDate, "wday", d_lite_wday, 0); 9489 9490 rb_define_method(cDate, "sunday?", d_lite_sunday_p, 0); 9491 rb_define_method(cDate, "monday?", d_lite_monday_p, 0); 9492 rb_define_method(cDate, "tuesday?", d_lite_tuesday_p, 0); 9493 rb_define_method(cDate, "wednesday?", d_lite_wednesday_p, 0); 9494 rb_define_method(cDate, "thursday?", d_lite_thursday_p, 0); 9495 rb_define_method(cDate, "friday?", d_lite_friday_p, 0); 9496 rb_define_method(cDate, "saturday?", d_lite_saturday_p, 0); 9497 9498#ifndef NDEBUG 9499 de_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2); 9500#endif 9501 9502 rb_define_private_method(cDate, "hour", d_lite_hour, 0); 9503 rb_define_private_method(cDate, "min", d_lite_min, 0); 9504 rb_define_private_method(cDate, "minute", d_lite_min, 0); 9505 rb_define_private_method(cDate, "sec", d_lite_sec, 0); 9506 rb_define_private_method(cDate, "second", d_lite_sec, 0); 9507 rb_define_private_method(cDate, "sec_fraction", d_lite_sec_fraction, 0); 9508 rb_define_private_method(cDate, "second_fraction", d_lite_sec_fraction, 0); 9509 rb_define_private_method(cDate, "offset", d_lite_offset, 0); 9510 rb_define_private_method(cDate, "zone", d_lite_zone, 0); 9511 9512 rb_define_method(cDate, "julian?", d_lite_julian_p, 0); 9513 rb_define_method(cDate, "gregorian?", d_lite_gregorian_p, 0); 9514 rb_define_method(cDate, "leap?", d_lite_leap_p, 0); 9515 9516 rb_define_method(cDate, "start", d_lite_start, 0); 9517 rb_define_method(cDate, "new_start", d_lite_new_start, -1); 9518 rb_define_method(cDate, "italy", d_lite_italy, 0); 9519 rb_define_method(cDate, "england", d_lite_england, 0); 9520 rb_define_method(cDate, "julian", d_lite_julian, 0); 9521 rb_define_method(cDate, "gregorian", d_lite_gregorian, 0); 9522 9523 rb_define_private_method(cDate, "new_offset", d_lite_new_offset, -1); 9524 9525 rb_define_method(cDate, "+", d_lite_plus, 1); 9526 rb_define_method(cDate, "-", d_lite_minus, 1); 9527 9528 rb_define_method(cDate, "next_day", d_lite_next_day, -1); 9529 rb_define_method(cDate, "prev_day", d_lite_prev_day, -1); 9530 rb_define_method(cDate, "next", d_lite_next, 0); 9531 rb_define_method(cDate, "succ", d_lite_next, 0); 9532 9533 rb_define_method(cDate, ">>", d_lite_rshift, 1); 9534 rb_define_method(cDate, "<<", d_lite_lshift, 1); 9535 9536 rb_define_method(cDate, "next_month", d_lite_next_month, -1); 9537 rb_define_method(cDate, "prev_month", d_lite_prev_month, -1); 9538 rb_define_method(cDate, "next_year", d_lite_next_year, -1); 9539 rb_define_method(cDate, "prev_year", d_lite_prev_year, -1); 9540 9541 rb_define_method(cDate, "step", d_lite_step, -1); 9542 rb_define_method(cDate, "upto", d_lite_upto, 1); 9543 rb_define_method(cDate, "downto", d_lite_downto, 1); 9544 9545 rb_define_method(cDate, "<=>", d_lite_cmp, 1); 9546 rb_define_method(cDate, "===", d_lite_equal, 1); 9547 rb_define_method(cDate, "eql?", d_lite_eql_p, 1); 9548 rb_define_method(cDate, "hash", d_lite_hash, 0); 9549 9550 rb_define_method(cDate, "to_s", d_lite_to_s, 0); 9551#ifndef NDEBUG 9552 de_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0); 9553#endif 9554 rb_define_method(cDate, "inspect", d_lite_inspect, 0); 9555 9556 rb_define_method(cDate, "strftime", d_lite_strftime, -1); 9557 9558 rb_define_method(cDate, "asctime", d_lite_asctime, 0); 9559 rb_define_method(cDate, "ctime", d_lite_asctime, 0); 9560 rb_define_method(cDate, "iso8601", d_lite_iso8601, 0); 9561 rb_define_method(cDate, "xmlschema", d_lite_iso8601, 0); 9562 rb_define_method(cDate, "rfc3339", d_lite_rfc3339, 0); 9563 rb_define_method(cDate, "rfc2822", d_lite_rfc2822, 0); 9564 rb_define_method(cDate, "rfc822", d_lite_rfc2822, 0); 9565 rb_define_method(cDate, "httpdate", d_lite_httpdate, 0); 9566 rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0); 9567 9568#ifndef NDEBUG 9569 de_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0); 9570#endif 9571 rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0); 9572 rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1); 9573 rb_define_singleton_method(cDate, "_load", date_s__load, 1); 9574 9575 /* datetime */ 9576 9577 cDateTime = rb_define_class("DateTime", cDate); 9578 9579 rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1); 9580 rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1); 9581 rb_define_singleton_method(cDateTime, "civil", datetime_s_civil, -1); 9582 rb_define_singleton_method(cDateTime, "new", datetime_s_civil, -1); 9583 rb_define_singleton_method(cDateTime, "commercial", 9584 datetime_s_commercial, -1); 9585 9586#ifndef NDEBUG 9587 de_define_singleton_method(cDateTime, "weeknum", 9588 datetime_s_weeknum, -1); 9589 de_define_singleton_method(cDateTime, "nth_kday", 9590 datetime_s_nth_kday, -1); 9591#endif 9592 9593 rb_undef_method(CLASS_OF(cDateTime), "today"); 9594 9595 rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1); 9596 rb_define_singleton_method(cDateTime, "_strptime", 9597 datetime_s__strptime, -1); 9598 rb_define_singleton_method(cDateTime, "strptime", 9599 datetime_s_strptime, -1); 9600 rb_define_singleton_method(cDateTime, "parse", 9601 datetime_s_parse, -1); 9602 rb_define_singleton_method(cDateTime, "iso8601", 9603 datetime_s_iso8601, -1); 9604 rb_define_singleton_method(cDateTime, "rfc3339", 9605 datetime_s_rfc3339, -1); 9606 rb_define_singleton_method(cDateTime, "xmlschema", 9607 datetime_s_xmlschema, -1); 9608 rb_define_singleton_method(cDateTime, "rfc2822", 9609 datetime_s_rfc2822, -1); 9610 rb_define_singleton_method(cDateTime, "rfc822", 9611 datetime_s_rfc2822, -1); 9612 rb_define_singleton_method(cDateTime, "httpdate", 9613 datetime_s_httpdate, -1); 9614 rb_define_singleton_method(cDateTime, "jisx0301", 9615 datetime_s_jisx0301, -1); 9616 9617#define f_public(m,s) rb_funcall(m, rb_intern("public"), 1,\ 9618 ID2SYM(rb_intern(s))) 9619 9620 f_public(cDateTime, "hour"); 9621 f_public(cDateTime, "min"); 9622 f_public(cDateTime, "minute"); 9623 f_public(cDateTime, "sec"); 9624 f_public(cDateTime, "second"); 9625 f_public(cDateTime, "sec_fraction"); 9626 f_public(cDateTime, "second_fraction"); 9627 f_public(cDateTime, "offset"); 9628 f_public(cDateTime, "zone"); 9629 f_public(cDateTime, "new_offset"); 9630 9631 rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0); 9632 9633 rb_define_method(cDateTime, "strftime", dt_lite_strftime, -1); 9634 9635 rb_define_method(cDateTime, "iso8601", dt_lite_iso8601, -1); 9636 rb_define_method(cDateTime, "xmlschema", dt_lite_iso8601, -1); 9637 rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1); 9638 rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1); 9639 9640 /* conversions */ 9641 9642 rb_define_method(rb_cTime, "to_time", time_to_time, 0); 9643 rb_define_method(rb_cTime, "to_date", time_to_date, 0); 9644 rb_define_method(rb_cTime, "to_datetime", time_to_datetime, 0); 9645 9646 rb_define_method(cDate, "to_time", date_to_time, 0); 9647 rb_define_method(cDate, "to_date", date_to_date, 0); 9648 rb_define_method(cDate, "to_datetime", date_to_datetime, 0); 9649 9650 rb_define_method(cDateTime, "to_time", datetime_to_time, 0); 9651 rb_define_method(cDateTime, "to_date", datetime_to_date, 0); 9652 rb_define_method(cDateTime, "to_datetime", datetime_to_datetime, 0); 9653 9654#ifndef NDEBUG 9655 /* tests */ 9656 9657 de_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0); 9658 de_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0); 9659 de_define_singleton_method(cDate, "test_commercial", 9660 date_s_test_commercial, 0); 9661 de_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0); 9662 de_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0); 9663 de_define_singleton_method(cDate, "test_unit_conv", 9664 date_s_test_unit_conv, 0); 9665 de_define_singleton_method(cDate, "test_all", date_s_test_all, 0); 9666#endif 9667} 9668 9669/* 9670Local variables: 9671c-file-style: "ruby" 9672End: 9673*/ 9674