Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

time.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 time.c -
4
5 $Author: nagachika $
6 created at: Tue Dec 28 14:31:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10 **********************************************************************/
11
12 #include "ruby/ruby.h"
13 #include <sys/types.h>
14 #include <time.h>
15 #include <errno.h>
16 #include "ruby/encoding.h"
17 #include "internal.h"
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <float.h>
24 #include <math.h>
25
26 #ifdef HAVE_STRINGS_H
27 #include <strings.h>
28 #endif
29
30 #if defined(HAVE_SYS_TIME_H)
31 #include <sys/time.h>
32 #endif
33
34 #include "timev.h"
35
36 static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
37 static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;
38
39 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
40 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
41 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
42 #define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
43
44 static int
45 eq(VALUE x, VALUE y)
46 {
47 if (FIXNUM_P(x) && FIXNUM_P(y)) {
48 return x == y;
49 }
50 return RTEST(rb_funcall(x, id_eq, 1, y));
51 }
52
53 static int
54 cmp(VALUE x, VALUE y)
55 {
56 if (FIXNUM_P(x) && FIXNUM_P(y)) {
57 if ((long)x < (long)y)
58 return -1;
59 if ((long)x > (long)y)
60 return 1;
61 return 0;
62 }
63 return rb_cmpint(rb_funcall(x, id_cmp, 1, y), x, y);
64 }
65
66 #define ne(x,y) (!eq((x),(y)))
67 #define lt(x,y) (cmp((x),(y)) < 0)
68 #define gt(x,y) (cmp((x),(y)) > 0)
69 #define le(x,y) (cmp((x),(y)) <= 0)
70 #define ge(x,y) (cmp((x),(y)) >= 0)
71
72 static VALUE
73 add(VALUE x, VALUE y)
74 {
75 if (FIXNUM_P(x) && FIXNUM_P(y)) {
76 long l = FIX2LONG(x) + FIX2LONG(y);
77 if (FIXABLE(l)) return LONG2FIX(l);
78 return LONG2NUM(l);
79 }
80 if (RB_TYPE_P(x, T_BIGNUM)) return rb_big_plus(x, y);
81 return rb_funcall(x, '+', 1, y);
82 }
83
84 static VALUE
85 sub(VALUE x, VALUE y)
86 {
87 if (FIXNUM_P(x) && FIXNUM_P(y)) {
88 long l = FIX2LONG(x) - FIX2LONG(y);
89 if (FIXABLE(l)) return LONG2FIX(l);
90 return LONG2NUM(l);
91 }
92 if (RB_TYPE_P(x, T_BIGNUM)) return rb_big_minus(x, y);
93 return rb_funcall(x, '-', 1, y);
94 }
95
96 #if !(HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG)
97 static int
98 long_mul(long x, long y, long *z)
99 {
100 unsigned long a, b, c;
101 int s;
102 if (x == 0 || y == 0) {
103 *z = 0;
104 return 1;
105 }
106 if (x < 0) {
107 s = -1;
108 a = (unsigned long)-x;
109 }
110 else {
111 s = 1;
112 a = (unsigned long)x;
113 }
114 if (y < 0) {
115 s = -s;
116 b = (unsigned long)-y;
117 }
118 else {
119 b = (unsigned long)y;
120 }
121 if (a <= ULONG_MAX / b) {
122 c = a * b;
123 if (s < 0) {
124 if (c <= (unsigned long)LONG_MAX + 1) {
125 *z = -(long)c;
126 return 1;
127 }
128 }
129 else {
130 if (c <= (unsigned long)LONG_MAX) {
131 *z = (long)c;
132 return 1;
133 }
134 }
135 }
136 return 0;
137 }
138 #endif
139
140 static VALUE
141 mul(VALUE x, VALUE y)
142 {
143 if (FIXNUM_P(x) && FIXNUM_P(y)) {
144 #if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
145 LONG_LONG ll = (LONG_LONG)FIX2LONG(x) * FIX2LONG(y);
146 if (FIXABLE(ll))
147 return LONG2FIX(ll);
148 return LL2NUM(ll);
149 #else
150 long z;
151 if (long_mul(FIX2LONG(x), FIX2LONG(y), &z))
152 return LONG2NUM(z);
153 #endif
154 }
155 if (RB_TYPE_P(x, T_BIGNUM))
156 return rb_big_mul(x, y);
157 return rb_funcall(x, '*', 1, y);
158 }
159
160 #define div(x,y) (rb_funcall((x), id_div, 1, (y)))
161
162 static VALUE
163 mod(VALUE x, VALUE y)
164 {
165 switch (TYPE(x)) {
166 case T_BIGNUM: return rb_big_modulo(x, y);
167 default: return rb_funcall(x, '%', 1, y);
168 }
169 }
170
171 #define neg(x) (sub(INT2FIX(0), (x)))
172 #define lshift(x,y) (rb_funcall((x), id_lshift, 1, (y)))
173
174 static VALUE
175 quo(VALUE x, VALUE y)
176 {
177 VALUE ret;
178 if (FIXNUM_P(x) && FIXNUM_P(y)) {
179 long a, b, c;
180 a = FIX2LONG(x);
181 b = FIX2LONG(y);
182 if (b == 0) rb_num_zerodiv();
183 c = a / b;
184 if (c * b == a) {
185 return LONG2NUM(c);
186 }
187 }
188 ret = rb_funcall(x, id_quo, 1, y);
189 if (RB_TYPE_P(ret, T_RATIONAL) &&
190 RRATIONAL(ret)->den == INT2FIX(1)) {
191 ret = RRATIONAL(ret)->num;
192 }
193 return ret;
194 }
195
196 #define mulquo(x,y,z) (((y) == (z)) ? (x) : quo(mul((x),(y)),(z)))
197
198 static void
199 divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
200 {
201 VALUE tmp, ary;
202 tmp = rb_funcall(n, id_divmod, 1, d);
203 ary = rb_check_array_type(tmp);
204 if (NIL_P(ary)) {
205 rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
206 rb_obj_classname(tmp));
207 }
208 *q = rb_ary_entry(ary, 0);
209 *r = rb_ary_entry(ary, 1);
210 }
211
212 #if SIZEOF_LONG == 8
213 # define INT64toNUM(x) LONG2NUM(x)
214 # define UINT64toNUM(x) ULONG2NUM(x)
215 #elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
216 # define INT64toNUM(x) LL2NUM(x)
217 # define UINT64toNUM(x) ULL2NUM(x)
218 #endif
219
220 #if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T
221 typedef uint64_t uwideint_t;
222 typedef int64_t wideint_t;
223 typedef uint64_t WIDEVALUE;
224 typedef int64_t SIGNED_WIDEVALUE;
225 # define WIDEVALUE_IS_WIDER 1
226 # define UWIDEINT_MAX UINT64_MAX
227 # define WIDEINT_MAX INT64_MAX
228 # define WIDEINT_MIN INT64_MIN
229 # define FIXWINT_P(tv) ((tv) & 1)
230 # define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
231 # define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG))
232 # define FIXWV_MAX (((int64_t)1 << 62) - 1)
233 # define FIXWV_MIN (-((int64_t)1 << 62))
234 # define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi))
235 # define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i))
236 # define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w))
237 #else
238 typedef unsigned long uwideint_t;
239 typedef long wideint_t;
240 typedef VALUE WIDEVALUE;
241 typedef SIGNED_VALUE SIGNED_WIDEVALUE;
242 # define WIDEVALUE_IS_WIDER 0
243 # define UWIDEINT_MAX ULONG_MAX
244 # define WIDEINT_MAX LONG_MAX
245 # define WIDEINT_MIN LONG_MIN
246 # define FIXWINT_P(v) FIXNUM_P(v)
247 # define FIXWV_MAX FIXNUM_MAX
248 # define FIXWV_MIN FIXNUM_MIN
249 # define FIXWVABLE(i) FIXABLE(i)
250 # define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i))
251 # define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
252 #endif
253
254 #define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
255 #define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
256 #define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
257
258 /* #define STRUCT_WIDEVAL */
259 #ifdef STRUCT_WIDEVAL
260 /* for type checking */
261 typedef struct {
262 WIDEVALUE value;
263 } wideval_t;
264 static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; }
265 # define WIDEVAL_GET(w) ((w).value)
266 #else
267 typedef WIDEVALUE wideval_t;
268 # define WIDEVAL_WRAP(v) (v)
269 # define WIDEVAL_GET(w) (w)
270 #endif
271
272 #if WIDEVALUE_IS_WIDER
273 static inline wideval_t
274 wint2wv(wideint_t wi)
275 {
276 if (FIXWVABLE(wi))
277 return WINT2FIXWV(wi);
278 else
279 return WIDEVAL_WRAP(INT64toNUM(wi));
280 }
281 # define WINT2WV(wi) wint2wv(wi)
282 #else
283 # define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi))
284 #endif
285
286 static inline VALUE
287 w2v(wideval_t w)
288 {
289 #if WIDEVALUE_IS_WIDER
290 if (FIXWV_P(w))
291 return INT64toNUM(FIXWV2WINT(w));
292 return (VALUE)WIDEVAL_GET(w);
293 #else
294 return WIDEVAL_GET(w);
295 #endif
296 }
297
298 #if WIDEVALUE_IS_WIDER
299 static wideval_t
300 v2w_bignum(VALUE v)
301 {
302 int sign;
303 uwideint_t u;
304 sign = rb_integer_pack(v, &u, 1, sizeof(u), 0,
305 INTEGER_PACK_NATIVE_BYTE_ORDER);
306 if (sign == 0)
307 return WINT2FIXWV(0);
308 else if (sign == -1) {
309 if (u <= -FIXWV_MIN)
310 return WINT2FIXWV(-(wideint_t)u);
311 }
312 else if (sign == +1) {
313 if (u <= FIXWV_MAX)
314 return WINT2FIXWV((wideint_t)u);
315 }
316 return WIDEVAL_WRAP(v);
317 }
318 #endif
319
320 static inline wideval_t
321 v2w(VALUE v)
322 {
323 if (RB_TYPE_P(v, T_RATIONAL)) {
324 if (RRATIONAL(v)->den != LONG2FIX(1))
325 return v;
326 v = RRATIONAL(v)->num;
327 }
328 #if WIDEVALUE_IS_WIDER
329 if (FIXNUM_P(v)) {
330 return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(long)v);
331 }
332 else if (RB_TYPE_P(v, T_BIGNUM) &&
333 rb_absint_size(v, NULL) <= sizeof(WIDEVALUE)) {
334 return v2w_bignum(v);
335 }
336 #endif
337 return WIDEVAL_WRAP(v);
338 }
339
340 static int
341 weq(wideval_t wx, wideval_t wy)
342 {
343 #if WIDEVALUE_IS_WIDER
344 if (FIXWV_P(wx) && FIXWV_P(wy)) {
345 return WIDEVAL_GET(wx) == WIDEVAL_GET(wy);
346 }
347 return RTEST(rb_funcall(w2v(wx), id_eq, 1, w2v(wy)));
348 #else
349 return eq(WIDEVAL_GET(wx), WIDEVAL_GET(wy));
350 #endif
351 }
352
353 static int
354 wcmp(wideval_t wx, wideval_t wy)
355 {
356 VALUE x, y;
357 #if WIDEVALUE_IS_WIDER
358 if (FIXWV_P(wx) && FIXWV_P(wy)) {
359 wideint_t a, b;
360 a = FIXWV2WINT(wx);
361 b = FIXWV2WINT(wy);
362 if (a < b)
363 return -1;
364 if (a > b)
365 return 1;
366 return 0;
367 }
368 #endif
369 x = w2v(wx);
370 y = w2v(wy);
371 return rb_cmpint(rb_funcall(x, id_cmp, 1, y), x, y);
372 }
373
374 #define wne(x,y) (!weq((x),(y)))
375 #define wlt(x,y) (wcmp((x),(y)) < 0)
376 #define wgt(x,y) (wcmp((x),(y)) > 0)
377 #define wle(x,y) (wcmp((x),(y)) <= 0)
378 #define wge(x,y) (wcmp((x),(y)) >= 0)
379
380 static wideval_t
381 wadd(wideval_t wx, wideval_t wy)
382 {
383 VALUE x;
384 #if WIDEVALUE_IS_WIDER
385 if (FIXWV_P(wx) && FIXWV_P(wy)) {
386 wideint_t r = FIXWV2WINT(wx) + FIXWV2WINT(wy);
387 return WINT2WV(r);
388 }
389 else
390 #endif
391 x = w2v(wx);
392 if (RB_TYPE_P(x, T_BIGNUM)) return v2w(rb_big_plus(x, w2v(wy)));
393 return v2w(rb_funcall(x, '+', 1, w2v(wy)));
394 }
395
396 static wideval_t
397 wsub(wideval_t wx, wideval_t wy)
398 {
399 VALUE x;
400 #if WIDEVALUE_IS_WIDER
401 if (FIXWV_P(wx) && FIXWV_P(wy)) {
402 wideint_t r = FIXWV2WINT(wx) - FIXWV2WINT(wy);
403 return WINT2WV(r);
404 }
405 else
406 #endif
407 x = w2v(wx);
408 if (RB_TYPE_P(x, T_BIGNUM)) return v2w(rb_big_minus(x, w2v(wy)));
409 return v2w(rb_funcall(x, '-', 1, w2v(wy)));
410 }
411
412 static int
413 wi_mul(wideint_t x, wideint_t y, wideint_t *z)
414 {
415 uwideint_t a, b, c;
416 int s;
417 if (x == 0 || y == 0) {
418 *z = 0;
419 return 1;
420 }
421 if (x < 0) {
422 s = -1;
423 a = (uwideint_t)-x;
424 }
425 else {
426 s = 1;
427 a = (uwideint_t)x;
428 }
429 if (y < 0) {
430 s = -s;
431 b = (uwideint_t)-y;
432 }
433 else {
434 b = (uwideint_t)y;
435 }
436 if (a <= UWIDEINT_MAX / b) {
437 c = a * b;
438 if (s < 0) {
439 if (c <= (uwideint_t)WIDEINT_MAX + 1) {
440 *z = -(wideint_t)c;
441 return 1;
442 }
443 }
444 else {
445 if (c <= (uwideint_t)WIDEINT_MAX) {
446 *z = (wideint_t)c;
447 return 1;
448 }
449 }
450 }
451 return 0;
452 }
453
454 static wideval_t
455 wmul(wideval_t wx, wideval_t wy)
456 {
457 VALUE x, z;
458 #if WIDEVALUE_IS_WIDER
459 if (FIXWV_P(wx) && FIXWV_P(wy)) {
460 wideint_t z;
461 if (wi_mul(FIXWV2WINT(wx), FIXWV2WINT(wy), &z))
462 return WINT2WV(z);
463 }
464 #endif
465 x = w2v(wx);
466 if (RB_TYPE_P(x, T_BIGNUM)) return v2w(rb_big_mul(x, w2v(wy)));
467 z = rb_funcall(x, '*', 1, w2v(wy));
468 if (RB_TYPE_P(z, T_RATIONAL) && RRATIONAL(z)->den == INT2FIX(1)) {
469 z = RRATIONAL(z)->num;
470 }
471 return v2w(z);
472 }
473
474 static wideval_t
475 wquo(wideval_t wx, wideval_t wy)
476 {
477 VALUE x, y, ret;
478 #if WIDEVALUE_IS_WIDER
479 if (FIXWV_P(wx) && FIXWV_P(wy)) {
480 wideint_t a, b, c;
481 a = FIXWV2WINT(wx);
482 b = FIXWV2WINT(wy);
483 if (b == 0) rb_num_zerodiv();
484 c = a / b;
485 if (c * b == a) {
486 return WINT2WV(c);
487 }
488 }
489 #endif
490 x = w2v(wx);
491 y = w2v(wy);
492 ret = rb_funcall(x, id_quo, 1, y);
493 if (RB_TYPE_P(ret, T_RATIONAL) &&
494 RRATIONAL(ret)->den == INT2FIX(1)) {
495 ret = RRATIONAL(ret)->num;
496 }
497 return v2w(ret);
498 }
499
500 #define wmulquo(x,y,z) ((WIDEVAL_GET(y) == WIDEVAL_GET(z)) ? (x) : wquo(wmul((x),(y)),(z)))
501 #define wmulquoll(x,y,z) (((y) == (z)) ? (x) : wquo(wmul((x),WINT2WV(y)),WINT2WV(z)))
502
503 static void
504 wdivmod(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
505 {
506 VALUE tmp, ary;
507 #if WIDEVALUE_IS_WIDER
508 if (FIXWV_P(wn) && FIXWV_P(wd)) {
509 wideint_t n, d, q, r;
510 d = FIXWV2WINT(wd);
511 if (d == 0) rb_num_zerodiv();
512 if (d == 1) {
513 *wq = wn;
514 *wr = WINT2FIXWV(0);
515 return;
516 }
517 if (d == -1) {
518 wideint_t xneg = -FIXWV2WINT(wn);
519 *wq = WINT2WV(xneg);
520 *wr = WINT2FIXWV(0);
521 return;
522 }
523 n = FIXWV2WINT(wn);
524 if (n == 0) {
525 *wq = WINT2FIXWV(0);
526 *wr = WINT2FIXWV(0);
527 return;
528 }
529 if (d < 0) {
530 if (n < 0) {
531 q = ((-n) / (-d));
532 r = ((-n) % (-d));
533 if (r != 0) {
534 q -= 1;
535 r += d;
536 }
537 }
538 else { /* 0 < n */
539 q = -(n / (-d));
540 r = -(n % (-d));
541 }
542 }
543 else { /* 0 < d */
544 if (n < 0) {
545 q = -((-n) / d);
546 r = -((-n) % d);
547 if (r != 0) {
548 q -= 1;
549 r += d;
550 }
551 }
552 else { /* 0 < n */
553 q = n / d;
554 r = n % d;
555 }
556 }
557 *wq = WINT2FIXWV(q);
558 *wr = WINT2FIXWV(r);
559 return;
560 }
561 #endif
562 tmp = rb_funcall(w2v(wn), id_divmod, 1, w2v(wd));
563 ary = rb_check_array_type(tmp);
564 if (NIL_P(ary)) {
565 rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
566 rb_obj_classname(tmp));
567 }
568 *wq = v2w(rb_ary_entry(ary, 0));
569 *wr = v2w(rb_ary_entry(ary, 1));
570 }
571
572 static void
573 wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr)
574 {
575 if (WIDEVAL_GET(wy) == WIDEVAL_GET(wz)) {
576 *wq = wx;
577 *wr = WINT2FIXWV(0);
578 return;
579 }
580 wdivmod(wmul(wx,wy), wz, wq, wr);
581 }
582
583 static wideval_t
584 wdiv(wideval_t wx, wideval_t wy)
585 {
586 wideval_t q, r;
587 wdivmod(wx, wy, &q, &r);
588 return q;
589 }
590
591 static wideval_t
592 wmod(wideval_t wx, wideval_t wy)
593 {
594 wideval_t q, r;
595 wdivmod(wx, wy, &q, &r);
596 return r;
597 }
598
599 static VALUE
600 num_exact(VALUE v)
601 {
602 VALUE tmp;
603 int t;
604
605 t = TYPE(v);
606 switch (t) {
607 case T_FIXNUM:
608 case T_BIGNUM:
609 return v;
610
611 case T_RATIONAL:
612 break;
613
614 case T_STRING:
615 case T_NIL:
616 goto typeerror;
617
618 default:
619 if ((tmp = rb_check_funcall(v, rb_intern("to_r"), 0, NULL)) != Qundef) {
620 /* test to_int method availability to reject non-Numeric
621 * objects such as String, Time, etc which have to_r method. */
622 if (!rb_respond_to(v, rb_intern("to_int"))) goto typeerror;
623 v = tmp;
624 break;
625 }
626 if (!NIL_P(tmp = rb_check_to_integer(v, "to_int"))) {
627 v = tmp;
628 break;
629 }
630 goto typeerror;
631 }
632
633 t = TYPE(v);
634 switch (t) {
635 case T_FIXNUM:
636 case T_BIGNUM:
637 return v;
638
639 case T_RATIONAL:
640 if (RRATIONAL(v)->den == INT2FIX(1))
641 v = RRATIONAL(v)->num;
642 break;
643
644 default:
645 typeerror:
646 rb_raise(rb_eTypeError, "can't convert %s into an exact number",
647 NIL_P(v) ? "nil" : rb_obj_classname(v));
648 }
649 return v;
650 }
651
652 /* time_t */
653
654 static wideval_t
655 rb_time_magnify(wideval_t w)
656 {
657 if (FIXWV_P(w)) {
658 wideint_t z;
659 if (wi_mul(FIXWV2WINT(w), TIME_SCALE, &z))
660 return WINT2WV(z);
661 }
662 return wmul(w, WINT2FIXWV(TIME_SCALE));
663 }
664
665 static wideval_t
666 rb_time_unmagnify(wideval_t w)
667 {
668 #if WIDEVALUE_IS_WIDER
669 if (FIXWV_P(w)) {
670 wideint_t a, b, c;
671 a = FIXWV2WINT(w);
672 b = TIME_SCALE;
673 c = a / b;
674 if (c * b == a) {
675 return WINT2FIXWV(c);
676 }
677 }
678 #endif
679 return wquo(w, WINT2FIXWV(TIME_SCALE));
680 }
681
682 static VALUE
683 rb_time_unmagnify_to_float(wideval_t w)
684 {
685 VALUE v;
686 #if WIDEVALUE_IS_WIDER
687 if (FIXWV_P(w)) {
688 wideint_t a, b, c;
689 a = FIXWV2WINT(w);
690 b = TIME_SCALE;
691 c = a / b;
692 if (c * b == a) {
693 return DBL2NUM((double)c);
694 }
695 v = DBL2NUM((double)FIXWV2WINT(w));
696 return quo(v, DBL2NUM(TIME_SCALE));
697 }
698 #endif
699 v = w2v(w);
700 return quo(v, DBL2NUM(TIME_SCALE));
701 }
702
703 static void
704 split_second(wideval_t timew, wideval_t *timew_p, VALUE *subsecx_p)
705 {
706 wideval_t q, r;
707 wdivmod(timew, WINT2FIXWV(TIME_SCALE), &q, &r);
708 *timew_p = q;
709 *subsecx_p = w2v(r);
710 }
711
712 static wideval_t
713 timet2wv(time_t t)
714 {
715 #if WIDEVALUE_IS_WIDER
716 if (TIMET_MIN == 0) {
717 uwideint_t wi = (uwideint_t)t;
718 if (wi <= FIXWV_MAX) {
719 return WINT2FIXWV(wi);
720 }
721 }
722 else {
723 wideint_t wi = (wideint_t)t;
724 if (FIXWV_MIN <= wi && wi <= FIXWV_MAX) {
725 return WINT2FIXWV(wi);
726 }
727 }
728 #endif
729 return v2w(TIMET2NUM(t));
730 }
731 #define TIMET2WV(t) timet2wv(t)
732
733 static time_t
734 wv2timet(wideval_t w)
735 {
736 #if WIDEVALUE_IS_WIDER
737 if (FIXWV_P(w)) {
738 wideint_t wi = FIXWV2WINT(w);
739 if (TIMET_MIN == 0) {
740 if (wi < 0)
741 rb_raise(rb_eRangeError, "negative value to convert into `time_t'");
742 if (TIMET_MAX < (uwideint_t)wi)
743 rb_raise(rb_eRangeError, "too big to convert into `time_t'");
744 }
745 else {
746 if (wi < TIMET_MIN || TIMET_MAX < wi)
747 rb_raise(rb_eRangeError, "too big to convert into `time_t'");
748 }
749 return (time_t)wi;
750 }
751 #endif
752 return NUM2TIMET(w2v(w));
753 }
754 #define WV2TIMET(t) wv2timet(t)
755
756 VALUE rb_cTime;
757 static VALUE time_utc_offset _((VALUE));
758
759 static int obj2int(VALUE obj);
760 static VALUE obj2vint(VALUE obj);
761 static int month_arg(VALUE arg);
762 static VALUE validate_utc_offset(VALUE utc_offset);
763 static VALUE validate_zone_name(VALUE zone_name);
764 static void validate_vtm(struct vtm *vtm);
765 static int obj2subsecx(VALUE obj, VALUE *subsecx);
766
767 static VALUE time_gmtime(VALUE);
768 static VALUE time_localtime(VALUE);
769 static VALUE time_fixoff(VALUE);
770
771 static time_t timegm_noleapsecond(struct tm *tm);
772 static int tmcmp(struct tm *a, struct tm *b);
773 static int vtmcmp(struct vtm *a, struct vtm *b);
774 static const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
775
776 static struct vtm *localtimew(wideval_t timew, struct vtm *result);
777
778 static int leap_year_p(long y);
779 #define leap_year_v_p(y) leap_year_p(NUM2LONG(mod((y), INT2FIX(400))))
780
781 #ifdef HAVE_GMTIME_R
782 #define rb_gmtime_r(t, tm) gmtime_r((t), (tm))
783 #define rb_localtime_r(t, tm) localtime_r((t), (tm))
784 #else
785 static inline struct tm *
786 rb_gmtime_r(const time_t *tp, struct tm *result)
787 {
788 struct tm *t = gmtime(tp);
789 if (t) *result = *t;
790 return t;
791 }
792
793 static inline struct tm *
794 rb_localtime_r(const time_t *tp, struct tm *result)
795 {
796 struct tm *t = localtime(tp);
797 if (t) *result = *t;
798 return t;
799 }
800 #endif
801
802 static struct tm *
803 rb_localtime_r2(const time_t *t, struct tm *result)
804 {
805 #if defined __APPLE__ && defined __LP64__
806 if (*t != (time_t)(int)*t) return NULL;
807 #endif
808 result = rb_localtime_r(t, result);
809 #if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
810 if (result) {
811 long gmtoff1 = 0;
812 long gmtoff2 = 0;
813 struct tm tmp = *result;
814 time_t t2;
815 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
816 gmtoff1 = result->tm_gmtoff;
817 # endif
818 t2 = mktime(&tmp);
819 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
820 gmtoff2 = tmp.tm_gmtoff;
821 # endif
822 if (*t + gmtoff1 != t2 + gmtoff2)
823 result = NULL;
824 }
825 #endif
826 return result;
827 }
828 #define LOCALTIME(tm, result) (tzset(),rb_localtime_r2((tm), &(result)))
829
830 #if !defined(HAVE_STRUCT_TM_TM_GMTOFF)
831 static struct tm *
832 rb_gmtime_r2(const time_t *t, struct tm *result)
833 {
834 result = rb_gmtime_r(t, result);
835 #if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
836 if (result) {
837 struct tm tmp = *result;
838 time_t t2 = timegm(&tmp);
839 if (*t != t2)
840 result = NULL;
841 }
842 #endif
843 return result;
844 }
845 # define GMTIME(tm, result) rb_gmtime_r2((tm), &(result))
846 #endif
847
848 static const int common_year_yday_offset[] = {
849 -1,
850 -1 + 31,
851 -1 + 31 + 28,
852 -1 + 31 + 28 + 31,
853 -1 + 31 + 28 + 31 + 30,
854 -1 + 31 + 28 + 31 + 30 + 31,
855 -1 + 31 + 28 + 31 + 30 + 31 + 30,
856 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
857 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
858 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
859 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
860 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
861 /* 1 2 3 4 5 6 7 8 9 10 11 */
862 };
863 static const int leap_year_yday_offset[] = {
864 -1,
865 -1 + 31,
866 -1 + 31 + 29,
867 -1 + 31 + 29 + 31,
868 -1 + 31 + 29 + 31 + 30,
869 -1 + 31 + 29 + 31 + 30 + 31,
870 -1 + 31 + 29 + 31 + 30 + 31 + 30,
871 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
872 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
873 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
874 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
875 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
876 /* 1 2 3 4 5 6 7 8 9 10 11 */
877 };
878
879 static const int common_year_days_in_month[] = {
880 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
881 };
882 static const int leap_year_days_in_month[] = {
883 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
884 };
885
886 static int
887 calc_tm_yday(long tm_year, int tm_mon, int tm_mday)
888 {
889 int tm_year_mod400 = (int)MOD(tm_year, 400);
890 int tm_yday = tm_mday;
891
892 if (leap_year_p(tm_year_mod400 + 1900))
893 tm_yday += leap_year_yday_offset[tm_mon];
894 else
895 tm_yday += common_year_yday_offset[tm_mon];
896
897 return tm_yday;
898 }
899
900 static wideval_t
901 timegmw_noleapsecond(struct vtm *vtm)
902 {
903 VALUE year1900;
904 VALUE q400, r400;
905 int year_mod400;
906 int yday;
907 long days_in400;
908 VALUE vdays, ret;
909 wideval_t wret;
910
911 year1900 = sub(vtm->year, INT2FIX(1900));
912
913 divmodv(year1900, INT2FIX(400), &q400, &r400);
914 year_mod400 = NUM2INT(r400);
915
916 yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday);
917
918 /*
919 * `Seconds Since the Epoch' in SUSv3:
920 * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
921 * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
922 * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
923 */
924 ret = LONG2NUM(vtm->sec
925 + vtm->min*60
926 + vtm->hour*3600);
927 days_in400 = yday
928 - 70*365
929 + DIV(year_mod400 - 69, 4)
930 - DIV(year_mod400 - 1, 100)
931 + (year_mod400 + 299) / 400;
932 vdays = LONG2NUM(days_in400);
933 vdays = add(vdays, mul(q400, INT2FIX(97)));
934 vdays = add(vdays, mul(year1900, INT2FIX(365)));
935 wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)), WINT2FIXWV(86400)));
936 wret = wadd(wret, v2w(vtm->subsecx));
937
938 return wret;
939 }
940
941 static st_table *zone_table;
942
943 static int
944 zone_str_update(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
945 {
946 const char *s = (const char *)*key;
947 const char **ret = (const char **)arg;
948
949 if (existing) {
950 *ret = (const char *)*value;
951 return ST_STOP;
952 }
953 *ret = s = strdup(s);
954 *key = *value = (st_data_t)s;
955 return ST_CONTINUE;
956 }
957
958 static const char *
959 zone_str(const char *s)
960 {
961 if (!zone_table)
962 zone_table = st_init_strtable();
963
964 st_update(zone_table, (st_data_t)s, zone_str_update, (st_data_t)&s);
965 return s;
966 }
967
968 static void
969 gmtimew_noleapsecond(wideval_t timew, struct vtm *vtm)
970 {
971 VALUE v;
972 int i, n, x, y;
973 const int *yday_offset;
974 int wday;
975 VALUE timev;
976 wideval_t timew2, w, w2;
977
978 vtm->isdst = 0;
979
980 split_second(timew, &timew2, &vtm->subsecx);
981
982 wdivmod(timew2, WINT2FIXWV(86400), &w2, &w);
983 timev = w2v(w2);
984 v = w2v(w);
985
986 wday = NUM2INT(mod(timev, INT2FIX(7)));
987 vtm->wday = (wday + 4) % 7;
988
989 n = NUM2INT(v);
990 vtm->sec = n % 60; n = n / 60;
991 vtm->min = n % 60; n = n / 60;
992 vtm->hour = n;
993
994 /* 97 leap days in the 400 year cycle */
995 divmodv(timev, INT2FIX(400*365 + 97), &timev, &v);
996 vtm->year = mul(timev, INT2FIX(400));
997
998 /* n is the days in the 400 year cycle.
999 * the start of the cycle is 1970-01-01. */
1000
1001 n = NUM2INT(v);
1002 y = 1970;
1003
1004 /* 30 years including 7 leap days (1972, 1976, ... 1996),
1005 * 31 days in January 2000 and
1006 * 29 days in February 2000
1007 * from 1970-01-01 to 2000-02-29 */
1008 if (30*365+7+31+29-1 <= n) {
1009 /* 2000-02-29 or after */
1010 if (n < 31*365+8) {
1011 /* 2000-02-29 to 2000-12-31 */
1012 y += 30;
1013 n -= 30*365+7;
1014 goto found;
1015 }
1016 else {
1017 /* 2001-01-01 or after */
1018 n -= 1;
1019 }
1020 }
1021
1022 x = n / (365*100 + 24);
1023 n = n % (365*100 + 24);
1024 y += x * 100;
1025 if (30*365+7+31+29-1 <= n) {
1026 if (n < 31*365+7) {
1027 y += 30;
1028 n -= 30*365+7;
1029 goto found;
1030 }
1031 else
1032 n += 1;
1033 }
1034
1035 x = n / (365*4 + 1);
1036 n = n % (365*4 + 1);
1037 y += x * 4;
1038 if (365*2+31+29-1 <= n) {
1039 if (n < 365*2+366) {
1040 y += 2;
1041 n -= 365*2;
1042 goto found;
1043 }
1044 else
1045 n -= 1;
1046 }
1047
1048 x = n / 365;
1049 n = n % 365;
1050 y += x;
1051
1052 found:
1053 vtm->yday = n+1;
1054 vtm->year = add(vtm->year, INT2NUM(y));
1055
1056 if (leap_year_p(y))
1057 yday_offset = leap_year_yday_offset;
1058 else
1059 yday_offset = common_year_yday_offset;
1060
1061 for (i = 0; i < 12; i++) {
1062 if (yday_offset[i] < n) {
1063 vtm->mon = i+1;
1064 vtm->mday = n - yday_offset[i];
1065 }
1066 else
1067 break;
1068 }
1069
1070 vtm->utc_offset = INT2FIX(0);
1071 vtm->zone = "UTC";
1072 }
1073
1074 static struct tm *
1075 gmtime_with_leapsecond(const time_t *timep, struct tm *result)
1076 {
1077 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1078 /* 4.4BSD counts leap seconds only with localtime, not with gmtime. */
1079 struct tm *t;
1080 int sign;
1081 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
1082 long gmtoff;
1083 t = LOCALTIME(timep, *result);
1084 if (t == NULL)
1085 return NULL;
1086
1087 /* subtract gmtoff */
1088 if (t->tm_gmtoff < 0) {
1089 sign = 1;
1090 gmtoff = -t->tm_gmtoff;
1091 }
1092 else {
1093 sign = -1;
1094 gmtoff = t->tm_gmtoff;
1095 }
1096 gmtoff_sec = (int)(gmtoff % 60);
1097 gmtoff = gmtoff / 60;
1098 gmtoff_min = (int)(gmtoff % 60);
1099 gmtoff = gmtoff / 60;
1100 gmtoff_hour = (int)gmtoff; /* <= 12 */
1101
1102 gmtoff_sec *= sign;
1103 gmtoff_min *= sign;
1104 gmtoff_hour *= sign;
1105
1106 gmtoff_day = 0;
1107
1108 if (gmtoff_sec) {
1109 /* If gmtoff_sec == 0, don't change result->tm_sec.
1110 * It may be 60 which is a leap second. */
1111 result->tm_sec += gmtoff_sec;
1112 if (result->tm_sec < 0) {
1113 result->tm_sec += 60;
1114 gmtoff_min -= 1;
1115 }
1116 if (60 <= result->tm_sec) {
1117 result->tm_sec -= 60;
1118 gmtoff_min += 1;
1119 }
1120 }
1121 if (gmtoff_min) {
1122 result->tm_min += gmtoff_min;
1123 if (result->tm_min < 0) {
1124 result->tm_min += 60;
1125 gmtoff_hour -= 1;
1126 }
1127 if (60 <= result->tm_min) {
1128 result->tm_min -= 60;
1129 gmtoff_hour += 1;
1130 }
1131 }
1132 if (gmtoff_hour) {
1133 result->tm_hour += gmtoff_hour;
1134 if (result->tm_hour < 0) {
1135 result->tm_hour += 24;
1136 gmtoff_day = -1;
1137 }
1138 if (24 <= result->tm_hour) {
1139 result->tm_hour -= 24;
1140 gmtoff_day = 1;
1141 }
1142 }
1143
1144 if (gmtoff_day) {
1145 if (gmtoff_day < 0) {
1146 if (result->tm_yday == 0) {
1147 result->tm_mday = 31;
1148 result->tm_mon = 11; /* December */
1149 result->tm_year--;
1150 result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
1151 }
1152 else if (result->tm_mday == 1) {
1153 const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
1154 leap_year_days_in_month :
1155 common_year_days_in_month;
1156 result->tm_mon--;
1157 result->tm_mday = days_in_month[result->tm_mon];
1158 result->tm_yday--;
1159 }
1160 else {
1161 result->tm_mday--;
1162 result->tm_yday--;
1163 }
1164 result->tm_wday = (result->tm_wday + 6) % 7;
1165 }
1166 else {
1167 int leap = leap_year_p(result->tm_year + 1900);
1168 if (result->tm_yday == (leap ? 365 : 364)) {
1169 result->tm_year++;
1170 result->tm_mon = 0; /* January */
1171 result->tm_mday = 1;
1172 result->tm_yday = 0;
1173 }
1174 else if (result->tm_mday == (leap ? leap_year_days_in_month :
1175 common_year_days_in_month)[result->tm_mon]) {
1176 result->tm_mon++;
1177 result->tm_mday = 1;
1178 result->tm_yday++;
1179 }
1180 else {
1181 result->tm_mday++;
1182 result->tm_yday++;
1183 }
1184 result->tm_wday = (result->tm_wday + 1) % 7;
1185 }
1186 }
1187 result->tm_isdst = 0;
1188 result->tm_gmtoff = 0;
1189 #if defined(HAVE_TM_ZONE)
1190 result->tm_zone = (char *)"UTC";
1191 #endif
1192 return result;
1193 #else
1194 return GMTIME(timep, *result);
1195 #endif
1196 }
1197
1198 static long this_year = 0;
1199 static time_t known_leap_seconds_limit;
1200 static int number_of_leap_seconds_known;
1201
1202 static void
1203 init_leap_second_info(void)
1204 {
1205 /*
1206 * leap seconds are determined by IERS.
1207 * It is announced 6 months before the leap second.
1208 * So no one knows leap seconds in the future after the next year.
1209 */
1210 if (this_year == 0) {
1211 time_t now;
1212 struct tm *tm, result;
1213 struct vtm vtm;
1214 wideval_t timew;
1215 now = time(NULL);
1216 gmtime(&now);
1217 tm = gmtime_with_leapsecond(&now, &result);
1218 if (!tm) return;
1219 this_year = tm->tm_year;
1220
1221 if (TIMET_MAX - now < (time_t)(366*86400))
1222 known_leap_seconds_limit = TIMET_MAX;
1223 else
1224 known_leap_seconds_limit = now + (time_t)(366*86400);
1225
1226 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
1227 return;
1228
1229 vtm.year = LONG2NUM(result.tm_year + 1900);
1230 vtm.mon = result.tm_mon + 1;
1231 vtm.mday = result.tm_mday;
1232 vtm.hour = result.tm_hour;
1233 vtm.min = result.tm_min;
1234 vtm.sec = result.tm_sec;
1235 vtm.subsecx = INT2FIX(0);
1236 vtm.utc_offset = INT2FIX(0);
1237
1238 timew = timegmw_noleapsecond(&vtm);
1239
1240 number_of_leap_seconds_known = NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
1241 }
1242 }
1243
1244 static wideval_t
1245 timegmw(struct vtm *vtm)
1246 {
1247 wideval_t timew;
1248 struct tm tm;
1249 time_t t;
1250 const char *errmsg;
1251
1252 /* The first leap second is 1972-06-30 23:59:60 UTC.
1253 * No leap seconds before. */
1254 if (gt(INT2FIX(1972), vtm->year))
1255 return timegmw_noleapsecond(vtm);
1256
1257 init_leap_second_info();
1258
1259 timew = timegmw_noleapsecond(vtm);
1260
1261 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
1262 return wadd(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
1263 }
1264
1265 tm.tm_year = rb_long2int(NUM2LONG(vtm->year) - 1900);
1266 tm.tm_mon = vtm->mon - 1;
1267 tm.tm_mday = vtm->mday;
1268 tm.tm_hour = vtm->hour;
1269 tm.tm_min = vtm->min;
1270 tm.tm_sec = vtm->sec;
1271 tm.tm_isdst = 0;
1272
1273 errmsg = find_time_t(&tm, 1, &t);
1274 if (errmsg)
1275 rb_raise(rb_eArgError, "%s", errmsg);
1276 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
1277 }
1278
1279 static struct vtm *
1280 gmtimew(wideval_t timew, struct vtm *result)
1281 {
1282 time_t t;
1283 struct tm tm;
1284 VALUE subsecx;
1285 wideval_t timew2;
1286
1287 if (wlt(timew, WINT2FIXWV(0))) {
1288 gmtimew_noleapsecond(timew, result);
1289 return result;
1290 }
1291
1292 init_leap_second_info();
1293
1294 if (wlt(rb_time_magnify(TIMET2WV(known_leap_seconds_limit)), timew)) {
1295 timew = wsub(timew, rb_time_magnify(WINT2WV(number_of_leap_seconds_known)));
1296 gmtimew_noleapsecond(timew, result);
1297 return result;
1298 }
1299
1300 split_second(timew, &timew2, &subsecx);
1301
1302 t = WV2TIMET(timew2);
1303 if (!gmtime_with_leapsecond(&t, &tm))
1304 return NULL;
1305
1306 result->year = LONG2NUM((long)tm.tm_year + 1900);
1307 result->mon = tm.tm_mon + 1;
1308 result->mday = tm.tm_mday;
1309 result->hour = tm.tm_hour;
1310 result->min = tm.tm_min;
1311 result->sec = tm.tm_sec;
1312 result->subsecx = subsecx;
1313 result->utc_offset = INT2FIX(0);
1314 result->wday = tm.tm_wday;
1315 result->yday = tm.tm_yday+1;
1316 result->isdst = tm.tm_isdst;
1317 result->zone = "UTC";
1318
1319 return result;
1320 }
1321
1322 static struct tm *localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone);
1323
1324 /*
1325 * The idea is borrowed from Perl:
1326 * http://use.perl.org/articles/08/02/07/197204.shtml
1327 *
1328 * compat_common_month_table is generated by the following program.
1329 * This table finds the last month which starts at the same day of a week.
1330 * The year 2037 is not used because:
1331 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522949
1332 *
1333 * #!/usr/bin/ruby
1334 *
1335 * require 'date'
1336 *
1337 * h = {}
1338 * 2036.downto(2010) {|y|
1339 * 1.upto(12) {|m|
1340 * next if m == 2 && y % 4 == 0
1341 * d = Date.new(y,m,1)
1342 * h[m] ||= {}
1343 * h[m][d.wday] ||= y
1344 * }
1345 * }
1346 *
1347 * 1.upto(12) {|m|
1348 * print "{"
1349 * 0.upto(6) {|w|
1350 * y = h[m][w]
1351 * print " #{y},"
1352 * }
1353 * puts "},"
1354 * }
1355 *
1356 */
1357 static int compat_common_month_table[12][7] = {
1358 /* Sun Mon Tue Wed Thu Fri Sat */
1359 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 }, /* January */
1360 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 }, /* February */
1361 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* March */
1362 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* April */
1363 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 }, /* May */
1364 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 }, /* June */
1365 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* July */
1366 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 }, /* August */
1367 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* September */
1368 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 }, /* October */
1369 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* November */
1370 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* December */
1371 };
1372
1373 /*
1374 * compat_leap_month_table is generated by following program.
1375 *
1376 * #!/usr/bin/ruby
1377 *
1378 * require 'date'
1379 *
1380 * h = {}
1381 * 2037.downto(2010) {|y|
1382 * 1.upto(12) {|m|
1383 * next unless m == 2 && y % 4 == 0
1384 * d = Date.new(y,m,1)
1385 * h[m] ||= {}
1386 * h[m][d.wday] ||= y
1387 * }
1388 * }
1389 *
1390 * 2.upto(2) {|m|
1391 * 0.upto(6) {|w|
1392 * y = h[m][w]
1393 * print " #{y},"
1394 * }
1395 * puts
1396 * }
1397 */
1398 static int compat_leap_month_table[7] = {
1399 /* Sun Mon Tue Wed Thu Fri Sat */
1400 2032, 2016, 2028, 2012, 2024, 2036, 2020, /* February */
1401 };
1402
1403 static int
1404 calc_wday(int year, int month, int day)
1405 {
1406 int a, y, m;
1407 int wday;
1408
1409 a = (14 - month) / 12;
1410 y = year + 4800 - a;
1411 m = month + 12 * a - 3;
1412 wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
1413 wday = wday % 7;
1414 return wday;
1415 }
1416
1417 static VALUE
1418 guess_local_offset(struct vtm *vtm_utc, int *isdst_ret, const char **zone_ret)
1419 {
1420 struct tm tm;
1421 long gmtoff;
1422 const char *zone;
1423 time_t t;
1424 struct vtm vtm2;
1425 VALUE timev;
1426 int y, wday;
1427
1428 /* Daylight Saving Time was introduced in 1916.
1429 * So we don't need to care about DST before that. */
1430 if (lt(vtm_utc->year, INT2FIX(1916))) {
1431 VALUE off = INT2FIX(0);
1432 int isdst = 0;
1433 zone = "UTC";
1434
1435 # if defined(NEGATIVE_TIME_T)
1436 # if SIZEOF_TIME_T <= 4
1437 /* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t. */
1438 # define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
1439 # else
1440 /* Since the Royal Greenwich Observatory was commissioned in 1675,
1441 no timezone defined using GMT at 1600. */
1442 # define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
1443 # endif
1444 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
1445 off = LONG2FIX(gmtoff);
1446 isdst = tm.tm_isdst;
1447 }
1448 else
1449 # endif
1450 /* 1970-01-01 00:00:00 UTC : The Unix epoch - the oldest time in portable time_t. */
1451 if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
1452 off = LONG2FIX(gmtoff);
1453 isdst = tm.tm_isdst;
1454 }
1455
1456 if (isdst_ret)
1457 *isdst_ret = isdst;
1458 if (zone_ret)
1459 *zone_ret = zone;
1460 return off;
1461 }
1462
1463 /* It is difficult to guess the future. */
1464
1465 vtm2 = *vtm_utc;
1466
1467 /* guess using a year before 2038. */
1468 y = NUM2INT(mod(vtm_utc->year, INT2FIX(400)));
1469 wday = calc_wday(y, vtm_utc->mon, 1);
1470 if (vtm_utc->mon == 2 && leap_year_p(y))
1471 vtm2.year = INT2FIX(compat_leap_month_table[wday]);
1472 else
1473 vtm2.year = INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
1474
1475 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
1476 t = NUM2TIMET(timev);
1477 zone = "UTC";
1478 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1479 if (isdst_ret)
1480 *isdst_ret = tm.tm_isdst;
1481 if (zone_ret)
1482 *zone_ret = zone;
1483 return LONG2FIX(gmtoff);
1484 }
1485
1486 {
1487 /* Use the current time offset as a last resort. */
1488 static time_t now = 0;
1489 static long now_gmtoff = 0;
1490 static const char *now_zone = "UTC";
1491 if (now == 0) {
1492 now = time(NULL);
1493 localtime_with_gmtoff_zone(&now, &tm, &now_gmtoff, &now_zone);
1494 }
1495 if (isdst_ret)
1496 *isdst_ret = tm.tm_isdst;
1497 if (zone_ret)
1498 *zone_ret = now_zone;
1499 return LONG2FIX(now_gmtoff);
1500 }
1501 }
1502
1503 static VALUE
1504 small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
1505 {
1506 int off;
1507
1508 off = vtm1->sec - vtm2->sec;
1509 off += (vtm1->min - vtm2->min) * 60;
1510 off += (vtm1->hour - vtm2->hour) * 3600;
1511 if (ne(vtm1->year, vtm2->year))
1512 off += lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
1513 else if (vtm1->mon != vtm2->mon)
1514 off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
1515 else if (vtm1->mday != vtm2->mday)
1516 off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
1517
1518 return INT2FIX(off);
1519 }
1520
1521 static wideval_t
1522 timelocalw(struct vtm *vtm)
1523 {
1524 time_t t;
1525 struct tm tm;
1526 VALUE v;
1527 wideval_t timew1, timew2;
1528 struct vtm vtm1, vtm2;
1529 int n;
1530
1531 if (FIXNUM_P(vtm->year)) {
1532 long l = FIX2LONG(vtm->year) - 1900;
1533 if (l < INT_MIN || INT_MAX < l)
1534 goto no_localtime;
1535 tm.tm_year = (int)l;
1536 }
1537 else {
1538 v = sub(vtm->year, INT2FIX(1900));
1539 if (lt(v, INT2NUM(INT_MIN)) || lt(INT2NUM(INT_MAX), v))
1540 goto no_localtime;
1541 tm.tm_year = NUM2INT(v);
1542 }
1543
1544 tm.tm_mon = vtm->mon-1;
1545 tm.tm_mday = vtm->mday;
1546 tm.tm_hour = vtm->hour;
1547 tm.tm_min = vtm->min;
1548 tm.tm_sec = vtm->sec;
1549 tm.tm_isdst = vtm->isdst;
1550
1551 if (find_time_t(&tm, 0, &t))
1552 goto no_localtime;
1553 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(vtm->subsecx));
1554
1555 no_localtime:
1556 timew1 = timegmw(vtm);
1557
1558 if (!localtimew(timew1, &vtm1))
1559 rb_raise(rb_eArgError, "localtimew error");
1560
1561 n = vtmcmp(vtm, &vtm1);
1562 if (n == 0) {
1563 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(12*3600)));
1564 if (!localtimew(timew1, &vtm1))
1565 rb_raise(rb_eArgError, "localtimew error");
1566 n = 1;
1567 }
1568
1569 if (n < 0) {
1570 timew2 = timew1;
1571 vtm2 = vtm1;
1572 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1573 if (!localtimew(timew1, &vtm1))
1574 rb_raise(rb_eArgError, "localtimew error");
1575 }
1576 else {
1577 timew2 = wadd(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1578 if (!localtimew(timew2, &vtm2))
1579 rb_raise(rb_eArgError, "localtimew error");
1580 }
1581 timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
1582 timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
1583
1584 if (weq(timew1, timew2))
1585 return timew1;
1586
1587 if (!localtimew(timew1, &vtm1))
1588 rb_raise(rb_eArgError, "localtimew error");
1589 if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
1590 return timew2;
1591
1592 if (!localtimew(timew2, &vtm2))
1593 rb_raise(rb_eArgError, "localtimew error");
1594 if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
1595 return timew1;
1596
1597 if (vtm->isdst)
1598 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
1599 else
1600 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
1601 }
1602
1603 static struct tm *
1604 localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone)
1605 {
1606 struct tm tm;
1607
1608 if (LOCALTIME(t, tm)) {
1609 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1610 *gmtoff = tm.tm_gmtoff;
1611 #else
1612 struct tm *u, *l;
1613 long off;
1614 struct tm tmbuf;
1615 l = &tm;
1616 u = GMTIME(t, tmbuf);
1617 if (!u)
1618 return NULL;
1619 if (l->tm_year != u->tm_year)
1620 off = l->tm_year < u->tm_year ? -1 : 1;
1621 else if (l->tm_mon != u->tm_mon)
1622 off = l->tm_mon < u->tm_mon ? -1 : 1;
1623 else if (l->tm_mday != u->tm_mday)
1624 off = l->tm_mday < u->tm_mday ? -1 : 1;
1625 else
1626 off = 0;
1627 off = off * 24 + l->tm_hour - u->tm_hour;
1628 off = off * 60 + l->tm_min - u->tm_min;
1629 off = off * 60 + l->tm_sec - u->tm_sec;
1630 *gmtoff = off;
1631 #endif
1632
1633 if (zone) {
1634 #if defined(HAVE_TM_ZONE)
1635 if (tm.tm_zone)
1636 *zone = zone_str(tm.tm_zone);
1637 else
1638 *zone = zone_str("(NO-TIMEZONE-ABBREVIATION)");
1639 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1640 /* this needs tzset or localtime, instead of localtime_r */
1641 *zone = zone_str(tzname[daylight && tm.tm_isdst]);
1642 #else
1643 {
1644 char buf[64];
1645 strftime(buf, sizeof(buf), "%Z", &tm);
1646 *zone = zone_str(buf);
1647 }
1648 #endif
1649 }
1650
1651 *result = tm;
1652 return result;
1653 }
1654 return NULL;
1655 }
1656
1657 static int
1658 timew_out_of_timet_range(wideval_t timew)
1659 {
1660 VALUE timexv;
1661 #if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T
1662 if (FIXWV_P(timew)) {
1663 wideint_t t = FIXWV2WINT(timew);
1664 if (t < TIME_SCALE * (wideint_t)TIMET_MIN ||
1665 TIME_SCALE * (1 + (wideint_t)TIMET_MAX) <= t)
1666 return 1;
1667 return 0;
1668 }
1669 #endif
1670 #if SIZEOF_TIME_T == SIZEOF_INT64_T
1671 if (FIXWV_P(timew)) {
1672 wideint_t t = FIXWV2WINT(timew);
1673 if (~(time_t)0 <= 0) {
1674 return 0;
1675 }
1676 else {
1677 if (t < 0)
1678 return 1;
1679 return 0;
1680 }
1681 }
1682 #endif
1683 timexv = w2v(timew);
1684 if (lt(timexv, mul(INT2FIX(TIME_SCALE), TIMET2NUM(TIMET_MIN))) ||
1685 le(mul(INT2FIX(TIME_SCALE), add(TIMET2NUM(TIMET_MAX), INT2FIX(1))), timexv))
1686 return 1;
1687 return 0;
1688 }
1689
1690 static struct vtm *
1691 localtimew(wideval_t timew, struct vtm *result)
1692 {
1693 VALUE subsecx, offset;
1694 const char *zone;
1695 int isdst;
1696
1697 if (!timew_out_of_timet_range(timew)) {
1698 time_t t;
1699 struct tm tm;
1700 long gmtoff;
1701 wideval_t timew2;
1702
1703 split_second(timew, &timew2, &subsecx);
1704
1705 t = WV2TIMET(timew2);
1706
1707 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1708 result->year = LONG2NUM((long)tm.tm_year + 1900);
1709 result->mon = tm.tm_mon + 1;
1710 result->mday = tm.tm_mday;
1711 result->hour = tm.tm_hour;
1712 result->min = tm.tm_min;
1713 result->sec = tm.tm_sec;
1714 result->subsecx = subsecx;
1715 result->wday = tm.tm_wday;
1716 result->yday = tm.tm_yday+1;
1717 result->isdst = tm.tm_isdst;
1718 result->utc_offset = LONG2NUM(gmtoff);
1719 result->zone = zone;
1720 return result;
1721 }
1722 }
1723
1724 if (!gmtimew(timew, result))
1725 return NULL;
1726
1727 offset = guess_local_offset(result, &isdst, &zone);
1728
1729 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
1730 return NULL;
1731
1732 result->utc_offset = offset;
1733 result->isdst = isdst;
1734 result->zone = zone;
1735
1736 return result;
1737 }
1738
1739 struct time_object {
1740 wideval_t timew; /* time_t value * TIME_SCALE. possibly Rational. */
1741 struct vtm vtm;
1742 int gmt; /* 0:utc 1:localtime 2:fixoff */
1743 int tm_got;
1744 };
1745
1746 #define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj))
1747 #define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj))
1748
1749 #define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type)
1750 #define TIME_INIT_P(tobj) ((tobj)->gmt != -1)
1751
1752 #define TIME_UTC_P(tobj) ((tobj)->gmt == 1)
1753 #define TIME_SET_UTC(tobj) ((tobj)->gmt = 1)
1754
1755 #define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0)
1756 #define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0)
1757
1758 #define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2)
1759 #define TIME_SET_FIXOFF(tobj, off) \
1760 ((tobj)->gmt = 2, \
1761 (tobj)->vtm.utc_offset = (off), \
1762 (tobj)->vtm.zone = NULL)
1763
1764 #define TIME_COPY_GMT(tobj1, tobj2) \
1765 ((tobj1)->gmt = (tobj2)->gmt, \
1766 (tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \
1767 (tobj1)->vtm.zone = (tobj2)->vtm.zone)
1768
1769 static VALUE time_get_tm(VALUE, struct time_object *);
1770 #define MAKE_TM(time, tobj) \
1771 do { \
1772 if ((tobj)->tm_got == 0) { \
1773 time_get_tm((time), (tobj)); \
1774 } \
1775 } while (0)
1776
1777 static void
1778 time_mark(void *ptr)
1779 {
1780 struct time_object *tobj = ptr;
1781 if (!tobj) return;
1782 if (!FIXWV_P(tobj->timew))
1783 rb_gc_mark(w2v(tobj->timew));
1784 rb_gc_mark(tobj->vtm.year);
1785 rb_gc_mark(tobj->vtm.subsecx);
1786 rb_gc_mark(tobj->vtm.utc_offset);
1787 }
1788
1789 static void
1790 time_free(void *tobj)
1791 {
1792 if (tobj) xfree(tobj);
1793 }
1794
1795 static size_t
1796 time_memsize(const void *tobj)
1797 {
1798 return tobj ? sizeof(struct time_object) : 0;
1799 }
1800
1801 static const rb_data_type_t time_data_type = {
1802 "time",
1803 {time_mark, time_free, time_memsize,},
1804 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
1805 };
1806
1807 static VALUE
1808 time_s_alloc(VALUE klass)
1809 {
1810 VALUE obj;
1811 struct time_object *tobj;
1812
1813 obj = TypedData_Make_Struct(klass, struct time_object, &time_data_type, tobj);
1814 tobj->gmt = -1;
1815 tobj->tm_got=0;
1816 tobj->timew = WINT2FIXWV(0);
1817
1818 return obj;
1819 }
1820
1821 static struct time_object *
1822 get_timeval(VALUE obj)
1823 {
1824 struct time_object *tobj;
1825 TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
1826 if (!TIME_INIT_P(tobj)) {
1827 rb_raise(rb_eTypeError, "uninitialized %"PRIsVALUE, rb_obj_class(obj));
1828 }
1829 return tobj;
1830 }
1831
1832 static struct time_object *
1833 get_new_timeval(VALUE obj)
1834 {
1835 struct time_object *tobj;
1836 TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
1837 if (TIME_INIT_P(tobj)) {
1838 rb_raise(rb_eTypeError, "already initialized %"PRIsVALUE, rb_obj_class(obj));
1839 }
1840 return tobj;
1841 }
1842
1843 static void
1844 time_modify(VALUE time)
1845 {
1846 rb_check_frozen(time);
1847 rb_check_trusted(time);
1848 }
1849
1850 static wideval_t
1851 timespec2timew(struct timespec *ts)
1852 {
1853 wideval_t timew;
1854
1855 timew = rb_time_magnify(TIMET2WV(ts->tv_sec));
1856 if (ts->tv_nsec)
1857 timew = wadd(timew, wmulquoll(WINT2WV(ts->tv_nsec), TIME_SCALE, 1000000000));
1858 return timew;
1859 }
1860
1861 static struct timespec
1862 timew2timespec(wideval_t timew)
1863 {
1864 VALUE subsecx;
1865 struct timespec ts;
1866 wideval_t timew2;
1867
1868 if (timew_out_of_timet_range(timew))
1869 rb_raise(rb_eArgError, "time out of system range");
1870 split_second(timew, &timew2, &subsecx);
1871 ts.tv_sec = WV2TIMET(timew2);
1872 ts.tv_nsec = NUM2LONG(mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE)));
1873 return ts;
1874 }
1875
1876 static struct timespec *
1877 timew2timespec_exact(wideval_t timew, struct timespec *ts)
1878 {
1879 VALUE subsecx;
1880 wideval_t timew2;
1881 VALUE nsecv;
1882
1883 if (timew_out_of_timet_range(timew))
1884 return NULL;
1885 split_second(timew, &timew2, &subsecx);
1886 ts->tv_sec = WV2TIMET(timew2);
1887 nsecv = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
1888 if (!FIXNUM_P(nsecv))
1889 return NULL;
1890 ts->tv_nsec = NUM2LONG(nsecv);
1891 return ts;
1892 }
1893
1894 /*
1895 * Document-method: now
1896 *
1897 * Alias for Time::new. Returns a Time object
1898 * initialized to the current system time.
1899 */
1900
1901 static VALUE
1902 time_init_0(VALUE time)
1903 {
1904 struct time_object *tobj;
1905 struct timespec ts;
1906
1907 time_modify(time);
1908 GetNewTimeval(time, tobj);
1909 tobj->gmt = 0;
1910 tobj->tm_got=0;
1911 tobj->timew = WINT2FIXWV(0);
1912 #ifdef HAVE_CLOCK_GETTIME
1913 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
1914 rb_sys_fail("clock_gettime");
1915 }
1916 #else
1917 {
1918 struct timeval tv;
1919 if (gettimeofday(&tv, 0) < 0) {
1920 rb_sys_fail("gettimeofday");
1921 }
1922 ts.tv_sec = tv.tv_sec;
1923 ts.tv_nsec = tv.tv_usec * 1000;
1924 }
1925 #endif
1926 tobj->timew = timespec2timew(&ts);
1927
1928 return time;
1929 }
1930
1931 static VALUE
1932 time_set_utc_offset(VALUE time, VALUE off)
1933 {
1934 struct time_object *tobj;
1935 off = num_exact(off);
1936
1937 time_modify(time);
1938 GetTimeval(time, tobj);
1939
1940 tobj->tm_got = 0;
1941 TIME_SET_FIXOFF(tobj, off);
1942
1943 return time;
1944 }
1945
1946 static void
1947 vtm_add_offset(struct vtm *vtm, VALUE off)
1948 {
1949 int sign;
1950 VALUE subsec, v;
1951 int sec, min, hour;
1952 int day;
1953
1954 vtm->utc_offset = sub(vtm->utc_offset, off);
1955
1956 if (lt(off, INT2FIX(0))) {
1957 sign = -1;
1958 off = neg(off);
1959 }
1960 else {
1961 sign = 1;
1962 }
1963 divmodv(off, INT2FIX(1), &off, &subsec);
1964 divmodv(off, INT2FIX(60), &off, &v);
1965 sec = NUM2INT(v);
1966 divmodv(off, INT2FIX(60), &off, &v);
1967 min = NUM2INT(v);
1968 divmodv(off, INT2FIX(24), &off, &v);
1969 hour = NUM2INT(v);
1970
1971 if (sign < 0) {
1972 subsec = neg(subsec);
1973 sec = -sec;
1974 min = -min;
1975 hour = -hour;
1976 }
1977
1978 day = 0;
1979
1980 if (!rb_equal(subsec, INT2FIX(0))) {
1981 vtm->subsecx = add(vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
1982 if (lt(vtm->subsecx, INT2FIX(0))) {
1983 vtm->subsecx = add(vtm->subsecx, INT2FIX(TIME_SCALE));
1984 sec -= 1;
1985 }
1986 if (le(INT2FIX(TIME_SCALE), vtm->subsecx)) {
1987 vtm->subsecx = sub(vtm->subsecx, INT2FIX(TIME_SCALE));
1988 sec += 1;
1989 }
1990 goto not_zero_sec;
1991 }
1992 if (sec) {
1993 not_zero_sec:
1994 /* If sec + subsec == 0, don't change vtm->sec.
1995 * It may be 60 which is a leap second. */
1996 vtm->sec += sec;
1997 if (vtm->sec < 0) {
1998 vtm->sec += 60;
1999 min -= 1;
2000 }
2001 if (60 <= vtm->sec) {
2002 vtm->sec -= 60;
2003 min += 1;
2004 }
2005 }
2006 if (min) {
2007 vtm->min += min;
2008 if (vtm->min < 0) {
2009 vtm->min += 60;
2010 hour -= 1;
2011 }
2012 if (60 <= vtm->min) {
2013 vtm->min -= 60;
2014 hour += 1;
2015 }
2016 }
2017 if (hour) {
2018 vtm->hour += hour;
2019 if (vtm->hour < 0) {
2020 vtm->hour += 24;
2021 day = -1;
2022 }
2023 if (24 <= vtm->hour) {
2024 vtm->hour -= 24;
2025 day = 1;
2026 }
2027 }
2028
2029 if (day) {
2030 if (day < 0) {
2031 if (vtm->mon == 1 && vtm->mday == 1) {
2032 vtm->mday = 31;
2033 vtm->mon = 12; /* December */
2034 vtm->year = sub(vtm->year, INT2FIX(1));
2035 vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
2036 }
2037 else if (vtm->mday == 1) {
2038 const int *days_in_month = leap_year_v_p(vtm->year) ?
2039 leap_year_days_in_month :
2040 common_year_days_in_month;
2041 vtm->mon--;
2042 vtm->mday = days_in_month[vtm->mon-1];
2043 vtm->yday--;
2044 }
2045 else {
2046 vtm->mday--;
2047 vtm->yday--;
2048 }
2049 vtm->wday = (vtm->wday + 6) % 7;
2050 }
2051 else {
2052 int leap = leap_year_v_p(vtm->year);
2053 if (vtm->mon == 12 && vtm->mday == 31) {
2054 vtm->year = add(vtm->year, INT2FIX(1));
2055 vtm->mon = 1; /* January */
2056 vtm->mday = 1;
2057 vtm->yday = 1;
2058 }
2059 else if (vtm->mday == (leap ? leap_year_days_in_month :
2060 common_year_days_in_month)[vtm->mon-1]) {
2061 vtm->mon++;
2062 vtm->mday = 1;
2063 vtm->yday++;
2064 }
2065 else {
2066 vtm->mday++;
2067 vtm->yday++;
2068 }
2069 vtm->wday = (vtm->wday + 1) % 7;
2070 }
2071 }
2072 }
2073
2074 static VALUE
2075 utc_offset_arg(VALUE arg)
2076 {
2077 VALUE tmp;
2078 if (!NIL_P(tmp = rb_check_string_type(arg))) {
2079 int n = 0;
2080 char *s = RSTRING_PTR(tmp);
2081 if (!rb_enc_str_asciicompat_p(tmp)) {
2082 invalid_utc_offset:
2083 rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
2084 }
2085 switch (RSTRING_LEN(tmp)) {
2086 case 9:
2087 if (s[6] != ':') goto invalid_utc_offset;
2088 if (!ISDIGIT(s[7]) || !ISDIGIT(s[8])) goto invalid_utc_offset;
2089 n += (s[7] * 10 + s[8] - '0' * 11);
2090 case 6:
2091 if (s[0] != '+' && s[0] != '-') goto invalid_utc_offset;
2092 if (!ISDIGIT(s[1]) || !ISDIGIT(s[2])) goto invalid_utc_offset;
2093 if (s[3] != ':') goto invalid_utc_offset;
2094 if (!ISDIGIT(s[4]) || !ISDIGIT(s[5])) goto invalid_utc_offset;
2095 break;
2096 default:
2097 goto invalid_utc_offset;
2098 }
2099 n += (s[1] * 10 + s[2] - '0' * 11) * 3600;
2100 n += (s[4] * 10 + s[5] - '0' * 11) * 60;
2101 if (s[0] == '-')
2102 n = -n;
2103 return INT2FIX(n);
2104 }
2105 else {
2106 return num_exact(arg);
2107 }
2108 }
2109
2110 static VALUE
2111 time_init_1(int argc, VALUE *argv, VALUE time)
2112 {
2113 struct vtm vtm;
2114 VALUE v[7];
2115 struct time_object *tobj;
2116
2117 vtm.wday = -1;
2118 vtm.yday = 0;
2119 vtm.zone = "";
2120
2121 /* year mon mday hour min sec off */
2122 rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
2123
2124 vtm.year = obj2vint(v[0]);
2125
2126 vtm.mon = NIL_P(v[1]) ? 1 : month_arg(v[1]);
2127
2128 vtm.mday = NIL_P(v[2]) ? 1 : obj2int(v[2]);
2129
2130 vtm.hour = NIL_P(v[3]) ? 0 : obj2int(v[3]);
2131
2132 vtm.min = NIL_P(v[4]) ? 0 : obj2int(v[4]);
2133
2134 vtm.subsecx = INT2FIX(0);
2135 vtm.sec = NIL_P(v[5]) ? 0 : obj2subsecx(v[5], &vtm.subsecx);
2136
2137 vtm.isdst = -1;
2138 vtm.utc_offset = Qnil;
2139 if (!NIL_P(v[6])) {
2140 VALUE arg = v[6];
2141 if (arg == ID2SYM(rb_intern("dst")))
2142 vtm.isdst = 1;
2143 else if (arg == ID2SYM(rb_intern("std")))
2144 vtm.isdst = 0;
2145 else
2146 vtm.utc_offset = utc_offset_arg(arg);
2147 }
2148
2149 validate_vtm(&vtm);
2150
2151 time_modify(time);
2152 GetNewTimeval(time, tobj);
2153 tobj->gmt = 0;
2154 tobj->tm_got=0;
2155 tobj->timew = WINT2FIXWV(0);
2156
2157 if (!NIL_P(vtm.utc_offset)) {
2158 VALUE off = vtm.utc_offset;
2159 vtm_add_offset(&vtm, neg(off));
2160 vtm.utc_offset = Qnil;
2161 tobj->timew = timegmw(&vtm);
2162 return time_set_utc_offset(time, off);
2163 }
2164 else {
2165 tobj->timew = timelocalw(&vtm);
2166 return time_localtime(time);
2167 }
2168 }
2169
2170
2171 /*
2172 * call-seq:
2173 * Time.new -> time
2174 * Time.new(year, month=nil, day=nil, hour=nil, min=nil, sec=nil, utc_offset=nil) -> time
2175 *
2176 * Returns a Time object.
2177 *
2178 * It is initialized to the current system time if no argument is given.
2179 *
2180 * *Note:* The new object will use the resolution available on your
2181 * system clock, and may include fractional seconds.
2182 *
2183 * If one or more arguments specified, the time is initialized to the specified
2184 * time.
2185 *
2186 * +sec+ may have fraction if it is a rational.
2187 *
2188 * +utc_offset+ is the offset from UTC.
2189 * It can be a string such as "+09:00" or a number of seconds such as 32400.
2190 *
2191 * a = Time.new #=> 2007-11-19 07:50:02 -0600
2192 * b = Time.new #=> 2007-11-19 07:50:02 -0600
2193 * a == b #=> false
2194 * "%.6f" % a.to_f #=> "1195480202.282373"
2195 * "%.6f" % b.to_f #=> "1195480202.283415"
2196 *
2197 * Time.new(2008,6,21, 13,30,0, "+09:00") #=> 2008-06-21 13:30:00 +0900
2198 *
2199 * # A trip for RubyConf 2007
2200 * t1 = Time.new(2007,11,1,15,25,0, "+09:00") # JST (Narita)
2201 * t2 = Time.new(2007,11,1,12, 5,0, "-05:00") # CDT (Minneapolis)
2202 * t3 = Time.new(2007,11,1,13,25,0, "-05:00") # CDT (Minneapolis)
2203 * t4 = Time.new(2007,11,1,16,53,0, "-04:00") # EDT (Charlotte)
2204 * t5 = Time.new(2007,11,5, 9,24,0, "-05:00") # EST (Charlotte)
2205 * t6 = Time.new(2007,11,5,11,21,0, "-05:00") # EST (Detroit)
2206 * t7 = Time.new(2007,11,5,13,45,0, "-05:00") # EST (Detroit)
2207 * t8 = Time.new(2007,11,6,17,10,0, "+09:00") # JST (Narita)
2208 * p((t2-t1)/3600.0) #=> 10.666666666666666
2209 * p((t4-t3)/3600.0) #=> 2.466666666666667
2210 * p((t6-t5)/3600.0) #=> 1.95
2211 * p((t8-t7)/3600.0) #=> 13.416666666666666
2212 *
2213 */
2214
2215 static VALUE
2216 time_init(int argc, VALUE *argv, VALUE time)
2217 {
2218 if (argc == 0)
2219 return time_init_0(time);
2220 else
2221 return time_init_1(argc, argv, time);
2222 }
2223
2224 static void
2225 time_overflow_p(time_t *secp, long *nsecp)
2226 {
2227 time_t sec = *secp;
2228 long nsec = *nsecp;
2229 long sec2;
2230
2231 if (nsec >= 1000000000) { /* nsec positive overflow */
2232 sec2 = nsec / 1000000000;
2233 if (TIMET_MAX - sec2 < sec) {
2234 rb_raise(rb_eRangeError, "out of Time range");
2235 }
2236 nsec -= sec2 * 1000000000;
2237 sec += sec2;
2238 }
2239 else if (nsec < 0) { /* nsec negative overflow */
2240 sec2 = NDIV(nsec,1000000000); /* negative div */
2241 if (sec < TIMET_MIN - sec2) {
2242 rb_raise(rb_eRangeError, "out of Time range");
2243 }
2244 nsec -= sec2 * 1000000000;
2245 sec += sec2;
2246 }
2247 #ifndef NEGATIVE_TIME_T
2248 if (sec < 0)
2249 rb_raise(rb_eArgError, "time must be positive");
2250 #endif
2251 *secp = sec;
2252 *nsecp = nsec;
2253 }
2254
2255 static wideval_t
2256 nsec2timew(time_t sec, long nsec)
2257 {
2258 struct timespec ts;
2259 time_overflow_p(&sec, &nsec);
2260 ts.tv_sec = sec;
2261 ts.tv_nsec = nsec;
2262 return timespec2timew(&ts);
2263 }
2264
2265 static VALUE
2266 time_new_timew(VALUE klass, wideval_t timew)
2267 {
2268 VALUE time = time_s_alloc(klass);
2269 struct time_object *tobj;
2270
2271 tobj = DATA_PTR(time); /* skip type check */
2272 tobj->gmt = 0;
2273 tobj->timew = timew;
2274
2275 return time;
2276 }
2277
2278 VALUE
2279 rb_time_new(time_t sec, long usec)
2280 {
2281 wideval_t timew;
2282
2283 if (usec >= 1000000) {
2284 long sec2 = usec / 1000000;
2285 if (sec > TIMET_MAX - sec2) {
2286 rb_raise(rb_eRangeError, "out of Time range");
2287 }
2288 usec -= sec2 * 1000000;
2289 sec += sec2;
2290 }
2291 else if (usec < 0) {
2292 long sec2 = NDIV(usec,1000000); /* negative div */
2293 if (sec < TIMET_MIN - sec2) {
2294 rb_raise(rb_eRangeError, "out of Time range");
2295 }
2296 usec -= sec2 * 1000000;
2297 sec += sec2;
2298 }
2299
2300 timew = nsec2timew(sec, usec * 1000);
2301 return time_new_timew(rb_cTime, timew);
2302 }
2303
2304 VALUE
2305 rb_time_nano_new(time_t sec, long nsec)
2306 {
2307 return time_new_timew(rb_cTime, nsec2timew(sec, nsec));
2308 }
2309
2310 VALUE
2311 rb_time_num_new(VALUE timev, VALUE off)
2312 {
2313 VALUE time = time_new_timew(rb_cTime, rb_time_magnify(v2w(timev)));
2314
2315 if (!NIL_P(off)) {
2316 off = utc_offset_arg(off);
2317 validate_utc_offset(off);
2318 time_set_utc_offset(time, off);
2319 return time;
2320 }
2321
2322 return time;
2323 }
2324
2325 static struct timespec
2326 time_timespec(VALUE num, int interval)
2327 {
2328 struct timespec t;
2329 const char *tstr = interval ? "time interval" : "time";
2330 VALUE i, f, ary;
2331
2332 #ifndef NEGATIVE_TIME_T
2333 interval = 1;
2334 #endif
2335
2336 switch (TYPE(num)) {
2337 case T_FIXNUM:
2338 t.tv_sec = NUM2TIMET(num);
2339 if (interval && t.tv_sec < 0)
2340 rb_raise(rb_eArgError, "%s must be positive", tstr);
2341 t.tv_nsec = 0;
2342 break;
2343
2344 case T_FLOAT:
2345 if (interval && RFLOAT_VALUE(num) < 0.0)
2346 rb_raise(rb_eArgError, "%s must be positive", tstr);
2347 else {
2348 double f, d;
2349
2350 d = modf(RFLOAT_VALUE(num), &f);
2351 if (d >= 0) {
2352 t.tv_nsec = (int)(d*1e9+0.5);
2353 if (t.tv_nsec >= 1000000000) {
2354 t.tv_nsec -= 1000000000;
2355 f += 1;
2356 }
2357 }
2358 else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) {
2359 t.tv_nsec = 1000000000 - t.tv_nsec;
2360 f -= 1;
2361 }
2362 t.tv_sec = (time_t)f;
2363 if (f != t.tv_sec) {
2364 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(num));
2365 }
2366 }
2367 break;
2368
2369 case T_BIGNUM:
2370 t.tv_sec = NUM2TIMET(num);
2371 if (interval && t.tv_sec < 0)
2372 rb_raise(rb_eArgError, "%s must be positive", tstr);
2373 t.tv_nsec = 0;
2374 break;
2375
2376 default:
2377 i = INT2FIX(1);
2378 ary = rb_check_funcall(num, id_divmod, 1, &i);
2379 if (ary != Qundef && !NIL_P(ary = rb_check_array_type(ary))) {
2380 i = rb_ary_entry(ary, 0);
2381 f = rb_ary_entry(ary, 1);
2382 t.tv_sec = NUM2TIMET(i);
2383 if (interval && t.tv_sec < 0)
2384 rb_raise(rb_eArgError, "%s must be positive", tstr);
2385 f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
2386 t.tv_nsec = NUM2LONG(f);
2387 }
2388 else {
2389 rb_raise(rb_eTypeError, "can't convert %s into %s",
2390 rb_obj_classname(num), tstr);
2391 }
2392 break;
2393 }
2394 return t;
2395 }
2396
2397 static struct timeval
2398 time_timeval(VALUE num, int interval)
2399 {
2400 struct timespec ts;
2401 struct timeval tv;
2402
2403 ts = time_timespec(num, interval);
2404 tv.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
2405 tv.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
2406
2407 return tv;
2408 }
2409
2410 struct timeval
2411 rb_time_interval(VALUE num)
2412 {
2413 return time_timeval(num, TRUE);
2414 }
2415
2416 struct timeval
2417 rb_time_timeval(VALUE time)
2418 {
2419 struct time_object *tobj;
2420 struct timeval t;
2421 struct timespec ts;
2422
2423 if (IsTimeval(time)) {
2424 GetTimeval(time, tobj);
2425 ts = timew2timespec(tobj->timew);
2426 t.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
2427 t.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
2428 return t;
2429 }
2430 return time_timeval(time, FALSE);
2431 }
2432
2433 struct timespec
2434 rb_time_timespec(VALUE time)
2435 {
2436 struct time_object *tobj;
2437 struct timespec t;
2438
2439 if (IsTimeval(time)) {
2440 GetTimeval(time, tobj);
2441 t = timew2timespec(tobj->timew);
2442 return t;
2443 }
2444 return time_timespec(time, FALSE);
2445 }
2446
2447 /*
2448 * call-seq:
2449 * Time.now -> time
2450 *
2451 * Creates a new Time object for the current time.
2452 *
2453 * Time.now #=> 2009-06-24 12:39:54 +0900
2454 */
2455
2456 static VALUE
2457 time_s_now(VALUE klass)
2458 {
2459 return rb_class_new_instance(0, NULL, klass);
2460 }
2461
2462 /*
2463 * call-seq:
2464 * Time.at(time) -> time
2465 * Time.at(seconds_with_frac) -> time
2466 * Time.at(seconds, microseconds_with_frac) -> time
2467 *
2468 * Creates a new Time object with the value given by +time+,
2469 * the given number of +seconds_with_frac+, or
2470 * +seconds+ and +microseconds_with_frac+ since the Epoch.
2471 * +seconds_with_frac+ and +microseconds_with_frac+
2472 * can be an Integer, Float, Rational, or other Numeric.
2473 * non-portable feature allows the offset to be negative on some systems.
2474 *
2475 * If a numeric argument is given, the result is in local time.
2476 *
2477 * Time.at(0) #=> 1969-12-31 18:00:00 -0600
2478 * Time.at(Time.at(0)) #=> 1969-12-31 18:00:00 -0600
2479 * Time.at(946702800) #=> 1999-12-31 23:00:00 -0600
2480 * Time.at(-284061600) #=> 1960-12-31 00:00:00 -0600
2481 * Time.at(946684800.2).usec #=> 200000
2482 * Time.at(946684800, 123456.789).nsec #=> 123456789
2483 */
2484
2485 static VALUE
2486 time_s_at(int argc, VALUE *argv, VALUE klass)
2487 {
2488 VALUE time, t;
2489 wideval_t timew;
2490
2491 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
2492 time = num_exact(time);
2493 t = num_exact(t);
2494 timew = wadd(rb_time_magnify(v2w(time)), wmulquoll(v2w(t), TIME_SCALE, 1000000));
2495 t = time_new_timew(klass, timew);
2496 }
2497 else if (IsTimeval(time)) {
2498 struct time_object *tobj, *tobj2;
2499 GetTimeval(time, tobj);
2500 t = time_new_timew(klass, tobj->timew);
2501 GetTimeval(t, tobj2);
2502 TIME_COPY_GMT(tobj2, tobj);
2503 }
2504 else {
2505 timew = rb_time_magnify(v2w(num_exact(time)));
2506 t = time_new_timew(klass, timew);
2507 }
2508
2509 return t;
2510 }
2511
2512 static const char months[][4] = {
2513 "jan", "feb", "mar", "apr", "may", "jun",
2514 "jul", "aug", "sep", "oct", "nov", "dec",
2515 };
2516
2517 static int
2518 obj2int(VALUE obj)
2519 {
2520 if (RB_TYPE_P(obj, T_STRING)) {
2521 obj = rb_str_to_inum(obj, 10, FALSE);
2522 }
2523
2524 return NUM2INT(obj);
2525 }
2526
2527 static VALUE
2528 obj2vint(VALUE obj)
2529 {
2530 if (RB_TYPE_P(obj, T_STRING)) {
2531 obj = rb_str_to_inum(obj, 10, FALSE);
2532 }
2533 else {
2534 obj = rb_to_int(obj);
2535 }
2536
2537 return obj;
2538 }
2539
2540 static int
2541 obj2subsecx(VALUE obj, VALUE *subsecx)
2542 {
2543 VALUE subsec;
2544
2545 if (RB_TYPE_P(obj, T_STRING)) {
2546 obj = rb_str_to_inum(obj, 10, FALSE);
2547 *subsecx = INT2FIX(0);
2548 return NUM2INT(obj);
2549 }
2550
2551 divmodv(num_exact(obj), INT2FIX(1), &obj, &subsec);
2552 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2553 return NUM2INT(obj);
2554 }
2555
2556 static long
2557 usec2subsecx(VALUE obj)
2558 {
2559 if (RB_TYPE_P(obj, T_STRING)) {
2560 obj = rb_str_to_inum(obj, 10, FALSE);
2561 }
2562
2563 return mulquo(num_exact(obj), INT2FIX(TIME_SCALE), INT2FIX(1000000));
2564 }
2565
2566 static int
2567 month_arg(VALUE arg)
2568 {
2569 int i, mon;
2570
2571 VALUE s = rb_check_string_type(arg);
2572 if (!NIL_P(s)) {
2573 mon = 0;
2574 for (i=0; i<12; i++) {
2575 if (RSTRING_LEN(s) == 3 &&
2576 STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
2577 mon = i+1;
2578 break;
2579 }
2580 }
2581 if (mon == 0) {
2582 char c = RSTRING_PTR(s)[0];
2583
2584 if ('0' <= c && c <= '9') {
2585 mon = obj2int(s);
2586 }
2587 }
2588 }
2589 else {
2590 mon = obj2int(arg);
2591 }
2592 return mon;
2593 }
2594
2595 static VALUE
2596 validate_utc_offset(VALUE utc_offset)
2597 {
2598 if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400)))
2599 rb_raise(rb_eArgError, "utc_offset out of range");
2600 return utc_offset;
2601 }
2602
2603 static VALUE
2604 validate_zone_name(VALUE zone_name)
2605 {
2606 StringValueCStr(zone_name);
2607 return zone_name;
2608 }
2609
2610 static void
2611 validate_vtm(struct vtm *vtm)
2612 {
2613 if ( vtm->mon < 1 || vtm->mon > 12
2614 || vtm->mday < 1 || vtm->mday > 31
2615 || vtm->hour < 0 || vtm->hour > 24
2616 || (vtm->hour == 24 && (vtm->min > 0 || vtm->sec > 0))
2617 || vtm->min < 0 || vtm->min > 59
2618 || vtm->sec < 0 || vtm->sec > 60
2619 || lt(vtm->subsecx, INT2FIX(0)) || ge(vtm->subsecx, INT2FIX(TIME_SCALE))
2620 || (!NIL_P(vtm->utc_offset) && (validate_utc_offset(vtm->utc_offset), 0)))
2621 rb_raise(rb_eArgError, "argument out of range");
2622 }
2623
2624 static void
2625 time_arg(int argc, VALUE *argv, struct vtm *vtm)
2626 {
2627 VALUE v[8];
2628
2629 vtm->year = INT2FIX(0);
2630 vtm->mon = 0;
2631 vtm->mday = 0;
2632 vtm->hour = 0;
2633 vtm->min = 0;
2634 vtm->sec = 0;
2635 vtm->subsecx = INT2FIX(0);
2636 vtm->utc_offset = Qnil;
2637 vtm->wday = 0;
2638 vtm->yday = 0;
2639 vtm->isdst = 0;
2640 vtm->zone = "";
2641
2642 if (argc == 10) {
2643 v[0] = argv[5];
2644 v[1] = argv[4];
2645 v[2] = argv[3];
2646 v[3] = argv[2];
2647 v[4] = argv[1];
2648 v[5] = argv[0];
2649 v[6] = Qnil;
2650 vtm->isdst = RTEST(argv[8]) ? 1 : 0;
2651 }
2652 else {
2653 rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
2654 /* v[6] may be usec or zone (parsedate) */
2655 /* v[7] is wday (parsedate; ignored) */
2656 vtm->wday = -1;
2657 vtm->isdst = -1;
2658 }
2659
2660 vtm->year = obj2vint(v[0]);
2661
2662 if (NIL_P(v[1])) {
2663 vtm->mon = 1;
2664 }
2665 else {
2666 vtm->mon = month_arg(v[1]);
2667 }
2668
2669 if (NIL_P(v[2])) {
2670 vtm->mday = 1;
2671 }
2672 else {
2673 vtm->mday = obj2int(v[2]);
2674 }
2675
2676 vtm->hour = NIL_P(v[3])?0:obj2int(v[3]);
2677
2678 vtm->min = NIL_P(v[4])?0:obj2int(v[4]);
2679
2680 if (!NIL_P(v[6]) && argc == 7) {
2681 vtm->sec = NIL_P(v[5])?0:obj2int(v[5]);
2682 vtm->subsecx = usec2subsecx(v[6]);
2683 }
2684 else {
2685 /* when argc == 8, v[6] is timezone, but ignored */
2686 vtm->sec = NIL_P(v[5])?0:obj2subsecx(v[5], &vtm->subsecx);
2687 }
2688
2689 validate_vtm(vtm);
2690 }
2691
2692 static int
2693 leap_year_p(long y)
2694 {
2695 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
2696 }
2697
2698 static time_t
2699 timegm_noleapsecond(struct tm *tm)
2700 {
2701 long tm_year = tm->tm_year;
2702 int tm_yday = tm->tm_mday;
2703 if (leap_year_p(tm_year + 1900))
2704 tm_yday += leap_year_yday_offset[tm->tm_mon];
2705 else
2706 tm_yday += common_year_yday_offset[tm->tm_mon];
2707
2708 /*
2709 * `Seconds Since the Epoch' in SUSv3:
2710 * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
2711 * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
2712 * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
2713 */
2714 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
2715 (time_t)(tm_yday +
2716 (tm_year-70)*365 +
2717 DIV(tm_year-69,4) -
2718 DIV(tm_year-1,100) +
2719 DIV(tm_year+299,400))*86400;
2720 }
2721
2722 #if 0
2723 #define DEBUG_FIND_TIME_NUMGUESS
2724 #define DEBUG_GUESSRANGE
2725 #endif
2726
2727 #ifdef DEBUG_GUESSRANGE
2728 #define DEBUG_REPORT_GUESSRANGE fprintf(stderr, "find time guess range: %ld - %ld : %"PRI_TIMET_PREFIX"u\n", guess_lo, guess_hi, (unsigned_time_t)(guess_hi-guess_lo))
2729 #else
2730 #define DEBUG_REPORT_GUESSRANGE
2731 #endif
2732
2733 #ifdef DEBUG_FIND_TIME_NUMGUESS
2734 #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
2735 static unsigned long long find_time_numguess;
2736
2737 static VALUE find_time_numguess_getter(void)
2738 {
2739 return ULL2NUM(find_time_numguess);
2740 }
2741 #else
2742 #define DEBUG_FIND_TIME_NUMGUESS_INC
2743 #endif
2744
2745 static const char *
2746 find_time_t(struct tm *tptr, int utc_p, time_t *tp)
2747 {
2748 time_t guess, guess0, guess_lo, guess_hi;
2749 struct tm *tm, tm0, tm_lo, tm_hi;
2750 int d;
2751 int find_dst;
2752 struct tm result;
2753 int status;
2754 int tptr_tm_yday;
2755
2756 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
2757
2758 guess_lo = TIMET_MIN;
2759 guess_hi = TIMET_MAX;
2760
2761 find_dst = 0 < tptr->tm_isdst;
2762
2763 #if defined(HAVE_MKTIME)
2764 tm0 = *tptr;
2765 if (!utc_p && (guess = mktime(&tm0)) != -1) {
2766 tm = GUESS(&guess);
2767 if (tm && tmcmp(tptr, tm) == 0) {
2768 goto found;
2769 }
2770 }
2771 #endif
2772
2773 tm0 = *tptr;
2774 if (tm0.tm_mon < 0) {
2775 tm0.tm_mon = 0;
2776 tm0.tm_mday = 1;
2777 tm0.tm_hour = 0;
2778 tm0.tm_min = 0;
2779 tm0.tm_sec = 0;
2780 }
2781 else if (11 < tm0.tm_mon) {
2782 tm0.tm_mon = 11;
2783 tm0.tm_mday = 31;
2784 tm0.tm_hour = 23;
2785 tm0.tm_min = 59;
2786 tm0.tm_sec = 60;
2787 }
2788 else if (tm0.tm_mday < 1) {
2789 tm0.tm_mday = 1;
2790 tm0.tm_hour = 0;
2791 tm0.tm_min = 0;
2792 tm0.tm_sec = 0;
2793 }
2794 else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
2795 leap_year_days_in_month :
2796 common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
2797 tm0.tm_mday = d;
2798 tm0.tm_hour = 23;
2799 tm0.tm_min = 59;
2800 tm0.tm_sec = 60;
2801 }
2802 else if (tm0.tm_hour < 0) {
2803 tm0.tm_hour = 0;
2804 tm0.tm_min = 0;
2805 tm0.tm_sec = 0;
2806 }
2807 else if (23 < tm0.tm_hour) {
2808 tm0.tm_hour = 23;
2809 tm0.tm_min = 59;
2810 tm0.tm_sec = 60;
2811 }
2812 else if (tm0.tm_min < 0) {
2813 tm0.tm_min = 0;
2814 tm0.tm_sec = 0;
2815 }
2816 else if (59 < tm0.tm_min) {
2817 tm0.tm_min = 59;
2818 tm0.tm_sec = 60;
2819 }
2820 else if (tm0.tm_sec < 0) {
2821 tm0.tm_sec = 0;
2822 }
2823 else if (60 < tm0.tm_sec) {
2824 tm0.tm_sec = 60;
2825 }
2826
2827 DEBUG_REPORT_GUESSRANGE;
2828 guess0 = guess = timegm_noleapsecond(&tm0);
2829 tm = GUESS(&guess);
2830 if (tm) {
2831 d = tmcmp(tptr, tm);
2832 if (d == 0) { goto found; }
2833 if (d < 0) {
2834 guess_hi = guess;
2835 guess -= 24 * 60 * 60;
2836 }
2837 else {
2838 guess_lo = guess;
2839 guess += 24 * 60 * 60;
2840 }
2841 DEBUG_REPORT_GUESSRANGE;
2842 if (guess_lo < guess && guess < guess_hi && (tm = GUESS(&guess)) != NULL) {
2843 d = tmcmp(tptr, tm);
2844 if (d == 0) { goto found; }
2845 if (d < 0)
2846 guess_hi = guess;
2847 else
2848 guess_lo = guess;
2849 DEBUG_REPORT_GUESSRANGE;
2850 }
2851 }
2852
2853 tm = GUESS(&guess_lo);
2854 if (!tm) goto error;
2855 d = tmcmp(tptr, tm);
2856 if (d < 0) goto out_of_range;
2857 if (d == 0) { guess = guess_lo; goto found; }
2858 tm_lo = *tm;
2859
2860 tm = GUESS(&guess_hi);
2861 if (!tm) goto error;
2862 d = tmcmp(tptr, tm);
2863 if (d > 0) goto out_of_range;
2864 if (d == 0) { guess = guess_hi; goto found; }
2865 tm_hi = *tm;
2866
2867 DEBUG_REPORT_GUESSRANGE;
2868
2869 status = 1;
2870
2871 while (guess_lo + 1 < guess_hi) {
2872 if (status == 0) {
2873 binsearch:
2874 guess = guess_lo / 2 + guess_hi / 2;
2875 if (guess <= guess_lo)
2876 guess = guess_lo + 1;
2877 else if (guess >= guess_hi)
2878 guess = guess_hi - 1;
2879 status = 1;
2880 }
2881 else {
2882 if (status == 1) {
2883 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
2884 guess = guess_hi - (guess0_hi - guess0);
2885 if (guess == guess_hi) /* hh:mm:60 tends to cause this condition. */
2886 guess--;
2887 status = 2;
2888 }
2889 else if (status == 2) {
2890 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
2891 guess = guess_lo + (guess0 - guess0_lo);
2892 if (guess == guess_lo)
2893 guess++;
2894 status = 0;
2895 }
2896 if (guess <= guess_lo || guess_hi <= guess) {
2897 /* Precious guess is invalid. try binary search. */
2898 #ifdef DEBUG_GUESSRANGE
2899 if (guess <= guess_lo) fprintf(stderr, "too small guess: %ld <= %ld\n", guess, guess_lo);
2900 if (guess_hi <= guess) fprintf(stderr, "too big guess: %ld <= %ld\n", guess_hi, guess);
2901 #endif
2902 goto binsearch;
2903 }
2904 }
2905
2906 tm = GUESS(&guess);
2907 if (!tm) goto error;
2908
2909 d = tmcmp(tptr, tm);
2910
2911 if (d < 0) {
2912 guess_hi = guess;
2913 tm_hi = *tm;
2914 DEBUG_REPORT_GUESSRANGE;
2915 }
2916 else if (d > 0) {
2917 guess_lo = guess;
2918 tm_lo = *tm;
2919 DEBUG_REPORT_GUESSRANGE;
2920 }
2921 else {
2922 found:
2923 if (!utc_p) {
2924 /* If localtime is nonmonotonic, another result may exist. */
2925 time_t guess2;
2926 if (find_dst) {
2927 guess2 = guess - 2 * 60 * 60;
2928 tm = LOCALTIME(&guess2, result);
2929 if (tm) {
2930 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
2931 tptr->tm_min != tm->tm_min ||
2932 tptr->tm_sec != tm->tm_sec) {
2933 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
2934 (tm->tm_min - tptr->tm_min) * 60 +
2935 (tm->tm_sec - tptr->tm_sec);
2936 if (tptr->tm_mday != tm->tm_mday)
2937 guess2 += 24 * 60 * 60;
2938 if (guess != guess2) {
2939 tm = LOCALTIME(&guess2, result);
2940 if (tm && tmcmp(tptr, tm) == 0) {
2941 if (guess < guess2)
2942 *tp = guess;
2943 else
2944 *tp = guess2;
2945 return NULL;
2946 }
2947 }
2948 }
2949 }
2950 }
2951 else {
2952 guess2 = guess + 2 * 60 * 60;
2953 tm = LOCALTIME(&guess2, result);
2954 if (tm) {
2955 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
2956 tptr->tm_min != tm->tm_min ||
2957 tptr->tm_sec != tm->tm_sec) {
2958 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
2959 (tm->tm_min - tptr->tm_min) * 60 +
2960 (tm->tm_sec - tptr->tm_sec);
2961 if (tptr->tm_mday != tm->tm_mday)
2962 guess2 -= 24 * 60 * 60;
2963 if (guess != guess2) {
2964 tm = LOCALTIME(&guess2, result);
2965 if (tm && tmcmp(tptr, tm) == 0) {
2966 if (guess < guess2)
2967 *tp = guess2;
2968 else
2969 *tp = guess;
2970 return NULL;
2971 }
2972 }
2973 }
2974 }
2975 }
2976 }
2977 *tp = guess;
2978 return NULL;
2979 }
2980 }
2981
2982 /* Given argument has no corresponding time_t. Let's extrapolate. */
2983 /*
2984 * `Seconds Since the Epoch' in SUSv3:
2985 * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
2986 * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
2987 * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
2988 */
2989
2990 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
2991
2992 *tp = guess_lo +
2993 ((tptr->tm_year - tm_lo.tm_year) * 365 +
2994 ((tptr->tm_year-69)/4) -
2995 ((tptr->tm_year-1)/100) +
2996 ((tptr->tm_year+299)/400) -
2997 ((tm_lo.tm_year-69)/4) +
2998 ((tm_lo.tm_year-1)/100) -
2999 ((tm_lo.tm_year+299)/400) +
3000 tptr_tm_yday -
3001 tm_lo.tm_yday) * 86400 +
3002 (tptr->tm_hour - tm_lo.tm_hour) * 3600 +
3003 (tptr->tm_min - tm_lo.tm_min) * 60 +
3004 (tptr->tm_sec - (tm_lo.tm_sec == 60 ? 59 : tm_lo.tm_sec));
3005
3006 return NULL;
3007
3008 out_of_range:
3009 return "time out of range";
3010
3011 error:
3012 return "gmtime/localtime error";
3013 }
3014
3015 static int
3016 vtmcmp(struct vtm *a, struct vtm *b)
3017 {
3018 if (ne(a->year, b->year))
3019 return lt(a->year, b->year) ? -1 : 1;
3020 else if (a->mon != b->mon)
3021 return a->mon < b->mon ? -1 : 1;
3022 else if (a->mday != b->mday)
3023 return a->mday < b->mday ? -1 : 1;
3024 else if (a->hour != b->hour)
3025 return a->hour < b->hour ? -1 : 1;
3026 else if (a->min != b->min)
3027 return a->min < b->min ? -1 : 1;
3028 else if (a->sec != b->sec)
3029 return a->sec < b->sec ? -1 : 1;
3030 else if (ne(a->subsecx, b->subsecx))
3031 return lt(a->subsecx, b->subsecx) ? -1 : 1;
3032 else
3033 return 0;
3034 }
3035
3036 static int
3037 tmcmp(struct tm *a, struct tm *b)
3038 {
3039 if (a->tm_year != b->tm_year)
3040 return a->tm_year < b->tm_year ? -1 : 1;
3041 else if (a->tm_mon != b->tm_mon)
3042 return a->tm_mon < b->tm_mon ? -1 : 1;
3043 else if (a->tm_mday != b->tm_mday)
3044 return a->tm_mday < b->tm_mday ? -1 : 1;
3045 else if (a->tm_hour != b->tm_hour)
3046 return a->tm_hour < b->tm_hour ? -1 : 1;
3047 else if (a->tm_min != b->tm_min)
3048 return a->tm_min < b->tm_min ? -1 : 1;
3049 else if (a->tm_sec != b->tm_sec)
3050 return a->tm_sec < b->tm_sec ? -1 : 1;
3051 else
3052 return 0;
3053 }
3054
3055 static VALUE
3056 time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
3057 {
3058 struct vtm vtm;
3059 VALUE time;
3060
3061 time_arg(argc, argv, &vtm);
3062 if (utc_p)
3063 time = time_new_timew(klass, timegmw(&vtm));
3064 else
3065 time = time_new_timew(klass, timelocalw(&vtm));
3066 if (utc_p) return time_gmtime(time);
3067 return time_localtime(time);
3068 }
3069
3070 /*
3071 * call-seq:
3072 * Time.utc(year) -> time
3073 * Time.utc(year, month) -> time
3074 * Time.utc(year, month, day) -> time
3075 * Time.utc(year, month, day, hour) -> time
3076 * Time.utc(year, month, day, hour, min) -> time
3077 * Time.utc(year, month, day, hour, min, sec_with_frac) -> time
3078 * Time.utc(year, month, day, hour, min, sec, usec_with_frac) -> time
3079 * Time.utc(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3080 * Time.gm(year) -> time
3081 * Time.gm(year, month) -> time
3082 * Time.gm(year, month, day) -> time
3083 * Time.gm(year, month, day, hour) -> time
3084 * Time.gm(year, month, day, hour, min) -> time
3085 * Time.gm(year, month, day, hour, min, sec_with_frac) -> time
3086 * Time.gm(year, month, day, hour, min, sec, usec_with_frac) -> time
3087 * Time.gm(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3088 *
3089 * Creates a Time object based on given values, interpreted as UTC (GMT). The
3090 * year must be specified. Other values default to the minimum value
3091 * for that field (and may be +nil+ or omitted). Months may
3092 * be specified by numbers from 1 to 12, or by the three-letter English
3093 * month names. Hours are specified on a 24-hour clock (0..23). Raises
3094 * an ArgumentError if any values are out of range. Will
3095 * also accept ten arguments in the order output by Time#to_a.
3096 *
3097 * +sec_with_frac+ and +usec_with_frac+ can have a fractional part.
3098 *
3099 * Time.utc(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3100 * Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3101 */
3102 static VALUE
3103 time_s_mkutc(int argc, VALUE *argv, VALUE klass)
3104 {
3105 return time_utc_or_local(argc, argv, TRUE, klass);
3106 }
3107
3108 /*
3109 * call-seq:
3110 * Time.local(year) -> time
3111 * Time.local(year, month) -> time
3112 * Time.local(year, month, day) -> time
3113 * Time.local(year, month, day, hour) -> time
3114 * Time.local(year, month, day, hour, min) -> time
3115 * Time.local(year, month, day, hour, min, sec_with_frac) -> time
3116 * Time.local(year, month, day, hour, min, sec, usec_with_frac) -> time
3117 * Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3118 * Time.mktime(year) -> time
3119 * Time.mktime(year, month) -> time
3120 * Time.mktime(year, month, day) -> time
3121 * Time.mktime(year, month, day, hour) -> time
3122 * Time.mktime(year, month, day, hour, min) -> time
3123 * Time.mktime(year, month, day, hour, min, sec_with_frac) -> time
3124 * Time.mktime(year, month, day, hour, min, sec, usec_with_frac) -> time
3125 * Time.mktime(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3126 *
3127 * Same as Time::gm, but interprets the values in the
3128 * local time zone.
3129 *
3130 * Time.local(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 -0600
3131 */
3132
3133 static VALUE
3134 time_s_mktime(int argc, VALUE *argv, VALUE klass)
3135 {
3136 return time_utc_or_local(argc, argv, FALSE, klass);
3137 }
3138
3139 /*
3140 * call-seq:
3141 * time.to_i -> int
3142 * time.tv_sec -> int
3143 *
3144 * Returns the value of _time_ as an integer number of seconds
3145 * since the Epoch.
3146 *
3147 * t = Time.now
3148 * "%10.5f" % t.to_f #=> "1270968656.89607"
3149 * t.to_i #=> 1270968656
3150 */
3151
3152 static VALUE
3153 time_to_i(VALUE time)
3154 {
3155 struct time_object *tobj;
3156
3157 GetTimeval(time, tobj);
3158 return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE)));
3159 }
3160
3161 /*
3162 * call-seq:
3163 * time.to_f -> float
3164 *
3165 * Returns the value of _time_ as a floating point number of
3166 * seconds since the Epoch.
3167 *
3168 * t = Time.now
3169 * "%10.5f" % t.to_f #=> "1270968744.77658"
3170 * t.to_i #=> 1270968744
3171 *
3172 * Note that IEEE 754 double is not accurate enough to represent
3173 * the number of nanoseconds since the Epoch.
3174 */
3175
3176 static VALUE
3177 time_to_f(VALUE time)
3178 {
3179 struct time_object *tobj;
3180
3181 GetTimeval(time, tobj);
3182 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3183 }
3184
3185 /*
3186 * call-seq:
3187 * time.to_r -> a_rational
3188 *
3189 * Returns the value of _time_ as a rational number of seconds
3190 * since the Epoch.
3191 *
3192 * t = Time.now
3193 * p t.to_r #=> (1270968792716287611/1000000000)
3194 *
3195 * This methods is intended to be used to get an accurate value
3196 * representing the nanoseconds since the Epoch. You can use this method
3197 * to convert _time_ to another Epoch.
3198 */
3199
3200 static VALUE
3201 time_to_r(VALUE time)
3202 {
3203 struct time_object *tobj;
3204 VALUE v;
3205
3206 GetTimeval(time, tobj);
3207 v = w2v(rb_time_unmagnify(tobj->timew));
3208 if (!RB_TYPE_P(v, T_RATIONAL)) {
3209 v = rb_Rational1(v);
3210 }
3211 return v;
3212 }
3213
3214 /*
3215 * call-seq:
3216 * time.usec -> int
3217 * time.tv_usec -> int
3218 *
3219 * Returns the number of microseconds for _time_.
3220 *
3221 * t = Time.now #=> 2007-11-19 08:03:26 -0600
3222 * "%10.6f" % t.to_f #=> "1195481006.775195"
3223 * t.usec #=> 775195
3224 */
3225
3226 static VALUE
3227 time_usec(VALUE time)
3228 {
3229 struct time_object *tobj;
3230 wideval_t w, q, r;
3231
3232 GetTimeval(time, tobj);
3233
3234 w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
3235 wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
3236 return rb_to_int(w2v(q));
3237 }
3238
3239 /*
3240 * call-seq:
3241 * time.nsec -> int
3242 * time.tv_nsec -> int
3243 *
3244 * Returns the number of nanoseconds for _time_.
3245 *
3246 * t = Time.now #=> 2007-11-17 15:18:03 +0900
3247 * "%10.9f" % t.to_f #=> "1195280283.536151409"
3248 * t.nsec #=> 536151406
3249 *
3250 * The lowest digits of #to_f and #nsec are different because
3251 * IEEE 754 double is not accurate enough to represent
3252 * the exact number of nanoseconds since the Epoch.
3253 *
3254 * The more accurate value is returned by #nsec.
3255 */
3256
3257 static VALUE
3258 time_nsec(VALUE time)
3259 {
3260 struct time_object *tobj;
3261
3262 GetTimeval(time, tobj);
3263 return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
3264 }
3265
3266 /*
3267 * call-seq:
3268 * time.subsec -> number
3269 *
3270 * Returns the fraction for _time_.
3271 *
3272 * The return value can be a rational number.
3273 *
3274 * t = Time.now #=> 2009-03-26 22:33:12 +0900
3275 * "%10.9f" % t.to_f #=> "1238074392.940563917"
3276 * t.subsec #=> (94056401/100000000)
3277 *
3278 * The lowest digits of #to_f and #subsec are different because
3279 * IEEE 754 double is not accurate enough to represent
3280 * the rational number.
3281 *
3282 * The more accurate value is returned by #subsec.
3283 */
3284
3285 static VALUE
3286 time_subsec(VALUE time)
3287 {
3288 struct time_object *tobj;
3289
3290 GetTimeval(time, tobj);
3291 return quo(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))), INT2FIX(TIME_SCALE));
3292 }
3293
3294 /*
3295 * call-seq:
3296 * time <=> other_time -> -1, 0, +1 or nil
3297 *
3298 * Comparison---Compares +time+ with +other_time+.
3299 *
3300 * -1, 0, +1 or nil depending on whether +time+ is less than, equal to, or
3301 * greater than +other_time+.
3302 *
3303 * +nil+ is returned if the two values are incomparable.
3304 *
3305 * t = Time.now #=> 2007-11-19 08:12:12 -0600
3306 * t2 = t + 2592000 #=> 2007-12-19 08:12:12 -0600
3307 * t <=> t2 #=> -1
3308 * t2 <=> t #=> 1
3309 *
3310 * t = Time.now #=> 2007-11-19 08:13:38 -0600
3311 * t2 = t + 0.1 #=> 2007-11-19 08:13:38 -0600
3312 * t.nsec #=> 98222999
3313 * t2.nsec #=> 198222999
3314 * t <=> t2 #=> -1
3315 * t2 <=> t #=> 1
3316 * t <=> t #=> 0
3317 */
3318
3319 static VALUE
3320 time_cmp(VALUE time1, VALUE time2)
3321 {
3322 struct time_object *tobj1, *tobj2;
3323 int n;
3324
3325 GetTimeval(time1, tobj1);
3326 if (IsTimeval(time2)) {
3327 GetTimeval(time2, tobj2);
3328 n = wcmp(tobj1->timew, tobj2->timew);
3329 }
3330 else {
3331 return rb_invcmp(time1, time2);
3332 }
3333 if (n == 0) return INT2FIX(0);
3334 if (n > 0) return INT2FIX(1);
3335 return INT2FIX(-1);
3336 }
3337
3338 /*
3339 * call-seq:
3340 * time.eql?(other_time)
3341 *
3342 * Returns +true+ if _time_ and +other_time+ are
3343 * both Time objects with the same seconds and fractional seconds.
3344 */
3345
3346 static VALUE
3347 time_eql(VALUE time1, VALUE time2)
3348 {
3349 struct time_object *tobj1, *tobj2;
3350
3351 GetTimeval(time1, tobj1);
3352 if (IsTimeval(time2)) {
3353 GetTimeval(time2, tobj2);
3354 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3355 }
3356 return Qfalse;
3357 }
3358
3359 /*
3360 * call-seq:
3361 * time.utc? -> true or false
3362 * time.gmt? -> true or false
3363 *
3364 * Returns +true+ if _time_ represents a time in UTC (GMT).
3365 *
3366 * t = Time.now #=> 2007-11-19 08:15:23 -0600
3367 * t.utc? #=> false
3368 * t = Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3369 * t.utc? #=> true
3370 *
3371 * t = Time.now #=> 2007-11-19 08:16:03 -0600
3372 * t.gmt? #=> false
3373 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3374 * t.gmt? #=> true
3375 */
3376
3377 static VALUE
3378 time_utc_p(VALUE time)
3379 {
3380 struct time_object *tobj;
3381
3382 GetTimeval(time, tobj);
3383 if (TIME_UTC_P(tobj)) return Qtrue;
3384 return Qfalse;
3385 }
3386
3387 /*
3388 * call-seq:
3389 * time.hash -> fixnum
3390 *
3391 * Returns a hash code for this Time object.
3392 */
3393
3394 static VALUE
3395 time_hash(VALUE time)
3396 {
3397 struct time_object *tobj;
3398
3399 GetTimeval(time, tobj);
3400 return rb_hash(w2v(tobj->timew));
3401 }
3402
3403 /* :nodoc: */
3404 static VALUE
3405 time_init_copy(VALUE copy, VALUE time)
3406 {
3407 struct time_object *tobj, *tcopy;
3408
3409 if (!OBJ_INIT_COPY(copy, time)) return copy;
3410 GetTimeval(time, tobj);
3411 GetNewTimeval(copy, tcopy);
3412 MEMCPY(tcopy, tobj, struct time_object, 1);
3413
3414 return copy;
3415 }
3416
3417 static VALUE
3418 time_dup(VALUE time)
3419 {
3420 VALUE dup = time_s_alloc(rb_obj_class(time));
3421 time_init_copy(dup, time);
3422 return dup;
3423 }
3424
3425 static VALUE
3426 time_localtime(VALUE time)
3427 {
3428 struct time_object *tobj;
3429 struct vtm vtm;
3430
3431 GetTimeval(time, tobj);
3432 if (TIME_LOCALTIME_P(tobj)) {
3433 if (tobj->tm_got)
3434 return time;
3435 }
3436 else {
3437 time_modify(time);
3438 }
3439
3440 if (!localtimew(tobj->timew, &vtm))
3441 rb_raise(rb_eArgError, "localtime error");
3442 tobj->vtm = vtm;
3443
3444 tobj->tm_got = 1;
3445 TIME_SET_LOCALTIME(tobj);
3446 return time;
3447 }
3448
3449 /*
3450 * call-seq:
3451 * time.localtime -> time
3452 * time.localtime(utc_offset) -> time
3453 *
3454 * Converts _time_ to local time (using the local time zone in
3455 * effect for this process) modifying the receiver.
3456 *
3457 * If +utc_offset+ is given, it is used instead of the local time.
3458 *
3459 * t = Time.utc(2000, "jan", 1, 20, 15, 1) #=> 2000-01-01 20:15:01 UTC
3460 * t.utc? #=> true
3461 *
3462 * t.localtime #=> 2000-01-01 14:15:01 -0600
3463 * t.utc? #=> false
3464 *
3465 * t.localtime("+09:00") #=> 2000-01-02 05:15:01 +0900
3466 * t.utc? #=> false
3467 */
3468
3469 static VALUE
3470 time_localtime_m(int argc, VALUE *argv, VALUE time)
3471 {
3472 VALUE off;
3473 rb_scan_args(argc, argv, "01", &off);
3474
3475 if (!NIL_P(off)) {
3476 off = utc_offset_arg(off);
3477 validate_utc_offset(off);
3478
3479 time_set_utc_offset(time, off);
3480 return time_fixoff(time);
3481 }
3482
3483 return time_localtime(time);
3484 }
3485
3486 /*
3487 * call-seq:
3488 * time.gmtime -> time
3489 * time.utc -> time
3490 *
3491 * Converts _time_ to UTC (GMT), modifying the receiver.
3492 *
3493 * t = Time.now #=> 2007-11-19 08:18:31 -0600
3494 * t.gmt? #=> false
3495 * t.gmtime #=> 2007-11-19 14:18:31 UTC
3496 * t.gmt? #=> true
3497 *
3498 * t = Time.now #=> 2007-11-19 08:18:51 -0600
3499 * t.utc? #=> false
3500 * t.utc #=> 2007-11-19 14:18:51 UTC
3501 * t.utc? #=> true
3502 */
3503
3504 static VALUE
3505 time_gmtime(VALUE time)
3506 {
3507 struct time_object *tobj;
3508 struct vtm vtm;
3509
3510 GetTimeval(time, tobj);
3511 if (TIME_UTC_P(tobj)) {
3512 if (tobj->tm_got)
3513 return time;
3514 }
3515 else {
3516 time_modify(time);
3517 }
3518
3519 if (!gmtimew(tobj->timew, &vtm))
3520 rb_raise(rb_eArgError, "gmtime error");
3521 tobj->vtm = vtm;
3522
3523 tobj->tm_got = 1;
3524 TIME_SET_UTC(tobj);
3525 return time;
3526 }
3527
3528 static VALUE
3529 time_fixoff(VALUE time)
3530 {
3531 struct time_object *tobj;
3532 struct vtm vtm;
3533 VALUE off;
3534
3535 GetTimeval(time, tobj);
3536 if (TIME_FIXOFF_P(tobj)) {
3537 if (tobj->tm_got)
3538 return time;
3539 }
3540 else {
3541 time_modify(time);
3542 }
3543
3544 if (TIME_FIXOFF_P(tobj))
3545 off = tobj->vtm.utc_offset;
3546 else
3547 off = INT2FIX(0);
3548
3549 if (!gmtimew(tobj->timew, &vtm))
3550 rb_raise(rb_eArgError, "gmtime error");
3551
3552 tobj->vtm = vtm;
3553 vtm_add_offset(&tobj->vtm, off);
3554
3555 tobj->tm_got = 1;
3556 TIME_SET_FIXOFF(tobj, off);
3557 return time;
3558 }
3559
3560 /*
3561 * call-seq:
3562 * time.getlocal -> new_time
3563 * time.getlocal(utc_offset) -> new_time
3564 *
3565 * Returns a new Time object representing _time_ in
3566 * local time (using the local time zone in effect for this process).
3567 *
3568 * If +utc_offset+ is given, it is used instead of the local time.
3569 *
3570 * t = Time.utc(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3571 * t.utc? #=> true
3572 *
3573 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
3574 * l.utc? #=> false
3575 * t == l #=> true
3576 *
3577 * j = t.getlocal("+09:00") #=> 2000-01-02 05:15:01 +0900
3578 * j.utc? #=> false
3579 * t == j #=> true
3580 */
3581
3582 static VALUE
3583 time_getlocaltime(int argc, VALUE *argv, VALUE time)
3584 {
3585 VALUE off;
3586 rb_scan_args(argc, argv, "01", &off);
3587
3588 if (!NIL_P(off)) {
3589 off = utc_offset_arg(off);
3590 validate_utc_offset(off);
3591
3592 time = time_dup(time);
3593 time_set_utc_offset(time, off);
3594 return time_fixoff(time);
3595 }
3596
3597 return time_localtime(time_dup(time));
3598 }
3599
3600 /*
3601 * call-seq:
3602 * time.getgm -> new_time
3603 * time.getutc -> new_time
3604 *
3605 * Returns a new Time object representing _time_ in UTC.
3606 *
3607 * t = Time.local(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 -0600
3608 * t.gmt? #=> false
3609 * y = t.getgm #=> 2000-01-02 02:15:01 UTC
3610 * y.gmt? #=> true
3611 * t == y #=> true
3612 */
3613
3614 static VALUE
3615 time_getgmtime(VALUE time)
3616 {
3617 return time_gmtime(time_dup(time));
3618 }
3619
3620 static VALUE
3621 time_get_tm(VALUE time, struct time_object *tobj)
3622 {
3623 if (TIME_UTC_P(tobj)) return time_gmtime(time);
3624 if (TIME_FIXOFF_P(tobj)) return time_fixoff(time);
3625 return time_localtime(time);
3626 }
3627
3628 static VALUE strftimev(const char *fmt, VALUE time, rb_encoding *enc);
3629
3630 /*
3631 * call-seq:
3632 * time.asctime -> string
3633 * time.ctime -> string
3634 *
3635 * Returns a canonical string representation of _time_.
3636 *
3637 * Time.now.asctime #=> "Wed Apr 9 08:56:03 2003"
3638 */
3639
3640 static VALUE
3641 time_asctime(VALUE time)
3642 {
3643 return strftimev("%a %b %e %T %Y", time, rb_usascii_encoding());
3644 }
3645
3646 /*
3647 * call-seq:
3648 * time.inspect -> string
3649 * time.to_s -> string
3650 *
3651 * Returns a string representing _time_. Equivalent to calling
3652 * #strftime with the appropriate format string.
3653 *
3654 * t = Time.now
3655 * t.to_s => "2012-11-10 18:16:12 +0100"
3656 * t.strftime "%Y-%m-%d %H:%M:%S %z" => "2012-11-10 18:16:12 +0100"
3657 *
3658 * t.utc.to_s => "2012-11-10 17:16:12 UTC"
3659 * t.strftime "%Y-%m-%d %H:%M:%S UTC" => "2012-11-10 17:16:12 UTC"
3660 */
3661
3662 static VALUE
3663 time_to_s(VALUE time)
3664 {
3665 struct time_object *tobj;
3666
3667 GetTimeval(time, tobj);
3668 if (TIME_UTC_P(tobj))
3669 return strftimev("%Y-%m-%d %H:%M:%S UTC", time, rb_usascii_encoding());
3670 else
3671 return strftimev("%Y-%m-%d %H:%M:%S %z", time, rb_usascii_encoding());
3672 }
3673
3674 static VALUE
3675 time_add(struct time_object *tobj, VALUE offset, int sign)
3676 {
3677 VALUE result;
3678 offset = num_exact(offset);
3679 if (sign < 0)
3680 result = time_new_timew(rb_cTime, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
3681 else
3682 result = time_new_timew(rb_cTime, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
3683 if (TIME_UTC_P(tobj)) {
3684 GetTimeval(result, tobj);
3685 TIME_SET_UTC(tobj);
3686 }
3687 else if (TIME_FIXOFF_P(tobj)) {
3688 VALUE off = tobj->vtm.utc_offset;
3689 GetTimeval(result, tobj);
3690 TIME_SET_FIXOFF(tobj, off);
3691 }
3692 return result;
3693 }
3694
3695 /*
3696 * call-seq:
3697 * time + numeric -> time
3698 *
3699 * Addition --- Adds some number of seconds (possibly fractional) to
3700 * _time_ and returns that value as a new Time object.
3701 *
3702 * t = Time.now #=> 2007-11-19 08:22:21 -0600
3703 * t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
3704 */
3705
3706 static VALUE
3707 time_plus(VALUE time1, VALUE time2)
3708 {
3709 struct time_object *tobj;
3710 GetTimeval(time1, tobj);
3711
3712 if (IsTimeval(time2)) {
3713 rb_raise(rb_eTypeError, "time + time?");
3714 }
3715 return time_add(tobj, time2, 1);
3716 }
3717
3718 /*
3719 * call-seq:
3720 * time - other_time -> float
3721 * time - numeric -> time
3722 *
3723 * Difference --- Returns a new Time object that represents the difference
3724 * between _time_ and +other_time+, or subtracts the given number
3725 * of seconds in +numeric+ from _time_.
3726 *
3727 * t = Time.now #=> 2007-11-19 08:23:10 -0600
3728 * t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
3729 * t2 - t #=> 2592000.0
3730 * t2 - 2592000 #=> 2007-11-19 08:23:10 -0600
3731 */
3732
3733 static VALUE
3734 time_minus(VALUE time1, VALUE time2)
3735 {
3736 struct time_object *tobj;
3737
3738 GetTimeval(time1, tobj);
3739 if (IsTimeval(time2)) {
3740 struct time_object *tobj2;
3741
3742 GetTimeval(time2, tobj2);
3743 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
3744 }
3745 return time_add(tobj, time2, -1);
3746 }
3747
3748 /*
3749 * call-seq:
3750 * time.succ -> new_time
3751 *
3752 * Returns a new Time object, one second later than _time_.
3753 * Time#succ is obsolete since 1.9.2 for time is not a discrete value.
3754 *
3755 * t = Time.now #=> 2007-11-19 08:23:57 -0600
3756 * t.succ #=> 2007-11-19 08:23:58 -0600
3757 *
3758 * Use instead <code>time + 1</code>
3759 *
3760 * t + 1 #=> 2007-11-19 08:23:58 -0600
3761 */
3762
3763 VALUE
3764 rb_time_succ(VALUE time)
3765 {
3766 struct time_object *tobj;
3767 struct time_object *tobj2;
3768
3769 rb_warn("Time#succ is obsolete; use time + 1");
3770 GetTimeval(time, tobj);
3771 time = time_new_timew(rb_cTime, wadd(tobj->timew, WINT2FIXWV(TIME_SCALE)));
3772 GetTimeval(time, tobj2);
3773 TIME_COPY_GMT(tobj2, tobj);
3774 return time;
3775 }
3776
3777 #define time_succ rb_time_succ
3778
3779 /*
3780 * call-seq:
3781 * time.round([ndigits]) -> new_time
3782 *
3783 * Rounds sub seconds to a given precision in decimal digits (0 digits by default).
3784 * It returns a new Time object.
3785 * +ndigits+ should be zero or positive integer.
3786 *
3787 * require 'time'
3788 *
3789 * t = Time.utc(2010,3,30, 5,43,"25.123456789".to_r)
3790 * p t.iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3791 * p t.round.iso8601(10) #=> "2010-03-30T05:43:25.0000000000Z"
3792 * p t.round(0).iso8601(10) #=> "2010-03-30T05:43:25.0000000000Z"
3793 * p t.round(1).iso8601(10) #=> "2010-03-30T05:43:25.1000000000Z"
3794 * p t.round(2).iso8601(10) #=> "2010-03-30T05:43:25.1200000000Z"
3795 * p t.round(3).iso8601(10) #=> "2010-03-30T05:43:25.1230000000Z"
3796 * p t.round(4).iso8601(10) #=> "2010-03-30T05:43:25.1235000000Z"
3797 * p t.round(5).iso8601(10) #=> "2010-03-30T05:43:25.1234600000Z"
3798 * p t.round(6).iso8601(10) #=> "2010-03-30T05:43:25.1234570000Z"
3799 * p t.round(7).iso8601(10) #=> "2010-03-30T05:43:25.1234568000Z"
3800 * p t.round(8).iso8601(10) #=> "2010-03-30T05:43:25.1234567900Z"
3801 * p t.round(9).iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3802 * p t.round(10).iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3803 *
3804 * t = Time.utc(1999,12,31, 23,59,59)
3805 * p((t + 0.4).round.iso8601(3)) #=> "1999-12-31T23:59:59.000Z"
3806 * p((t + 0.49).round.iso8601(3)) #=> "1999-12-31T23:59:59.000Z"
3807 * p((t + 0.5).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3808 * p((t + 1.4).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3809 * p((t + 1.49).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3810 * p((t + 1.5).round.iso8601(3)) #=> "2000-01-01T00:00:01.000Z"
3811 *
3812 * t = Time.utc(1999,12,31, 23,59,59)
3813 * p (t + 0.123456789).round(4).iso8601(6) #=> "1999-12-31T23:59:59.123500Z"
3814 */
3815
3816 static VALUE
3817 time_round(int argc, VALUE *argv, VALUE time)
3818 {
3819 VALUE ndigits, v, a, b, den;
3820 long nd;
3821 struct time_object *tobj;
3822
3823 rb_scan_args(argc, argv, "01", &ndigits);
3824
3825 if (NIL_P(ndigits))
3826 ndigits = INT2FIX(0);
3827 else
3828 ndigits = rb_to_int(ndigits);
3829
3830 nd = NUM2LONG(ndigits);
3831 if (nd < 0)
3832 rb_raise(rb_eArgError, "negative ndigits given");
3833
3834 GetTimeval(time, tobj);
3835 v = w2v(rb_time_unmagnify(tobj->timew));
3836
3837 a = INT2FIX(1);
3838 b = INT2FIX(10);
3839 while (0 < nd) {
3840 if (nd & 1)
3841 a = mul(a, b);
3842 b = mul(b, b);
3843 nd = nd >> 1;
3844 }
3845 den = quo(INT2FIX(1), a);
3846 v = mod(v, den);
3847 if (lt(v, quo(den, INT2FIX(2))))
3848 return time_add(tobj, v, -1);
3849 else
3850 return time_add(tobj, sub(den, v), 1);
3851 }
3852
3853 /*
3854 * call-seq:
3855 * time.sec -> fixnum
3856 *
3857 * Returns the second of the minute (0..60) for _time_.
3858 *
3859 * *Note:* Seconds range from zero to 60 to allow the system to inject
3860 * leap seconds. See http://en.wikipedia.org/wiki/Leap_second for further
3861 * details.
3862 *
3863 * t = Time.now #=> 2007-11-19 08:25:02 -0600
3864 * t.sec #=> 2
3865 */
3866
3867 static VALUE
3868 time_sec(VALUE time)
3869 {
3870 struct time_object *tobj;
3871
3872 GetTimeval(time, tobj);
3873 MAKE_TM(time, tobj);
3874 return INT2FIX(tobj->vtm.sec);
3875 }
3876
3877 /*
3878 * call-seq:
3879 * time.min -> fixnum
3880 *
3881 * Returns the minute of the hour (0..59) for _time_.
3882 *
3883 * t = Time.now #=> 2007-11-19 08:25:51 -0600
3884 * t.min #=> 25
3885 */
3886
3887 static VALUE
3888 time_min(VALUE time)
3889 {
3890 struct time_object *tobj;
3891
3892 GetTimeval(time, tobj);
3893 MAKE_TM(time, tobj);
3894 return INT2FIX(tobj->vtm.min);
3895 }
3896
3897 /*
3898 * call-seq:
3899 * time.hour -> fixnum
3900 *
3901 * Returns the hour of the day (0..23) for _time_.
3902 *
3903 * t = Time.now #=> 2007-11-19 08:26:20 -0600
3904 * t.hour #=> 8
3905 */
3906
3907 static VALUE
3908 time_hour(VALUE time)
3909 {
3910 struct time_object *tobj;
3911
3912 GetTimeval(time, tobj);
3913 MAKE_TM(time, tobj);
3914 return INT2FIX(tobj->vtm.hour);
3915 }
3916
3917 /*
3918 * call-seq:
3919 * time.day -> fixnum
3920 * time.mday -> fixnum
3921 *
3922 * Returns the day of the month (1..n) for _time_.
3923 *
3924 * t = Time.now #=> 2007-11-19 08:27:03 -0600
3925 * t.day #=> 19
3926 * t.mday #=> 19
3927 */
3928
3929 static VALUE
3930 time_mday(VALUE time)
3931 {
3932 struct time_object *tobj;
3933
3934 GetTimeval(time, tobj);
3935 MAKE_TM(time, tobj);
3936 return INT2FIX(tobj->vtm.mday);
3937 }
3938
3939 /*
3940 * call-seq:
3941 * time.mon -> fixnum
3942 * time.month -> fixnum
3943 *
3944 * Returns the month of the year (1..12) for _time_.
3945 *
3946 * t = Time.now #=> 2007-11-19 08:27:30 -0600
3947 * t.mon #=> 11
3948 * t.month #=> 11
3949 */
3950
3951 static VALUE
3952 time_mon(VALUE time)
3953 {
3954 struct time_object *tobj;
3955
3956 GetTimeval(time, tobj);
3957 MAKE_TM(time, tobj);
3958 return INT2FIX(tobj->vtm.mon);
3959 }
3960
3961 /*
3962 * call-seq:
3963 * time.year -> fixnum
3964 *
3965 * Returns the year for _time_ (including the century).
3966 *
3967 * t = Time.now #=> 2007-11-19 08:27:51 -0600
3968 * t.year #=> 2007
3969 */
3970
3971 static VALUE
3972 time_year(VALUE time)
3973 {
3974 struct time_object *tobj;
3975
3976 GetTimeval(time, tobj);
3977 MAKE_TM(time, tobj);
3978 return tobj->vtm.year;
3979 }
3980
3981 /*
3982 * call-seq:
3983 * time.wday -> fixnum
3984 *
3985 * Returns an integer representing the day of the week, 0..6, with
3986 * Sunday == 0.
3987 *
3988 * t = Time.now #=> 2007-11-20 02:35:35 -0600
3989 * t.wday #=> 2
3990 * t.sunday? #=> false
3991 * t.monday? #=> false
3992 * t.tuesday? #=> true
3993 * t.wednesday? #=> false
3994 * t.thursday? #=> false
3995 * t.friday? #=> false
3996 * t.saturday? #=> false
3997 */
3998
3999 static VALUE
4000 time_wday(VALUE time)
4001 {
4002 struct time_object *tobj;
4003
4004 GetTimeval(time, tobj);
4005 MAKE_TM(time, tobj);
4006 return INT2FIX(tobj->vtm.wday);
4007 }
4008
4009 #define wday_p(n) {\
4010 struct time_object *tobj;\
4011 GetTimeval(time, tobj);\
4012 MAKE_TM(time, tobj);\
4013 return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\
4014 }
4015
4016 /*
4017 * call-seq:
4018 * time.sunday? -> true or false
4019 *
4020 * Returns +true+ if _time_ represents Sunday.
4021 *
4022 * t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
4023 * t.sunday? #=> true
4024 */
4025
4026 static VALUE
4027 time_sunday(VALUE time)
4028 {
4029 wday_p(0);
4030 }
4031
4032 /*
4033 * call-seq:
4034 * time.monday? -> true or false
4035 *
4036 * Returns +true+ if _time_ represents Monday.
4037 *
4038 * t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
4039 * p t.monday? #=> true
4040 */
4041
4042 static VALUE
4043 time_monday(VALUE time)
4044 {
4045 wday_p(1);
4046 }
4047
4048 /*
4049 * call-seq:
4050 * time.tuesday? -> true or false
4051 *
4052 * Returns +true+ if _time_ represents Tuesday.
4053 *
4054 * t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
4055 * p t.tuesday? #=> true
4056 */
4057
4058 static VALUE
4059 time_tuesday(VALUE time)
4060 {
4061 wday_p(2);
4062 }
4063
4064 /*
4065 * call-seq:
4066 * time.wednesday? -> true or false
4067 *
4068 * Returns +true+ if _time_ represents Wednesday.
4069 *
4070 * t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
4071 * p t.wednesday? #=> true
4072 */
4073
4074 static VALUE
4075 time_wednesday(VALUE time)
4076 {
4077 wday_p(3);
4078 }
4079
4080 /*
4081 * call-seq:
4082 * time.thursday? -> true or false
4083 *
4084 * Returns +true+ if _time_ represents Thursday.
4085 *
4086 * t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
4087 * p t.thursday? #=> true
4088 */
4089
4090 static VALUE
4091 time_thursday(VALUE time)
4092 {
4093 wday_p(4);
4094 }
4095
4096 /*
4097 * call-seq:
4098 * time.friday? -> true or false
4099 *
4100 * Returns +true+ if _time_ represents Friday.
4101 *
4102 * t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
4103 * t.friday? #=> true
4104 */
4105
4106 static VALUE
4107 time_friday(VALUE time)
4108 {
4109 wday_p(5);
4110 }
4111
4112 /*
4113 * call-seq:
4114 * time.saturday? -> true or false
4115 *
4116 * Returns +true+ if _time_ represents Saturday.
4117 *
4118 * t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
4119 * t.saturday? #=> true
4120 */
4121
4122 static VALUE
4123 time_saturday(VALUE time)
4124 {
4125 wday_p(6);
4126 }
4127
4128 /*
4129 * call-seq:
4130 * time.yday -> fixnum
4131 *
4132 * Returns an integer representing the day of the year, 1..366.
4133 *
4134 * t = Time.now #=> 2007-11-19 08:32:31 -0600
4135 * t.yday #=> 323
4136 */
4137
4138 static VALUE
4139 time_yday(VALUE time)
4140 {
4141 struct time_object *tobj;
4142
4143 GetTimeval(time, tobj);
4144 MAKE_TM(time, tobj);
4145 return INT2FIX(tobj->vtm.yday);
4146 }
4147
4148 /*
4149 * call-seq:
4150 * time.isdst -> true or false
4151 * time.dst? -> true or false
4152 *
4153 * Returns +true+ if _time_ occurs during Daylight
4154 * Saving Time in its time zone.
4155 *
4156 * # CST6CDT:
4157 * Time.local(2000, 1, 1).zone #=> "CST"
4158 * Time.local(2000, 1, 1).isdst #=> false
4159 * Time.local(2000, 1, 1).dst? #=> false
4160 * Time.local(2000, 7, 1).zone #=> "CDT"
4161 * Time.local(2000, 7, 1).isdst #=> true
4162 * Time.local(2000, 7, 1).dst? #=> true
4163 *
4164 * # Asia/Tokyo:
4165 * Time.local(2000, 1, 1).zone #=> "JST"
4166 * Time.local(2000, 1, 1).isdst #=> false
4167 * Time.local(2000, 1, 1).dst? #=> false
4168 * Time.local(2000, 7, 1).zone #=> "JST"
4169 * Time.local(2000, 7, 1).isdst #=> false
4170 * Time.local(2000, 7, 1).dst? #=> false
4171 */
4172
4173 static VALUE
4174 time_isdst(VALUE time)
4175 {
4176 struct time_object *tobj;
4177
4178 GetTimeval(time, tobj);
4179 MAKE_TM(time, tobj);
4180 return tobj->vtm.isdst ? Qtrue : Qfalse;
4181 }
4182
4183 /*
4184 * call-seq:
4185 * time.zone -> string
4186 *
4187 * Returns the name of the time zone used for _time_. As of Ruby
4188 * 1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
4189 *
4190 * t = Time.gm(2000, "jan", 1, 20, 15, 1)
4191 * t.zone #=> "UTC"
4192 * t = Time.local(2000, "jan", 1, 20, 15, 1)
4193 * t.zone #=> "CST"
4194 */
4195
4196 static VALUE
4197 time_zone(VALUE time)
4198 {
4199 struct time_object *tobj;
4200
4201 GetTimeval(time, tobj);
4202 MAKE_TM(time, tobj);
4203
4204 if (TIME_UTC_P(tobj)) {
4205 return rb_obj_untaint(rb_locale_str_new_cstr("UTC"));
4206 }
4207 if (tobj->vtm.zone == NULL)
4208 return Qnil;
4209 return rb_obj_untaint(rb_locale_str_new_cstr(tobj->vtm.zone));
4210 }
4211
4212 /*
4213 * call-seq:
4214 * time.gmt_offset -> fixnum
4215 * time.gmtoff -> fixnum
4216 * time.utc_offset -> fixnum
4217 *
4218 * Returns the offset in seconds between the timezone of _time_
4219 * and UTC.
4220 *
4221 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
4222 * t.gmt_offset #=> 0
4223 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
4224 * l.gmt_offset #=> -21600
4225 */
4226
4227 static VALUE
4228 time_utc_offset(VALUE time)
4229 {
4230 struct time_object *tobj;
4231
4232 GetTimeval(time, tobj);
4233 MAKE_TM(time, tobj);
4234
4235 if (TIME_UTC_P(tobj)) {
4236 return INT2FIX(0);
4237 }
4238 else {
4239 return tobj->vtm.utc_offset;
4240 }
4241 }
4242
4243 /*
4244 * call-seq:
4245 * time.to_a -> array
4246 *
4247 * Returns a ten-element _array_ of values for _time_:
4248 *
4249 * [sec, min, hour, day, month, year, wday, yday, isdst, zone]
4250 *
4251 * See the individual methods for an explanation of the
4252 * valid ranges of each value. The ten elements can be passed directly
4253 * to Time::utc or Time::local to create a
4254 * new Time object.
4255 *
4256 * t = Time.now #=> 2007-11-19 08:36:01 -0600
4257 * now = t.to_a #=> [1, 36, 8, 19, 11, 2007, 1, 323, false, "CST"]
4258 */
4259
4260 static VALUE
4261 time_to_a(VALUE time)
4262 {
4263 struct time_object *tobj;
4264
4265 GetTimeval(time, tobj);
4266 MAKE_TM(time, tobj);
4267 return rb_ary_new3(10,
4268 INT2FIX(tobj->vtm.sec),
4269 INT2FIX(tobj->vtm.min),
4270 INT2FIX(tobj->vtm.hour),
4271 INT2FIX(tobj->vtm.mday),
4272 INT2FIX(tobj->vtm.mon),
4273 tobj->vtm.year,
4274 INT2FIX(tobj->vtm.wday),
4275 INT2FIX(tobj->vtm.yday),
4276 tobj->vtm.isdst?Qtrue:Qfalse,
4277 time_zone(time));
4278 }
4279
4280 #define SMALLBUF 100
4281 static size_t
4282 rb_strftime_alloc(char **buf, VALUE formatv, const char *format, rb_encoding *enc,
4283 struct vtm *vtm, wideval_t timew, int gmt)
4284 {
4285 size_t size, len, flen;
4286 VALUE timev = Qnil;
4287 struct timespec ts;
4288
4289 if (!timew2timespec_exact(timew, &ts))
4290 timev = w2v(rb_time_unmagnify(timew));
4291
4292 (*buf)[0] = '\0';
4293 flen = strlen(format);
4294 if (flen == 0) {
4295 return 0;
4296 }
4297 errno = 0;
4298 if (timev == Qnil)
4299 len = rb_strftime_timespec(*buf, SMALLBUF, format, enc, vtm, &ts, gmt);
4300 else
4301 len = rb_strftime(*buf, SMALLBUF, format, enc, vtm, timev, gmt);
4302 if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
4303 for (size=1024; ; size*=2) {
4304 *buf = xmalloc(size);
4305 (*buf)[0] = '\0';
4306 if (timev == Qnil)
4307 len = rb_strftime_timespec(*buf, size, format, enc, vtm, &ts, gmt);
4308 else
4309 len = rb_strftime(*buf, size, format, enc, vtm, timev, gmt);
4310 /*
4311 * buflen can be zero EITHER because there's not enough
4312 * room in the string, or because the control command
4313 * goes to the empty string. Make a reasonable guess that
4314 * if the buffer is 1024 times bigger than the length of the
4315 * format string, it's not failing for lack of room.
4316 */
4317 if (len > 0) break;
4318 xfree(*buf);
4319 if (size >= 1024 * flen) {
4320 if (!NIL_P(formatv)) rb_sys_fail_str(formatv);
4321 rb_sys_fail(format);
4322 break;
4323 }
4324 }
4325 return len;
4326 }
4327
4328 static VALUE
4329 strftimev(const char *fmt, VALUE time, rb_encoding *enc)
4330 {
4331 struct time_object *tobj;
4332 char buffer[SMALLBUF], *buf = buffer;
4333 long len;
4334 VALUE str;
4335
4336 GetTimeval(time, tobj);
4337 MAKE_TM(time, tobj);
4338 len = rb_strftime_alloc(&buf, Qnil, fmt, enc, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
4339 str = rb_enc_str_new(buf, len, enc);
4340 if (buf != buffer) xfree(buf);
4341 return str;
4342 }
4343
4344 /*
4345 * call-seq:
4346 * time.strftime( string ) -> string
4347 *
4348 * Formats _time_ according to the directives in the given format string.
4349 *
4350 * The directives begin with a percent (%) character.
4351 * Any text not listed as a directive will be passed through to the
4352 * output string.
4353 *
4354 * The directive consists of a percent (%) character,
4355 * zero or more flags, optional minimum field width,
4356 * optional modifier and a conversion specifier
4357 * as follows:
4358 *
4359 * %<flags><width><modifier><conversion>
4360 *
4361 * Flags:
4362 * - don't pad a numerical output
4363 * _ use spaces for padding
4364 * 0 use zeros for padding
4365 * ^ upcase the result string
4366 * # change case
4367 * : use colons for %z
4368 *
4369 * The minimum field width specifies the minimum width.
4370 *
4371 * The modifiers are "E" and "O".
4372 * They are ignored.
4373 *
4374 * Format directives:
4375 *
4376 * Date (Year, Month, Day):
4377 * %Y - Year with century (can be negative, 4 digits at least)
4378 * -0001, 0000, 1995, 2009, 14292, etc.
4379 * %C - year / 100 (rounded down such as 20 in 2009)
4380 * %y - year % 100 (00..99)
4381 *
4382 * %m - Month of the year, zero-padded (01..12)
4383 * %_m blank-padded ( 1..12)
4384 * %-m no-padded (1..12)
4385 * %B - The full month name (``January'')
4386 * %^B uppercased (``JANUARY'')
4387 * %b - The abbreviated month name (``Jan'')
4388 * %^b uppercased (``JAN'')
4389 * %h - Equivalent to %b
4390 *
4391 * %d - Day of the month, zero-padded (01..31)
4392 * %-d no-padded (1..31)
4393 * %e - Day of the month, blank-padded ( 1..31)
4394 *
4395 * %j - Day of the year (001..366)
4396 *
4397 * Time (Hour, Minute, Second, Subsecond):
4398 * %H - Hour of the day, 24-hour clock, zero-padded (00..23)
4399 * %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
4400 * %I - Hour of the day, 12-hour clock, zero-padded (01..12)
4401 * %l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
4402 * %P - Meridian indicator, lowercase (``am'' or ``pm'')
4403 * %p - Meridian indicator, uppercase (``AM'' or ``PM'')
4404 *
4405 * %M - Minute of the hour (00..59)
4406 *
4407 * %S - Second of the minute (00..60)
4408 *
4409 * %L - Millisecond of the second (000..999)
4410 * The digits under millisecond are truncated to not produce 1000.
4411 * %N - Fractional seconds digits, default is 9 digits (nanosecond)
4412 * %3N millisecond (3 digits)
4413 * %6N microsecond (6 digits)
4414 * %9N nanosecond (9 digits)
4415 * %12N picosecond (12 digits)
4416 * %15N femtosecond (15 digits)
4417 * %18N attosecond (18 digits)
4418 * %21N zeptosecond (21 digits)
4419 * %24N yoctosecond (24 digits)
4420 * The digits under the specified length are truncated to avoid
4421 * carry up.
4422 *
4423 * Time zone:
4424 * %z - Time zone as hour and minute offset from UTC (e.g. +0900)
4425 * %:z - hour and minute offset from UTC with a colon (e.g. +09:00)
4426 * %::z - hour, minute and second offset from UTC (e.g. +09:00:00)
4427 * %Z - Abbreviated time zone name or similar information.
4428 *
4429 * Weekday:
4430 * %A - The full weekday name (``Sunday'')
4431 * %^A uppercased (``SUNDAY'')
4432 * %a - The abbreviated name (``Sun'')
4433 * %^a uppercased (``SUN'')
4434 * %u - Day of the week (Monday is 1, 1..7)
4435 * %w - Day of the week (Sunday is 0, 0..6)
4436 *
4437 * ISO 8601 week-based year and week number:
4438 * The first week of YYYY starts with a Monday and includes YYYY-01-04.
4439 * The days in the year before the first week are in the last week of
4440 * the previous year.
4441 * %G - The week-based year
4442 * %g - The last 2 digits of the week-based year (00..99)
4443 * %V - Week number of the week-based year (01..53)
4444 *
4445 * Week number:
4446 * The first week of YYYY that starts with a Sunday or Monday (according to %U
4447 * or %W). The days in the year before the first week are in week 0.
4448 * %U - Week number of the year. The week starts with Sunday. (00..53)
4449 * %W - Week number of the year. The week starts with Monday. (00..53)
4450 *
4451 * Seconds since the Epoch:
4452 * %s - Number of seconds since 1970-01-01 00:00:00 UTC.
4453 *
4454 * Literal string:
4455 * %n - Newline character (\n)
4456 * %t - Tab character (\t)
4457 * %% - Literal ``%'' character
4458 *
4459 * Combination:
4460 * %c - date and time (%a %b %e %T %Y)
4461 * %D - Date (%m/%d/%y)
4462 * %F - The ISO 8601 date format (%Y-%m-%d)
4463 * %v - VMS date (%e-%^b-%4Y)
4464 * %x - Same as %D
4465 * %X - Same as %T
4466 * %r - 12-hour time (%I:%M:%S %p)
4467 * %R - 24-hour time (%H:%M)
4468 * %T - 24-hour time (%H:%M:%S)
4469 *
4470 * This method is similar to strftime() function defined in ISO C and POSIX.
4471 *
4472 * While all directives are locale independent since Ruby 1.9, %Z is platform
4473 * dependent.
4474 * So, the result may differ even if the same format string is used in other
4475 * systems such as C.
4476 *
4477 * %z is recommended over %Z.
4478 * %Z doesn't identify the timezone.
4479 * For example, "CST" is used at America/Chicago (-06:00),
4480 * America/Havana (-05:00), Asia/Harbin (+08:00), Australia/Darwin (+09:30)
4481 * and Australia/Adelaide (+10:30).
4482 * Also, %Z is highly dependent on the operating system.
4483 * For example, it may generate a non ASCII string on Japanese Windows.
4484 * i.e. the result can be different to "JST".
4485 * So the numeric time zone offset, %z, is recommended.
4486 *
4487 * Examples:
4488 *
4489 * t = Time.new(2007,11,19,8,37,48,"-06:00") #=> 2007-11-19 08:37:48 -0600
4490 * t.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007"
4491 * t.strftime("at %I:%M%p") #=> "at 08:37AM"
4492 *
4493 * Various ISO 8601 formats:
4494 * %Y%m%d => 20071119 Calendar date (basic)
4495 * %F => 2007-11-19 Calendar date (extended)
4496 * %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month
4497 * %Y => 2007 Calendar date, reduced accuracy, specific year
4498 * %C => 20 Calendar date, reduced accuracy, specific century
4499 * %Y%j => 2007323 Ordinal date (basic)
4500 * %Y-%j => 2007-323 Ordinal date (extended)
4501 * %GW%V%u => 2007W471 Week date (basic)
4502 * %G-W%V-%u => 2007-W47-1 Week date (extended)
4503 * %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic)
4504 * %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended)
4505 * %H%M%S => 083748 Local time (basic)
4506 * %T => 08:37:48 Local time (extended)
4507 * %H%M => 0837 Local time, reduced accuracy, specific minute (basic)
4508 * %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended)
4509 * %H => 08 Local time, reduced accuracy, specific hour
4510 * %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic)
4511 * %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended)
4512 * %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic)
4513 * %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended)
4514 * %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic)
4515 * %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended)
4516 * %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic)
4517 * %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended)
4518 * %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic)
4519 * %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended)
4520 * %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic)
4521 * %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended)
4522 * %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic)
4523 * %FT%R => 2007-11-19T08:37 Calendar date and local time (extended)
4524 * %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic)
4525 * %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended)
4526 * %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic)
4527 * %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended)
4528 *
4529 */
4530
4531 static VALUE
4532 time_strftime(VALUE time, VALUE format)
4533 {
4534 struct time_object *tobj;
4535 char buffer[SMALLBUF], *buf = buffer;
4536 const char *fmt;
4537 long len;
4538 rb_encoding *enc;
4539 VALUE str;
4540
4541 GetTimeval(time, tobj);
4542 MAKE_TM(time, tobj);
4543 StringValue(format);
4544 if (!rb_enc_str_asciicompat_p(format)) {
4545 rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
4546 }
4547 format = rb_str_new4(format);
4548 fmt = RSTRING_PTR(format);
4549 len = RSTRING_LEN(format);
4550 enc = rb_enc_get(format);
4551 if (len == 0) {
4552 rb_warning("strftime called with empty format string");
4553 }
4554 else if (memchr(fmt, '\0', len)) {
4555 /* Ruby string may contain \0's. */
4556 const char *p = fmt, *pe = fmt + len;
4557
4558 str = rb_str_new(0, 0);
4559 while (p < pe) {
4560 len = rb_strftime_alloc(&buf, format, p, enc,
4561 &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
4562 rb_str_cat(str, buf, len);
4563 p += strlen(p);
4564 if (buf != buffer) {
4565 xfree(buf);
4566 buf = buffer;
4567 }
4568 for (fmt = p; p < pe && !*p; ++p);
4569 if (p > fmt) rb_str_cat(str, fmt, p - fmt);
4570 }
4571 return str;
4572 }
4573 else {
4574 len = rb_strftime_alloc(&buf, format, RSTRING_PTR(format), enc,
4575 &tobj->vtm, tobj->timew, TIME_UTC_P(tobj));
4576 }
4577 str = rb_enc_str_new(buf, len, enc);
4578 if (buf != buffer) xfree(buf);
4579 return str;
4580 }
4581
4582 /* :nodoc: */
4583 static VALUE
4584 time_mdump(VALUE time)
4585 {
4586 struct time_object *tobj;
4587 unsigned long p, s;
4588 char buf[8];
4589 int i;
4590 VALUE str;
4591
4592 struct vtm vtm;
4593 long year;
4594 long usec, nsec;
4595 VALUE subsecx, nano, subnano, v;
4596
4597 GetTimeval(time, tobj);
4598
4599 gmtimew(tobj->timew, &vtm);
4600
4601 if (FIXNUM_P(vtm.year)) {
4602 year = FIX2LONG(vtm.year);
4603 if (year < 1900 || 1900+0xffff < year)
4604 rb_raise(rb_eArgError, "year too big to marshal: %ld UTC", year);
4605 }
4606 else {
4607 rb_raise(rb_eArgError, "year too big to marshal");
4608 }
4609
4610 subsecx = vtm.subsecx;
4611
4612 nano = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
4613 divmodv(nano, INT2FIX(1), &v, &subnano);
4614 nsec = FIX2LONG(v);
4615 usec = nsec / 1000;
4616 nsec = nsec % 1000;
4617
4618 nano = add(LONG2FIX(nsec), subnano);
4619
4620 p = 0x1UL << 31 | /* 1 */
4621 TIME_UTC_P(tobj) << 30 | /* 1 */
4622 (year-1900) << 14 | /* 16 */
4623 (vtm.mon-1) << 10 | /* 4 */
4624 vtm.mday << 5 | /* 5 */
4625 vtm.hour; /* 5 */
4626 s = vtm.min << 26 | /* 6 */
4627 vtm.sec << 20 | /* 6 */
4628 usec; /* 20 */
4629
4630 for (i=0; i<4; i++) {
4631 buf[i] = (unsigned char)p;
4632 p = RSHIFT(p, 8);
4633 }
4634 for (i=4; i<8; i++) {
4635 buf[i] = (unsigned char)s;
4636 s = RSHIFT(s, 8);
4637 }
4638
4639 str = rb_str_new(buf, 8);
4640 rb_copy_generic_ivar(str, time);
4641 if (!rb_equal(nano, INT2FIX(0))) {
4642 if (RB_TYPE_P(nano, T_RATIONAL)) {
4643 rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
4644 rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
4645 }
4646 else {
4647 rb_ivar_set(str, id_nano_num, nano);
4648 rb_ivar_set(str, id_nano_den, INT2FIX(1));
4649 }
4650 }
4651 if (nsec) { /* submicro is only for Ruby 1.9.1 compatibility */
4652 /*
4653 * submicro is formatted in fixed-point packed BCD (without sign).
4654 * It represent digits under microsecond.
4655 * For nanosecond resolution, 3 digits (2 bytes) are used.
4656 * However it can be longer.
4657 * Extra digits are ignored for loading.
4658 */
4659 char buf[2];
4660 int len = (int)sizeof(buf);
4661 buf[1] = (char)((nsec % 10) << 4);
4662 nsec /= 10;
4663 buf[0] = (char)(nsec % 10);
4664 nsec /= 10;
4665 buf[0] |= (char)((nsec % 10) << 4);
4666 if (buf[1] == 0)
4667 len = 1;
4668 rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
4669 }
4670 if (!TIME_UTC_P(tobj)) {
4671 VALUE off = time_utc_offset(time), div, mod;
4672 divmodv(off, INT2FIX(1), &div, &mod);
4673 if (rb_equal(mod, INT2FIX(0)))
4674 off = rb_Integer(div);
4675 rb_ivar_set(str, id_offset, off);
4676 }
4677 if (tobj->vtm.zone) {
4678 rb_ivar_set(str, id_zone, rb_locale_str_new_cstr(tobj->vtm.zone));
4679 }
4680 return str;
4681 }
4682
4683 /* :nodoc: */
4684 static VALUE
4685 time_dump(int argc, VALUE *argv, VALUE time)
4686 {
4687 VALUE str;
4688
4689 rb_scan_args(argc, argv, "01", 0);
4690 str = time_mdump(time);
4691
4692 return str;
4693 }
4694
4695 /* :nodoc: */
4696 static VALUE
4697 time_mload(VALUE time, VALUE str)
4698 {
4699 struct time_object *tobj;
4700 unsigned long p, s;
4701 time_t sec;
4702 long usec;
4703 unsigned char *buf;
4704 struct vtm vtm;
4705 int i, gmt;
4706 long nsec;
4707 VALUE submicro, nano_num, nano_den, offset, zone;
4708 wideval_t timew;
4709 st_data_t data;
4710
4711 time_modify(time);
4712
4713 #define get_attr(attr, iffound) \
4714 attr = rb_attr_get(str, id_##attr); \
4715 if (!NIL_P(attr)) { \
4716 data = id_##attr; \
4717 iffound; \
4718 st_delete(rb_generic_ivar_table(str), &data, 0); \
4719 }
4720
4721 get_attr(nano_num, {});
4722 get_attr(nano_den, {});
4723 get_attr(submicro, {});
4724 get_attr(offset, (offset = rb_rescue(validate_utc_offset, offset, NULL, Qnil)));
4725 get_attr(zone, (zone = rb_rescue(validate_zone_name, zone, NULL, Qnil)));
4726
4727 #undef get_attr
4728
4729 rb_copy_generic_ivar(time, str);
4730
4731 StringValue(str);
4732 buf = (unsigned char *)RSTRING_PTR(str);
4733 if (RSTRING_LEN(str) != 8) {
4734 rb_raise(rb_eTypeError, "marshaled time format differ");
4735 }
4736
4737 p = s = 0;
4738 for (i=0; i<4; i++) {
4739 p |= buf[i]<<(8*i);
4740 }
4741 for (i=4; i<8; i++) {
4742 s |= buf[i]<<(8*(i-4));
4743 }
4744
4745 if ((p & (1UL<<31)) == 0) {
4746 gmt = 0;
4747 offset = Qnil;
4748 sec = p;
4749 usec = s;
4750 nsec = usec * 1000;
4751 timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
4752 }
4753 else {
4754 p &= ~(1UL<<31);
4755 gmt = (int)((p >> 30) & 0x1);
4756
4757 vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
4758 vtm.mon = ((int)(p >> 10) & 0xf) + 1;
4759 vtm.mday = (int)(p >> 5) & 0x1f;
4760 vtm.hour = (int) p & 0x1f;
4761 vtm.min = (int)(s >> 26) & 0x3f;
4762 vtm.sec = (int)(s >> 20) & 0x3f;
4763 vtm.utc_offset = INT2FIX(0);
4764 vtm.yday = vtm.wday = 0;
4765 vtm.isdst = 0;
4766 vtm.zone = "";
4767
4768 usec = (long)(s & 0xfffff);
4769 nsec = usec * 1000;
4770
4771
4772 vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
4773 if (nano_num != Qnil) {
4774 VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
4775 vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
4776 }
4777 else if (submicro != Qnil) { /* for Ruby 1.9.1 compatibility */
4778 unsigned char *ptr;
4779 long len;
4780 int digit;
4781 ptr = (unsigned char*)StringValuePtr(submicro);
4782 len = RSTRING_LEN(submicro);
4783 nsec = 0;
4784 if (0 < len) {
4785 if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
4786 nsec += digit * 100;
4787 if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
4788 nsec += digit * 10;
4789 }
4790 if (1 < len) {
4791 if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
4792 nsec += digit;
4793 }
4794 vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
4795 end_submicro: ;
4796 }
4797 timew = timegmw(&vtm);
4798 }
4799
4800 GetNewTimeval(time, tobj);
4801 tobj->gmt = 0;
4802 tobj->tm_got = 0;
4803 tobj->timew = timew;
4804 if (gmt) {
4805 TIME_SET_UTC(tobj);
4806 }
4807 else if (!NIL_P(offset)) {
4808 time_set_utc_offset(time, offset);
4809 time_fixoff(time);
4810 }
4811 if (!NIL_P(zone)) {
4812 zone = rb_str_new_frozen(zone);
4813 tobj->vtm.zone = RSTRING_PTR(zone);
4814 rb_ivar_set(time, id_zone, zone);
4815 }
4816
4817 return time;
4818 }
4819
4820 /* :nodoc: */
4821 static VALUE
4822 time_load(VALUE klass, VALUE str)
4823 {
4824 VALUE time = time_s_alloc(klass);
4825
4826 time_mload(time, str);
4827 return time;
4828 }
4829
4830 /*
4831 * Time is an abstraction of dates and times. Time is stored internally as
4832 * the number of seconds with fraction since the _Epoch_, January 1, 1970
4833 * 00:00 UTC. Also see the library module Date. The Time class treats GMT
4834 * (Greenwich Mean Time) and UTC (Coordinated Universal Time) as equivalent.
4835 * GMT is the older way of referring to these baseline times but persists in
4836 * the names of calls on POSIX systems.
4837 *
4838 * All times may have fraction. Be aware of this fact when comparing times
4839 * with each other -- times that are apparently equal when displayed may be
4840 * different when compared.
4841 *
4842 * Since Ruby 1.9.2, Time implementation uses a signed 63 bit integer,
4843 * Bignum or Rational.
4844 * The integer is a number of nanoseconds since the _Epoch_ which can
4845 * represent 1823-11-12 to 2116-02-20.
4846 * When Bignum or Rational is used (before 1823, after 2116, under
4847 * nanosecond), Time works slower as when integer is used.
4848 *
4849 * = Examples
4850 *
4851 * All of these examples were done using the EST timezone which is GMT-5.
4852 *
4853 * == Creating a new Time instance
4854 *
4855 * You can create a new instance of Time with Time::new. This will use the
4856 * current system time. Time::now is an alias for this. You can also
4857 * pass parts of the time to Time::new such as year, month, minute, etc. When
4858 * you want to construct a time this way you must pass at least a year. If you
4859 * pass the year with nothing else time will default to January 1 of that year
4860 * at 00:00:00 with the current system timezone. Here are some examples:
4861 *
4862 * Time.new(2002) #=> 2002-01-01 00:00:00 -0500
4863 * Time.new(2002, 10) #=> 2002-10-01 00:00:00 -0500
4864 * Time.new(2002, 10, 31) #=> 2002-10-31 00:00:00 -0500
4865 * Time.new(2002, 10, 31, 2, 2, 2, "+02:00") #=> 2002-10-31 02:02:02 +0200
4866 *
4867 * You can also use #gm, #local and
4868 * #utc to infer GMT, local and UTC timezones instead of using
4869 * the current system setting.
4870 *
4871 * You can also create a new time using Time::at which takes the number of
4872 * seconds (or fraction of seconds) since the {Unix
4873 * Epoch}[http://en.wikipedia.org/wiki/Unix_time].
4874 *
4875 * Time.at(628232400) #=> 1989-11-28 00:00:00 -0500
4876 *
4877 * == Working with an instance of Time
4878 *
4879 * Once you have an instance of Time there is a multitude of things you can
4880 * do with it. Below are some examples. For all of the following examples, we
4881 * will work on the assumption that you have done the following:
4882 *
4883 * t = Time.new(1993, 02, 24, 12, 0, 0, "+09:00")
4884 *
4885 * Was that a monday?
4886 *
4887 * t.monday? #=> false
4888 *
4889 * What year was that again?
4890 *
4891 * t.year #=> 1993
4892 *
4893 * Was is daylight savings at the time?
4894 *
4895 * t.dst? #=> false
4896 *
4897 * What's the day a year later?
4898 *
4899 * t + (60*60*24*365) #=> 1994-02-24 12:00:00 +0900
4900 *
4901 * How many seconds was that since the Unix Epoch?
4902 *
4903 * t.to_i #=> 730522800
4904 *
4905 * You can also do standard functions like compare two times.
4906 *
4907 * t1 = Time.new(2010)
4908 * t2 = Time.new(2011)
4909 *
4910 * t1 == t2 #=> false
4911 * t1 == t1 #=> true
4912 * t1 < t2 #=> true
4913 * t1 > t2 #=> false
4914 *
4915 * Time.new(2010,10,31).between?(t1, t2) #=> true
4916 */
4917
4918 void
4919 Init_Time(void)
4920 {
4921 #undef rb_intern
4922 #define rb_intern(str) rb_intern_const(str)
4923
4924 id_eq = rb_intern("==");
4925 id_ne = rb_intern("!=");
4926 id_quo = rb_intern("quo");
4927 id_div = rb_intern("div");
4928 id_cmp = rb_intern("<=>");
4929 id_lshift = rb_intern("<<");
4930 id_divmod = rb_intern("divmod");
4931 id_mul = rb_intern("*");
4932 id_submicro = rb_intern("submicro");
4933 id_nano_num = rb_intern("nano_num");
4934 id_nano_den = rb_intern("nano_den");
4935 id_offset = rb_intern("offset");
4936 id_zone = rb_intern("zone");
4937
4938 rb_cTime = rb_define_class("Time", rb_cObject);
4939 rb_include_module(rb_cTime, rb_mComparable);
4940
4941 rb_define_alloc_func(rb_cTime, time_s_alloc);
4942 rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
4943 rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
4944 rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
4945 rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
4946 rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
4947 rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
4948
4949 rb_define_method(rb_cTime, "to_i", time_to_i, 0);
4950 rb_define_method(rb_cTime, "to_f", time_to_f, 0);
4951 rb_define_method(rb_cTime, "to_r", time_to_r, 0);
4952 rb_define_method(rb_cTime, "<=>", time_cmp, 1);
4953 rb_define_method(rb_cTime, "eql?", time_eql, 1);
4954 rb_define_method(rb_cTime, "hash", time_hash, 0);
4955 rb_define_method(rb_cTime, "initialize", time_init, -1);
4956 rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1);
4957
4958 rb_define_method(rb_cTime, "localtime", time_localtime_m, -1);
4959 rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
4960 rb_define_method(rb_cTime, "utc", time_gmtime, 0);
4961 rb_define_method(rb_cTime, "getlocal", time_getlocaltime, -1);
4962 rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
4963 rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
4964
4965 rb_define_method(rb_cTime, "ctime", time_asctime, 0);
4966 rb_define_method(rb_cTime, "asctime", time_asctime, 0);
4967 rb_define_method(rb_cTime, "to_s", time_to_s, 0);
4968 rb_define_method(rb_cTime, "inspect", time_to_s, 0);
4969 rb_define_method(rb_cTime, "to_a", time_to_a, 0);
4970
4971 rb_define_method(rb_cTime, "+", time_plus, 1);
4972 rb_define_method(rb_cTime, "-", time_minus, 1);
4973
4974 rb_define_method(rb_cTime, "succ", time_succ, 0);
4975 rb_define_method(rb_cTime, "round", time_round, -1);
4976
4977 rb_define_method(rb_cTime, "sec", time_sec, 0);
4978 rb_define_method(rb_cTime, "min", time_min, 0);
4979 rb_define_method(rb_cTime, "hour", time_hour, 0);
4980 rb_define_method(rb_cTime, "mday", time_mday, 0);
4981 rb_define_method(rb_cTime, "day", time_mday, 0);
4982 rb_define_method(rb_cTime, "mon", time_mon, 0);
4983 rb_define_method(rb_cTime, "month", time_mon, 0);
4984 rb_define_method(rb_cTime, "year", time_year, 0);
4985 rb_define_method(rb_cTime, "wday", time_wday, 0);
4986 rb_define_method(rb_cTime, "yday", time_yday, 0);
4987 rb_define_method(rb_cTime, "isdst", time_isdst, 0);
4988 rb_define_method(rb_cTime, "dst?", time_isdst, 0);
4989 rb_define_method(rb_cTime, "zone", time_zone, 0);
4990 rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
4991 rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
4992 rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
4993
4994 rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
4995 rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
4996
4997 rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
4998 rb_define_method(rb_cTime, "monday?", time_monday, 0);
4999 rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
5000 rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
5001 rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
5002 rb_define_method(rb_cTime, "friday?", time_friday, 0);
5003 rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
5004
5005 rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
5006 rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
5007 rb_define_method(rb_cTime, "usec", time_usec, 0);
5008 rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
5009 rb_define_method(rb_cTime, "nsec", time_nsec, 0);
5010 rb_define_method(rb_cTime, "subsec", time_subsec, 0);
5011
5012 rb_define_method(rb_cTime, "strftime", time_strftime, 1);
5013
5014 /* methods for marshaling */
5015 rb_define_private_method(rb_cTime, "_dump", time_dump, -1);
5016 rb_define_private_method(rb_singleton_class(rb_cTime), "_load", time_load, 1);
5017 #if 0
5018 /* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
5019 rb_define_private_method(rb_cTime, "marshal_dump", time_mdump, 0);
5020 rb_define_private_method(rb_cTime, "marshal_load", time_mload, 1);
5021 #endif
5022
5023 #ifdef DEBUG_FIND_TIME_NUMGUESS
5024 rb_define_virtual_variable("$find_time_numguess", find_time_numguess_getter, NULL);
5025 #endif
5026 }
time_data_type
static const rb_data_type_t time_data_type
Definition: time.c:1801
rb_big_modulo
VALUE rb_big_modulo(VALUE x, VALUE y)
Definition: bignum.c:6189
rb_hash
VALUE rb_hash(VALUE obj)
Definition: hash.c:106
ISDIGIT
#define ISDIGIT(c)
Definition: ruby.h:1775
quo
static VALUE quo(VALUE x, VALUE y)
Definition: time.c:175
cmp
static int cmp(VALUE x, VALUE y)
Definition: time.c:54
WINT2FIXWV
#define WINT2FIXWV(i)
Definition: time.c:250
vtmcmp
static int vtmcmp(struct vtm *a, struct vtm *b)
Definition: time.c:3016
timegm_noleapsecond
static time_t timegm_noleapsecond(struct tm *tm)
Definition: time.c:2699
vtm::yday
int yday
Definition: timev.h:14
w2v
static VALUE w2v(wideval_t w)
Definition: time.c:287
WV2TIMET
#define WV2TIMET(t)
Definition: time.c:754
this_year
static long this_year
Definition: time.c:1198
rb_integer_pack
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Definition: bignum.c:3531
time_mon
static VALUE time_mon(VALUE time)
Definition: time.c:3952
time_to_r
static VALUE time_to_r(VALUE time)
Definition: time.c:3201
rb_str_new4
#define rb_str_new4
Definition: intern.h:842
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1171
gettimeofday
int gettimeofday(struct timeval *, struct timezone *)
Definition: win32.c:4307
FALSE
#define FALSE
Definition: nkf.h:174
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
obj2int
static int obj2int(VALUE obj)
Definition: time.c:2518
time_sunday
static VALUE time_sunday(VALUE time)
Definition: time.c:4027
time_getlocaltime
static VALUE time_getlocaltime(int argc, VALUE *argv, VALUE time)
Definition: time.c:3583
strlen
size_t strlen(const char *)
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1288
timew2timespec_exact
static struct timespec * timew2timespec_exact(wideval_t timew, struct timespec *ts)
Definition: time.c:1877
T_FIXNUM
#define T_FIXNUM
Definition: ruby.h:489
st_table
Definition: st.h:69
ST_STOP
Definition: st.h:100
rb_define_virtual_variable
void rb_define_virtual_variable(const char *, VALUE(*)(ANYARGS), void(*)(ANYARGS))
Definition: variable.c:616
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:630
time_s_now
static VALUE time_s_now(VALUE klass)
Definition: time.c:2457
time_object::tm_got
int tm_got
Definition: time.c:1743
id_eq
static ID id_eq
Definition: time.c:37
time_utc_or_local
static VALUE time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
Definition: time.c:3056
tmcmp
static int tmcmp(struct tm *a, struct tm *b)
Definition: time.c:3037
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
time_utc_p
static VALUE time_utc_p(VALUE time)
Definition: time.c:3378
wideint_t
long wideint_t
Definition: time.c:239
get_new_timeval
static struct time_object * get_new_timeval(VALUE obj)
Definition: time.c:1833
GUESS
#define GUESS(p)
ruby.h
vtm::zone
const char * zone
Definition: timev.h:16
GetTimeval
#define GetTimeval(obj, tobj)
Definition: time.c:1746
timelocalw
static wideval_t timelocalw(struct vtm *vtm)
Definition: time.c:1522
rb_str_cat
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2140
split_second
static void split_second(wideval_t timew, wideval_t *timew_p, VALUE *subsecx_p)
Definition: time.c:704
vtm::year
VALUE year
Definition: timev.h:5
Qtrue
#define Qtrue
Definition: ruby.h:426
obj2vint
static VALUE obj2vint(VALUE obj)
Definition: time.c:2528
time_minus
static VALUE time_minus(VALUE time1, VALUE time2)
Definition: time.c:3734
small_vtm_sub
static VALUE small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
Definition: time.c:1504
OBJ_INIT_COPY
#define OBJ_INIT_COPY(obj, orig)
Definition: intern.h:287
time_hash
static VALUE time_hash(VALUE time)
Definition: time.c:3395
vtm::subsecx
VALUE subsecx
Definition: timev.h:11
time_localtime_m
static VALUE time_localtime_m(int argc, VALUE *argv, VALUE time)
Definition: time.c:3470
time_s_alloc
static VALUE time_s_alloc(VALUE klass)
Definition: time.c:1808
ST_CONTINUE
Definition: st.h:100
_
static VALUE time_utc_offset _((VALUE))
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
time_get_tm
static VALUE time_get_tm(VALUE, struct time_object *)
Definition: time.c:3621
calc_tm_yday
static int calc_tm_yday(long tm_year, int tm_mon, int tm_mday)
Definition: time.c:887
rb_big_plus
VALUE rb_big_plus(VALUE x, VALUE y)
Definition: bignum.c:5867
time_sec
static VALUE time_sec(VALUE time)
Definition: time.c:3868
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2411
rb_define_private_method
void rb_define_private_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1500
timeval::tv_sec
long tv_sec
Definition: ossl_asn1.c:17
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:548
T_RATIONAL
#define T_RATIONAL
Definition: ruby.h:495
leap_year_p
static int leap_year_p(long y)
Definition: time.c:2693
rb_long2int
#define rb_long2int(n)
Definition: ruby.h:317
DEBUG_REPORT_GUESSRANGE
#define DEBUG_REPORT_GUESSRANGE
Definition: time.c:2730
UWIDEINT_MAX
#define UWIDEINT_MAX
Definition: time.c:243
localtime_with_gmtoff_zone
static struct tm * localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone)
Definition: time.c:1604
WIDEVAL_GET
#define WIDEVAL_GET(w)
Definition: time.c:269
time_gmtime
static VALUE time_gmtime(VALUE)
Definition: time.c:3505
time_monday
static VALUE time_monday(VALUE time)
Definition: time.c:4043
rb_check_trusted
#define rb_check_trusted(obj)
Definition: intern.h:283
NDIV
#define NDIV(x, y)
Definition: time.c:39
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:775
common_year_days_in_month
static const int common_year_days_in_month[]
Definition: time.c:879
INTEGER_PACK_NATIVE_BYTE_ORDER
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Definition: intern.h:146
rb_time_succ
VALUE rb_time_succ(VALUE time)
Definition: time.c:3764
time_init
static VALUE time_init(int argc, VALUE *argv, VALUE time)
Definition: time.c:2216
rb_to_int
VALUE rb_to_int(VALUE)
Definition: object.c:2679
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
vtm_add_offset
static void vtm_add_offset(struct vtm *vtm, VALUE off)
Definition: time.c:1947
time_round
static VALUE time_round(int argc, VALUE *argv, VALUE time)
Definition: time.c:3817
add
static VALUE add(VALUE x, VALUE y)
Definition: time.c:73
div
#define div(x, y)
Definition: time.c:160
IsTimeval
#define IsTimeval(obj)
Definition: time.c:1749
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
st_init_strtable
st_table * st_init_strtable(void)
Definition: st.c:284
time_plus
static VALUE time_plus(VALUE time1, VALUE time2)
Definition: time.c:3707
wsub
static wideval_t wsub(wideval_t wx, wideval_t wy)
Definition: time.c:397
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_include_module
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:827
time_utc_offset
static VALUE time_utc_offset(VALUE time)
Definition: time.c:4228
leap_year_v_p
#define leap_year_v_p(y)
Definition: time.c:779
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:3604
time_usec
static VALUE time_usec(VALUE time)
Definition: time.c:3227
long_mul
static int long_mul(long x, long y, long *z)
Definition: time.c:98
compat_leap_month_table
static int compat_leap_month_table[7]
Definition: time.c:1398
st_update
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg)
Definition: st.c:867
FIXWV2WINT
#define FIXWV2WINT(w)
Definition: time.c:251
TIME_LOCALTIME_P
#define TIME_LOCALTIME_P(tobj)
Definition: time.c:1755
time_init_0
static VALUE time_init_0(VALUE time)
Definition: time.c:1902
rb_localtime_r2
static struct tm * rb_localtime_r2(const time_t *t, struct tm *result)
Definition: time.c:803
id_ne
static ID id_ne
Definition: time.c:37
time_memsize
static size_t time_memsize(const void *tobj)
Definition: time.c:1796
wadd
static wideval_t wadd(wideval_t wx, wideval_t wy)
Definition: time.c:381
time_mload
static VALUE time_mload(VALUE time, VALUE str)
Definition: time.c:4697
FIXNUM_P
#define FIXNUM_P(f)
Definition: ruby.h:347
rb_Float
VALUE rb_Float(VALUE)
Definition: object.c:2895
time_wednesday
static VALUE time_wednesday(VALUE time)
Definition: time.c:4075
rb_check_to_integer
VALUE rb_check_to_integer(VALUE, const char *)
Definition: object.c:2665
time_min
static VALUE time_min(VALUE time)
Definition: time.c:3888
time_cmp
static VALUE time_cmp(VALUE time1, VALUE time2)
Definition: time.c:3320
SMALLBUF
#define SMALLBUF
Definition: time.c:4280
rb_cmpint
int rb_cmpint(VALUE val, VALUE a, VALUE b)
Definition: bignum.c:2909
time_yday
static VALUE time_yday(VALUE time)
Definition: time.c:4139
rb_strftime_alloc
static size_t rb_strftime_alloc(char **buf, VALUE formatv, const char *format, rb_encoding *enc, struct vtm *vtm, wideval_t timew, int gmt)
Definition: time.c:4282
vtm::min
int min
Definition: timev.h:9
strftimev
static VALUE strftimev(const char *fmt, VALUE time, rb_encoding *enc)
Definition: time.c:4329
rb_eRangeError
VALUE rb_eRangeError
Definition: error.c:552
rb_obj_classname
const char * rb_obj_classname(VALUE)
Definition: variable.c:406
WINT2WV
#define WINT2WV(wi)
Definition: time.c:283
number_of_leap_seconds_known
static int number_of_leap_seconds_known
Definition: time.c:1200
time_add
static VALUE time_add(struct time_object *tobj, VALUE offset, int sign)
Definition: time.c:3675
time_new_timew
static VALUE time_new_timew(VALUE klass, wideval_t timew)
Definition: time.c:2266
timespec::tv_sec
time_t tv_sec
Definition: missing.h:51
time_object
Definition: time.c:1739
st_data_t
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
rb_obj_untaint
VALUE rb_obj_untaint(VALUE)
Definition: object.c:993
TIME_UTC_P
#define TIME_UTC_P(tobj)
Definition: time.c:1752
rb_gmtime_r2
static struct tm * rb_gmtime_r2(const time_t *t, struct tm *result)
Definition: time.c:832
WIDEVAL_WRAP
#define WIDEVAL_WRAP(v)
Definition: time.c:268
wv2timet
static time_t wv2timet(wideval_t w)
Definition: time.c:734
rb_singleton_class
VALUE rb_singleton_class(VALUE obj)
Returns the singleton class of obj.
Definition: class.c:1628
time_wday
static VALUE time_wday(VALUE time)
Definition: time.c:4000
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
nsec2timew
static wideval_t nsec2timew(time_t sec, long nsec)
Definition: time.c:2256
find_time_t
static const char * find_time_t(struct tm *tptr, int utc_p, time_t *tp)
Definition: time.c:2746
time_object::gmt
int gmt
Definition: time.c:1742
neg
#define neg(x)
Definition: time.c:171
time_asctime
static VALUE time_asctime(VALUE time)
Definition: time.c:3641
uwideint_t
unsigned long uwideint_t
Definition: time.c:238
RRATIONAL
#define RRATIONAL(obj)
Definition: ruby.h:1130
time_s_at
static VALUE time_s_at(int argc, VALUE *argv, VALUE klass)
Definition: time.c:2486
le
#define le(x, y)
Definition: time.c:69
time_set_utc_offset
static VALUE time_set_utc_offset(VALUE time, VALUE off)
Definition: time.c:1932
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
rb_rescue
VALUE rb_rescue(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*r_proc)(ANYARGS), VALUE data2)
Definition: eval.c:799
rb_mComparable
VALUE rb_mComparable
Definition: compar.c:14
GetNewTimeval
#define GetNewTimeval(obj, tobj)
Definition: time.c:1747
wmod
static wideval_t wmod(wideval_t wx, wideval_t wy)
Definition: time.c:592
rb_class_new_instance
VALUE rb_class_new_instance(int, VALUE *, VALUE)
Definition: object.c:1855
rb_strftime_timespec
size_t rb_strftime_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, int gmt)
Definition: strftime.c:837
time_load
static VALUE time_load(VALUE klass, VALUE str)
Definition: time.c:4822
timeval::tv_usec
long tv_usec
Definition: ossl_asn1.c:18
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
get_attr
#define get_attr(attr, iffound)
rb_time_new
VALUE rb_time_new(time_t sec, long usec)
Definition: time.c:2279
ne
#define ne(x, y)
Definition: time.c:66
wmulquoll
#define wmulquoll(x, y, z)
Definition: time.c:501
rb_str_to_inum
VALUE rb_str_to_inum(VALUE str, int base, int badcheck)
Definition: bignum.c:4129
TIME_SET_UTC
#define TIME_SET_UTC(tobj)
Definition: time.c:1753
obj2subsecx
static int obj2subsecx(VALUE obj, VALUE *subsecx)
Definition: time.c:2541
time_object::vtm
struct vtm vtm
Definition: time.c:1741
T_NIL
#define T_NIL
Definition: ruby.h:476
mod
static VALUE mod(VALUE x, VALUE y)
Definition: time.c:163
LOCALTIME
#define LOCALTIME(tm, result)
Definition: time.c:828
vtm
Definition: timev.h:4
time_saturday
static VALUE time_saturday(VALUE time)
Definition: time.c:4123
TIME_FIXOFF_P
#define TIME_FIXOFF_P(tobj)
Definition: time.c:1758
timev.h
FIXWVABLE
#define FIXWVABLE(i)
Definition: time.c:249
wcmp
static int wcmp(wideval_t wx, wideval_t wy)
Definition: time.c:354
id_div
static ID id_div
Definition: time.c:37
time_subsec
static VALUE time_subsec(VALUE time)
Definition: time.c:3286
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
timespec::tv_nsec
long tv_nsec
Definition: missing.h:52
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
id_cmp
static ID id_cmp
Definition: time.c:37
localtimew
static struct vtm * localtimew(wideval_t timew, struct vtm *result)
Definition: time.c:1691
unistd.h
time_arg
static void time_arg(int argc, VALUE *argv, struct vtm *vtm)
Definition: time.c:2625
rb_sys_fail_str
void rb_sys_fail_str(VALUE mesg)
Definition: error.c:1982
wdiv
static wideval_t wdiv(wideval_t wx, wideval_t wy)
Definition: time.c:584
WIDEVALUE
VALUE WIDEVALUE
Definition: time.c:240
T_FLOAT
#define T_FLOAT
Definition: ruby.h:481
GMTIME
#define GMTIME(tm, result)
Definition: time.c:845
rb_intern
#define rb_intern(str)
TYPE
#define TYPE(x)
Definition: ruby.h:505
argc
int argc
Definition: ruby.c:131
zone_str
static const char * zone_str(const char *s)
Definition: time.c:959
Qfalse
#define Qfalse
Definition: ruby.h:425
calc_wday
static int calc_wday(int year, int month, int day)
Definition: time.c:1404
wmul
static wideval_t wmul(wideval_t wx, wideval_t wy)
Definition: time.c:455
rb_Integer
VALUE rb_Integer(VALUE)
Definition: object.c:2736
TIME_INIT_P
#define TIME_INIT_P(tobj)
Definition: time.c:1750
FIXWV_MIN
#define FIXWV_MIN
Definition: time.c:248
time_eql
static VALUE time_eql(VALUE time1, VALUE time2)
Definition: time.c:3347
wideval_t
WIDEVALUE wideval_t
Definition: time.c:267
T_BIGNUM
#define T_BIGNUM
Definition: ruby.h:487
LONG_MAX
#define LONG_MAX
Definition: ruby.h:191
FIXWV_P
#define FIXWV_P(w)
Definition: time.c:256
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1352
validate_utc_offset
static VALUE validate_utc_offset(VALUE utc_offset)
Definition: time.c:2596
rb_gmtime_r
static struct tm * rb_gmtime_r(const time_t *tp, struct tm *result)
Definition: time.c:786
mulquo
#define mulquo(x, y, z)
Definition: time.c:196
rb_num_zerodiv
void rb_num_zerodiv(void)
Definition: numeric.c:125
guess_local_offset
static VALUE guess_local_offset(struct vtm *vtm_utc, int *isdst_ret, const char **zone_ret)
Definition: time.c:1418
weq
static int weq(wideval_t wx, wideval_t wy)
Definition: time.c:341
encoding.h
time_localtime
static VALUE time_localtime(VALUE)
Definition: time.c:3426
vtm::utc_offset
VALUE utc_offset
Definition: timev.h:12
time_mday
static VALUE time_mday(VALUE time)
Definition: time.c:3930
gmtimew_noleapsecond
static void gmtimew_noleapsecond(wideval_t timew, struct vtm *vtm)
Definition: time.c:969
utc_offset_arg
static VALUE utc_offset_arg(VALUE arg)
Definition: time.c:2075
WIDEINT_MAX
#define WIDEINT_MAX
Definition: time.c:244
time_to_i
static VALUE time_to_i(VALUE time)
Definition: time.c:3153
Init_Time
void Init_Time(void)
Definition: time.c:4919
divmodv
static void divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
Definition: time.c:199
id_zone
static ID id_zone
Definition: time.c:36
rb_big_minus
VALUE rb_big_minus(VALUE x, VALUE y)
Definition: bignum.c:5903
id_mul
static ID id_mul
Definition: time.c:36
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:841
time_to_s
static VALUE time_to_s(VALUE time)
Definition: time.c:3663
rb_locale_str_new_cstr
VALUE rb_locale_str_new_cstr(const char *)
Definition: string.c:725
id_submicro
static ID id_submicro
Definition: time.c:36
time_to_f
static VALUE time_to_f(VALUE time)
Definition: time.c:3177
timeval
Definition: ossl_asn1.c:16
errno
int errno
TRUE
#define TRUE
Definition: nkf.h:175
CLOCK_REALTIME
#define CLOCK_REALTIME
Definition: win32.h:128
leap_year_yday_offset
static const int leap_year_yday_offset[]
Definition: time.c:863
rb_strftime
size_t rb_strftime(char *s, size_t maxsize, const char *format, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt)
Definition: strftime.c:831
time_getgmtime
static VALUE time_getgmtime(VALUE time)
Definition: time.c:3615
rb_localtime_r
static struct tm * rb_localtime_r(const time_t *tp, struct tm *result)
Definition: time.c:794
validate_vtm
static void validate_vtm(struct vtm *vtm)
Definition: time.c:2611
const
#define const
Definition: strftime.c:102
time_succ
#define time_succ
Definition: time.c:3777
id_lshift
static ID id_lshift
Definition: time.c:37
rb_Rational1
#define rb_Rational1(x)
Definition: intern.h:173
strdup
#define strdup(s)
Definition: util.h:67
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
rb_ivar_set
VALUE rb_ivar_set(VALUE, ID, VALUE)
Definition: variable.c:1133
TIME_COPY_GMT
#define TIME_COPY_GMT(tobj1, tobj2)
Definition: time.c:1764
time_free
static void time_free(void *tobj)
Definition: time.c:1790
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
rb_time_magnify
static wideval_t rb_time_magnify(wideval_t w)
Definition: time.c:655
PRIsVALUE
#define PRIsVALUE
Definition: ruby.h:137
internal.h
ID
unsigned long ID
Definition: ruby.h:89
rb_usascii_encoding
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1257
Qnil
#define Qnil
Definition: ruby.h:427
time_fixoff
static VALUE time_fixoff(VALUE)
Definition: time.c:3529
num_exact
static VALUE num_exact(VALUE v)
Definition: time.c:600
TIMET2WV
#define TIMET2WV(t)
Definition: time.c:731
VALUE
unsigned long VALUE
Definition: ruby.h:88
rb_big_mul
VALUE rb_big_mul(VALUE x, VALUE y)
Definition: bignum.c:5997
time_init_1
static VALUE time_init_1(int argc, VALUE *argv, VALUE time)
Definition: time.c:2111
wi_mul
static int wi_mul(wideint_t x, wideint_t y, wideint_t *z)
Definition: time.c:413
zone_table
static st_table * zone_table
Definition: time.c:941
result
static VALUE result
Definition: nkf.c:40
rb_enc_str_asciicompat_p
#define rb_enc_str_asciicompat_p(str)
Definition: encoding.h:200
time_timespec
static struct timespec time_timespec(VALUE num, int interval)
Definition: time.c:2326
sub
static VALUE sub(VALUE x, VALUE y)
Definition: time.c:85
id_nano_num
static ID id_nano_num
Definition: time.c:36
rb_ary_new3
#define rb_ary_new3
Definition: intern.h:91
rb_check_funcall
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:409
clock_gettime
int clock_gettime(clockid_t, struct timespec *)
Definition: win32.c:4319
rb_time_nano_new
VALUE rb_time_nano_new(time_t sec, long nsec)
Definition: time.c:2305
timew_out_of_timet_range
static int timew_out_of_timet_range(wideval_t timew)
Definition: time.c:1658
DIV
#define DIV(n, d)
Definition: time.c:41
rb_absint_size
size_t rb_absint_size(VALUE val, int *nlz_bits_ret)
Definition: bignum.c:3231
mul
static VALUE mul(VALUE x, VALUE y)
Definition: time.c:141
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
gmtimew
static struct vtm * gmtimew(wideval_t timew, struct vtm *result)
Definition: time.c:1280
usec2subsecx
static long usec2subsecx(VALUE obj)
Definition: time.c:2557
FIXABLE
#define FIXABLE(f)
Definition: ruby.h:350
time_object::timew
wideval_t timew
Definition: time.c:1740
validate_zone_name
static VALUE validate_zone_name(VALUE zone_name)
Definition: time.c:2604
id_nano_den
static ID id_nano_den
Definition: time.c:36
ge
#define ge(x, y)
Definition: time.c:70
month_arg
static int month_arg(VALUE arg)
Definition: time.c:2567
TYPEOF_TIMEVAL_TV_USEC
#define TYPEOF_TIMEVAL_TV_USEC
Definition: timev.h:28
time_tuesday
static VALUE time_tuesday(VALUE time)
Definition: time.c:4059
LONG2NUM
#define LONG2NUM(x)
Definition: ruby.h:1309
rb_time_unmagnify
static wideval_t rb_time_unmagnify(wideval_t w)
Definition: time.c:666
vtm::mon
int mon
Definition: timev.h:6
v2w
static wideval_t v2w(VALUE v)
Definition: time.c:321
time_to_a
static VALUE time_to_a(VALUE time)
Definition: time.c:4261
time_thursday
static VALUE time_thursday(VALUE time)
Definition: time.c:4091
rb_respond_to
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:1639
common_year_yday_offset
static const int common_year_yday_offset[]
Definition: time.c:848
time_timeval
static struct timeval time_timeval(VALUE num, int interval)
Definition: time.c:2398
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:541
time_strftime
static VALUE time_strftime(VALUE time, VALUE format)
Definition: time.c:4532
timegmw_noleapsecond
static wideval_t timegmw_noleapsecond(struct vtm *vtm)
Definition: time.c:901
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:845
time_hour
static VALUE time_hour(VALUE time)
Definition: time.c:3908
known_leap_seconds_limit
static time_t known_leap_seconds_limit
Definition: time.c:1199
rb_equal
VALUE rb_equal(VALUE, VALUE)
Definition: object.c:89
rb_enc_get
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:832
wlt
#define wlt(x, y)
Definition: time.c:375
RFLOAT_VALUE
#define RFLOAT_VALUE(v)
Definition: ruby.h:814
size
int size
Definition: encoding.c:49
f
#define f
INT2FIX
#define INT2FIX(i)
Definition: ruby.h:231
TIME_SET_LOCALTIME
#define TIME_SET_LOCALTIME(tobj)
Definition: time.c:1756
id_divmod
static ID id_divmod
Definition: time.c:36
xmalloc
#define xmalloc
Definition: defines.h:108
time_mdump
static VALUE time_mdump(VALUE time)
Definition: time.c:4584
time_mark
static void time_mark(void *ptr)
Definition: time.c:1778
rb_data_type_struct
Definition: ruby.h:966
MOD
#define MOD(n, d)
Definition: time.c:42
rb_check_array_type
VALUE rb_check_array_type(VALUE ary)
Definition: array.c:628
TIME_SET_FIXOFF
#define TIME_SET_FIXOFF(tobj, off)
Definition: time.c:1759
time_isdst
static VALUE time_isdst(VALUE time)
Definition: time.c:4174
time_dup
static VALUE time_dup(VALUE time)
Definition: time.c:3418
time_s_mkutc
static VALUE time_s_mkutc(int argc, VALUE *argv, VALUE klass)
Definition: time.c:3103
timespec2timew
static wideval_t timespec2timew(struct timespec *ts)
Definition: time.c:1851
MAKE_TM
#define MAKE_TM(time, tobj)
Definition: time.c:1770
rb_check_string_type
VALUE rb_check_string_type(VALUE)
Definition: string.c:1679
gmtime_with_leapsecond
static struct tm * gmtime_with_leapsecond(const time_t *timep, struct tm *result)
Definition: time.c:1075
key
uint8_t key[16]
Definition: random.c:1250
gt
#define gt(x, y)
Definition: time.c:68
rb_time_timespec
struct timespec rb_time_timespec(VALUE time)
Definition: time.c:2434
LONG2FIX
#define LONG2FIX(i)
Definition: ruby.h:232
RTEST
#define RTEST(v)
Definition: ruby.h:437
T_STRING
#define T_STRING
Definition: ruby.h:482
vtm::isdst
int isdst
Definition: timev.h:15
wmuldivmod
static void wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr)
Definition: time.c:573
timespec
Definition: missing.h:50
compat_common_month_table
static int compat_common_month_table[12][7]
Definition: time.c:1357
time_overflow_p
static void time_overflow_p(time_t *secp, long *nsecp)
Definition: time.c:2225
SIGNED_WIDEVALUE
SIGNED_VALUE SIGNED_WIDEVALUE
Definition: time.c:241
zone
Definition: date_parse.c:336
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
init_leap_second_info
static void init_leap_second_info(void)
Definition: time.c:1203
rb_enc_str_new
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:548
time_friday
static VALUE time_friday(VALUE time)
Definition: time.c:4107
leap_year_days_in_month
static const int leap_year_days_in_month[]
Definition: time.c:882
vtm::hour
int hour
Definition: timev.h:8
digit
#define digit(x)
Definition: langinfo.c:58
wdivmod
static void wdivmod(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
Definition: time.c:504
ID2SYM
#define ID2SYM(x)
Definition: ruby.h:355
vtm::mday
int mday
Definition: timev.h:7
timew2timespec
static struct timespec timew2timespec(wideval_t timew)
Definition: time.c:1862
rb_cTime
VALUE rb_cTime
Definition: time.c:756
vtm::sec
int sec
Definition: timev.h:10
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:540
time_zone
static VALUE time_zone(VALUE time)
Definition: time.c:4197
rb_str_new_frozen
VALUE rb_str_new_frozen(VALUE)
Definition: string.c:833
STRCASECMP
#define STRCASECMP(s1, s2)
Definition: ruby.h:1783
FIXWV_MAX
#define FIXWV_MAX
Definition: time.c:247
TIME_SCALE
#define TIME_SCALE
Definition: timev.h:19
id_offset
static ID id_offset
Definition: time.c:36
lt
#define lt(x, y)
Definition: time.c:67
rb_warning
void rb_warning(const char *fmt,...)
Definition: error.c:236
timet2wv
static wideval_t timet2wv(time_t t)
Definition: time.c:713
rb_check_frozen
#define rb_check_frozen(obj)
Definition: intern.h:277
time_modify
static void time_modify(VALUE time)
Definition: time.c:1844
time_s_mktime
static VALUE time_s_mktime(int argc, VALUE *argv, VALUE klass)
Definition: time.c:3134
id_quo
static ID id_quo
Definition: time.c:37
rb_copy_generic_ivar
void rb_copy_generic_ivar(VALUE, VALUE)
Definition: variable.c:1049
zone_str_update
static int zone_str_update(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
Definition: time.c:944
time_year
static VALUE time_year(VALUE time)
Definition: time.c:3972
xfree
void void xfree(void *)
vtm::wday
int wday
Definition: timev.h:13
rb_time_unmagnify_to_float
static VALUE rb_time_unmagnify_to_float(wideval_t w)
Definition: time.c:683
time_init_copy
static VALUE time_init_copy(VALUE copy, VALUE time)
Definition: time.c:3405
NULL
#define NULL
Definition: _sdbm.c:103
FIX2LONG
#define FIX2LONG(x)
Definition: ruby.h:345
Qundef
#define Qundef
Definition: ruby.h:428
time_nsec
static VALUE time_nsec(VALUE time)
Definition: time.c:3258
rb_invcmp
VALUE rb_invcmp(VALUE x, VALUE y)
Definition: compar.c:42
months
static const char months[][4]
Definition: time.c:2512
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
get_timeval
static struct time_object * get_timeval(VALUE obj)
Definition: time.c:1822
eq
static int eq(VALUE x, VALUE y)
Definition: time.c:45
rb_warn
void rb_warn(const char *fmt,...)
Definition: error.c:223
rb_eArgError
VALUE rb_eArgError
Definition: error.c:549
time_dump
static VALUE time_dump(int argc, VALUE *argv, VALUE time)
Definition: time.c:4685
NUM2LONG
#define NUM2LONG(x)
Definition: ruby.h:600
rb_time_timeval
struct timeval rb_time_timeval(VALUE time)
Definition: time.c:2417
TYPEOF_TIMEVAL_TV_SEC
#define TYPEOF_TIMEVAL_TV_SEC
Definition: timev.h:22
argv
char ** argv
Definition: ruby.c:132
DBL2NUM
#define DBL2NUM(dbl)
Definition: ruby.h:815
StringValue
#define StringValue(v)
Definition: ruby.h:539
OnigEncodingTypeST
Definition: oniguruma.h:158
wday_p
#define wday_p(n)
Definition: time.c:4009
rb_str_new
VALUE rb_str_new(const char *, long)
Definition: string.c:534
rb_obj_class
VALUE rb_obj_class(VALUE)
Definition: object.c:226
SIGNED_VALUE
#define SIGNED_VALUE
Definition: ruby.h:90
timegmw
static wideval_t timegmw(struct vtm *vtm)
Definition: time.c:1245
rb_time_num_new
VALUE rb_time_num_new(VALUE timev, VALUE off)
Definition: time.c:2311
wquo
static wideval_t wquo(wideval_t wx, wideval_t wy)
Definition: time.c:475