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