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