Ruby: ext/date/date_core.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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