Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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