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