Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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