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