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