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