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