12 #define _DEFAULT_SOURCE
14 #include "ruby/internal/config.h"
20 #include <sys/types.h>
30 #if defined(HAVE_SYS_TIME_H)
31 # include <sys/time.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"
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;
56 #define id_divmod idDivmod
57 #define id_name idName
58 #define UTC_ZONE Qundef
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)
84 if ((
long)x < (
long)y)
86 if ((
long)x > (
long)y)
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)
124 return rb_fix_mul_fix(x, y);
126 if (RB_BIGNUM_TYPE_P(x))
135 return rb_fix_div_fix(x, y);
137 if (RB_BIGNUM_TYPE_P(x))
147 if (
FIXNUM_P(x))
return rb_fix_mod_fix(x, y);
153 #define neg(x) (subv(INT2FIX(0), (x)))
169 return rb_numeric_quo(x, y);
175 VALUE ret = quor(x, y);
177 RRATIONAL(ret)->den ==
INT2FIX(1)) {
178 ret = RRATIONAL(ret)->num;
183 #define mulquov(x,y,z) (((y) == (z)) ? (x) : quov(mulv((x),(y)),(z)))
192 rb_fix_divmod_fix(n, d, q, r);
207 # define INT64toNUM(x) LONG2NUM(x)
208 #elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
209 # define INT64toNUM(x) LL2NUM(x)
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))
230 typedef unsigned long uwideint_t;
231 typedef long wideint_t;
232 typedef VALUE 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))
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)
252 #ifdef STRUCT_WIDEVAL
257 static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v };
return w; }
258 # define WIDEVAL_GET(w) ((w).value)
260 typedef WIDEVALUE wideval_t;
261 # define WIDEVAL_WRAP(v) (v)
262 # define WIDEVAL_GET(w) (w)
265 #if WIDEVALUE_IS_WIDER
266 static inline wideval_t
267 wint2wv(wideint_t wi)
270 return WINT2FIXWV(wi);
272 return WIDEVAL_WRAP(INT64toNUM(wi));
274 # define WINT2WV(wi) wint2wv(wi)
276 # define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi))
282 #if WIDEVALUE_IS_WIDER
284 return INT64toNUM(FIXWV2WINT(w));
285 return (
VALUE)WIDEVAL_GET(w);
287 return WIDEVAL_GET(w);
291 #if WIDEVALUE_IS_WIDER
300 return WINT2FIXWV(0);
301 else if (sign == -1) {
303 return WINT2FIXWV(-(wideint_t)u);
305 else if (sign == +1) {
307 return WINT2FIXWV((wideint_t)u);
309 return WIDEVAL_WRAP(v);
313 static inline wideval_t
317 if (RRATIONAL(v)->den !=
LONG2FIX(1))
318 return WIDEVAL_WRAP(v);
319 v = RRATIONAL(v)->num;
321 #if WIDEVALUE_IS_WIDER
323 return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(
long)v);
325 else if (RB_BIGNUM_TYPE_P(v) &&
327 return v2w_bignum(v);
330 return WIDEVAL_WRAP(v);
334 weq(wideval_t wx, wideval_t wy)
336 #if WIDEVALUE_IS_WIDER
337 if (FIXWV_P(wx) && FIXWV_P(wy)) {
338 return WIDEVAL_GET(wx) == WIDEVAL_GET(wy);
342 return eq(WIDEVAL_GET(wx), WIDEVAL_GET(wy));
347 wcmp(wideval_t wx, wideval_t wy)
350 #if WIDEVALUE_IS_WIDER
351 if (FIXWV_P(wx) && FIXWV_P(wy)) {
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)
374 wadd(wideval_t wx, wideval_t wy)
376 #if WIDEVALUE_IS_WIDER
377 if (FIXWV_P(wx) && FIXWV_P(wy)) {
378 wideint_t r = FIXWV2WINT(wx) + FIXWV2WINT(wy);
382 return v2w(addv(w2v(wx), w2v(wy)));
386 wsub(wideval_t wx, wideval_t wy)
388 #if WIDEVALUE_IS_WIDER
389 if (FIXWV_P(wx) && FIXWV_P(wy)) {
390 wideint_t r = FIXWV2WINT(wx) - FIXWV2WINT(wy);
394 return v2w(subv(w2v(wx), w2v(wy)));
398 wmul(wideval_t wx, wideval_t wy)
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));
406 return v2w(mulv(w2v(wx), w2v(wy)));
410 wquo(wideval_t wx, wideval_t wy)
412 #if WIDEVALUE_IS_WIDER
413 if (FIXWV_P(wx) && FIXWV_P(wy)) {
424 return v2w(quov(w2v(wx), w2v(wy)));
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)))
430 #if WIDEVALUE_IS_WIDER
432 wdivmod0(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
434 if (FIXWV_P(wn) && FIXWV_P(wd)) {
435 wideint_t n, d, q, r;
444 wideint_t xneg = -FIXWV2WINT(wn);
457 if (d > 0 ? r < 0 : r > 0) {
470 wdivmod(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr)
473 #if WIDEVALUE_IS_WIDER
474 if (wdivmod0(wn, wd, wq, wr))
return;
476 divmodv(w2v(wn), w2v(wd), &vq, &vr);
482 wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr)
484 if (WIDEVAL_GET(wy) == WIDEVAL_GET(wz)) {
489 wdivmod(wmul(wx,wy), wz, wq, wr);
493 wdiv(wideval_t wx, wideval_t wy)
495 #if WIDEVALUE_IS_WIDER
497 if (wdivmod0(wx, wy, &q, &dmy))
return q;
499 return v2w(divv(w2v(wx), w2v(wy)));
503 wmod(wideval_t wx, wideval_t wy)
505 #if WIDEVALUE_IS_WIDER
507 if (wdivmod0(wx, wy, &dmy, &r))
return r;
509 return v2w(modv(w2v(wx), w2v(wy)));
523 return rb_rational_canonicalize(v);
536 return rb_rational_canonicalize(tmp);
553 rb_time_magnify(wideval_t w)
555 return wmul(w, WINT2FIXWV(TIME_SCALE));
559 rb_time_unmagnify_to_rational(wideval_t w)
561 return quor(w2v(w),
INT2FIX(TIME_SCALE));
565 rb_time_unmagnify(wideval_t w)
567 return v2w(rb_time_unmagnify_to_rational(w));
571 rb_time_unmagnify_to_float(wideval_t w)
574 #if WIDEVALUE_IS_WIDER
583 v =
DBL2NUM((
double)FIXWV2WINT(w));
584 return quov(v,
DBL2NUM(TIME_SCALE));
591 return quov(v,
DBL2NUM(TIME_SCALE));
595 split_second(wideval_t timew, wideval_t *timew_p,
VALUE *subsecx_p)
598 wdivmod(timew, WINT2FIXWV(TIME_SCALE), &q, &r);
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);
614 wideint_t wi = (wideint_t)t;
615 if (FIXWV_MIN <= wi && wi <= FIXWV_MAX) {
616 return WINT2FIXWV(wi);
620 return v2w(TIMET2NUM(t));
622 #define TIMET2WV(t) timet2wv(t)
625 wv2timet(wideval_t w)
627 #if WIDEVALUE_IS_WIDER
629 wideint_t wi = FIXWV2WINT(w);
630 if (TIMET_MIN == 0) {
633 if (TIMET_MAX < (uwideint_t)wi)
637 if (wi < TIMET_MIN || TIMET_MAX < wi)
643 return NUM2TIMET(w2v(w));
645 #define WV2TIMET(t) wv2timet(t)
648 static VALUE rb_cTimeTM;
650 static int obj2int(
VALUE obj);
651 static uint32_t obj2ubits(
VALUE obj,
unsigned int bits);
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);
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);
670 static struct vtm *localtimew(wideval_t timew,
struct vtm *result);
672 static int leap_year_p(
long y);
673 #define leap_year_v_p(y) leap_year_p(NUM2LONG(modv((y), INT2FIX(400))))
677 bool ruby_tz_uptodate_p;
680 ruby_reset_timezone(
void)
682 ruby_tz_uptodate_p =
false;
683 ruby_reset_leap_second_info();
689 if (ruby_tz_uptodate_p)
return;
690 ruby_tz_uptodate_p =
true;
695 rb_localtime_r(
const time_t *t,
struct tm *result)
697 #if defined __APPLE__ && defined __LP64__
698 if (*t != (time_t)(
int)*t)
return NULL;
702 result = localtime_r(t, result);
705 struct tm *tmp = localtime(t);
706 if (tmp) *result = *tmp;
709 #if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
713 struct tm tmp = *result;
716 # if defined(HAVE_STRUCT_TM_TM_GMTOFF)
717 gmtoff1 = result->tm_gmtoff;
718 gmtoff2 = tmp.tm_gmtoff;
720 if (*t + gmtoff1 != t2 + gmtoff2)
726 #define LOCALTIME(tm, result) rb_localtime_r((tm), &(result))
728 #ifndef HAVE_STRUCT_TM_TM_GMTOFF
730 rb_gmtime_r(
const time_t *t,
struct tm *result)
733 result = gmtime_r(t, result);
735 struct tm *tmp = gmtime(t);
736 if (tmp) *result = *tmp;
738 #if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
739 if (result && *t != timegm(result)) {
745 # define GMTIME(tm, result) rb_gmtime_r((tm), &(result))
748 static const int16_t common_year_yday_offset[] = {
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
763 static const int16_t leap_year_yday_offset[] = {
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
779 static const int8_t common_year_days_in_month[] = {
780 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
782 static const int8_t leap_year_days_in_month[] = {
783 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
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))
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)
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)
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)
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)
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)
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)
823 10,11,12,13,14,15,16,17,18,19, \
824 20,21,22,23,24,25,26,27,28
827 10,11,12,13,14,15,16,17,18,19, \
828 20,21,22,23,24,25,26,27,28,29
831 10,11,12,13,14,15,16,17,18,19, \
832 20,21,22,23,24,25,26,27,28,29,30
835 10,11,12,13,14,15,16,17,18,19, \
836 20,21,22,23,24,25,26,27,28,29,30,31
838 static const uint8_t common_year_mday_of_yday[] = {
840 D31, D28, D31, D30, D31, D30, D31, D31, D30, D31, D30, D31
842 static const uint8_t leap_year_mday_of_yday[] = {
843 D31, D29, D31, D30, D31, D30, D31, D31, D30, D31, D30, D31
852 calc_tm_yday(
long tm_year,
int tm_mon,
int tm_mday)
854 int tm_year_mod400 = (int)MOD(tm_year, 400);
855 int tm_yday = tm_mday;
857 if (leap_year_p(tm_year_mod400 + 1900))
858 tm_yday += leap_year_yday_offset[tm_mon];
860 tm_yday += common_year_yday_offset[tm_mon];
866 timegmw_noleapsecond(
struct vtm *
vtm)
878 divmodv(year1900,
INT2FIX(400), &q400, &r400);
881 yday = calc_tm_yday(year_mod400,
vtm->mon-1,
vtm->mday);
894 + DIV(year_mod400 - 69, 4)
895 - DIV(year_mod400 - 1, 100)
896 + (year_mod400 + 299) / 400;
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));
907 zone_str(
const char *zone)
915 return rb_fstring_lit(
"(NO-TIMEZONE-ABBREVIATION)");
918 for (p = zone; *p; p++)
923 len = p - zone + strlen(p);
930 return rb_fstring(str);
934 gmtimew_noleapsecond(wideval_t timew,
struct vtm *
vtm)
940 wideval_t timew2, w, w2;
945 split_second(timew, &timew2, &subsecx);
946 vtm->subsecx = subsecx;
948 wdivmod(timew2, WINT2FIXWV(86400), &w2, &w);
953 vtm->wday = (wday + 4) % 7;
956 vtm->sec = n % 60; n = n / 60;
957 vtm->min = n % 60; n = n / 60;
961 divmodv(timev,
INT2FIX(400*365 + 97), &timev, &v);
974 if (30*365+7+31+29-1 <= n) {
988 x = n / (365*100 + 24);
989 n = n % (365*100 + 24);
991 if (30*365+7+31+29-1 <= n) {
1001 x = n / (365*4 + 1);
1002 n = n % (365*4 + 1);
1004 if (365*2+31+29-1 <= n) {
1005 if (n < 365*2+366) {
1022 if (leap_year_p(y)) {
1023 vtm->mon = leap_year_mon_of_yday[n];
1024 vtm->mday = leap_year_mday_of_yday[n];
1027 vtm->mon = common_year_mon_of_yday[n];
1028 vtm->mday = common_year_mday_of_yday[n];
1032 vtm->zone = str_utc;
1036 gmtime_with_leapsecond(
const time_t *timep,
struct tm *result)
1038 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1042 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
1044 t = LOCALTIME(timep, *result);
1049 if (t->tm_gmtoff < 0) {
1051 gmtoff = -t->tm_gmtoff;
1055 gmtoff = t->tm_gmtoff;
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;
1065 gmtoff_hour *= sign;
1072 result->tm_sec += gmtoff_sec;
1073 if (result->tm_sec < 0) {
1074 result->tm_sec += 60;
1077 if (60 <= result->tm_sec) {
1078 result->tm_sec -= 60;
1083 result->tm_min += gmtoff_min;
1084 if (result->tm_min < 0) {
1085 result->tm_min += 60;
1088 if (60 <= result->tm_min) {
1089 result->tm_min -= 60;
1094 result->tm_hour += gmtoff_hour;
1095 if (result->tm_hour < 0) {
1096 result->tm_hour += 24;
1099 if (24 <= result->tm_hour) {
1100 result->tm_hour -= 24;
1106 if (gmtoff_day < 0) {
1107 if (result->tm_yday == 0) {
1108 result->tm_mday = 31;
1109 result->tm_mon = 11;
1111 result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
1113 else if (result->tm_mday == 1) {
1114 const int8_t *days_in_month = days_in_month_of(result->tm_year + 1900);
1116 result->tm_mday = days_in_month[result->tm_mon];
1123 result->tm_wday = (result->tm_wday + 6) % 7;
1126 int leap = leap_year_p(result->tm_year + 1900);
1127 if (result->tm_yday == (leap ? 365 : 364)) {
1130 result->tm_mday = 1;
1131 result->tm_yday = 0;
1133 else if (result->tm_mday == days_in_month_of(leap)[result->tm_mon]) {
1135 result->tm_mday = 1;
1142 result->tm_wday = (result->tm_wday + 1) % 7;
1145 result->tm_isdst = 0;
1146 result->tm_gmtoff = 0;
1147 #if defined(HAVE_TM_ZONE)
1148 result->tm_zone = (
char *)
"UTC";
1152 return GMTIME(timep, *result);
1156 static long this_year = 0;
1157 static time_t known_leap_seconds_limit;
1158 static int number_of_leap_seconds_known;
1161 init_leap_second_info(
void)
1168 if (this_year == 0) {
1170 struct tm *tm, result;
1174 #ifdef HAVE_GMTIME_R
1175 gmtime_r(&now, &result);
1179 tm = gmtime_with_leapsecond(&now, &result);
1181 this_year = tm->tm_year;
1183 if (TIMET_MAX - now < (time_t)(366*86400))
1184 known_leap_seconds_limit = TIMET_MAX;
1186 known_leap_seconds_limit = now + (time_t)(366*86400);
1188 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
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;
1200 timew = timegmw_noleapsecond(&
vtm);
1202 number_of_leap_seconds_known =
NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
1208 ruby_reset_leap_second_info(
void)
1224 return timegmw_noleapsecond(
vtm);
1226 init_leap_second_info();
1228 timew = timegmw_noleapsecond(
vtm);
1231 if (number_of_leap_seconds_known == 0) {
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)));
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;
1249 errmsg = find_time_t(&tm, 1, &t);
1252 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(
vtm->subsecx));
1256 gmtimew(wideval_t timew,
struct vtm *result)
1263 if (wlt(timew, WINT2FIXWV(0))) {
1264 gmtimew_noleapsecond(timew, result);
1268 init_leap_second_info();
1270 if (number_of_leap_seconds_known == 0) {
1274 gmtimew_noleapsecond(timew, result);
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);
1283 split_second(timew, &timew2, &subsecx);
1285 t = WV2TIMET(timew2);
1286 if (!gmtime_with_leapsecond(&t, &tm))
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;
1301 result->zone = rb_fstring_lit(
"UTC");
1307 #define GMTIMEW(w, v) \
1308 (gmtimew(w, v) ? (void)0 : rb_raise(rb_eArgError, "gmtime error"))
1310 static struct tm *localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *zone);
1345 static const int compat_common_month_table[12][7] = {
1347 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 },
1348 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 },
1349 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1350 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1351 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 },
1352 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 },
1353 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1354 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 },
1355 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1356 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 },
1357 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1358 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1386 static const int compat_leap_month_table[7] = {
1388 2032, 2016, 2028, 2012, 2024, 2036, 2020,
1392 calc_wday(
int year_mod400,
int month,
int day)
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;
1406 guess_local_offset(
struct vtm *vtm_utc,
int *isdst_ret,
VALUE *zone_ret)
1414 int year_mod400, wday;
1418 if (lt(vtm_utc->year,
INT2FIX(1916))) {
1421 zone = rb_fstring_lit(
"UTC");
1423 # if defined(NEGATIVE_TIME_T)
1424 # if SIZEOF_TIME_T <= 4
1426 # define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
1430 # define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
1432 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
1434 isdst = tm.tm_isdst;
1439 if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
1441 isdst = tm.tm_isdst;
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]);
1461 vtm2.year =
INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
1463 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
1464 t = NUM2TIMET(timev);
1466 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1468 *isdst_ret = tm.tm_isdst;
1476 static time_t now = 0;
1477 static long now_gmtoff = 0;
1478 static int now_isdst = 0;
1479 static VALUE now_zone;
1483 localtime_with_gmtoff_zone(&now, &tm, &now_gmtoff, &zone);
1484 now_isdst = tm.tm_isdst;
1485 zone = rb_fstring(zone);
1490 *isdst_ret = now_isdst;
1492 *zone_ret = now_zone;
1498 small_vtm_sub(
struct vtm *vtm1,
struct vtm *vtm2)
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;
1516 timelocalw(
struct vtm *
vtm)
1521 wideval_t timew1, timew2;
1522 struct vtm vtm1, vtm2;
1527 if (l < INT_MIN || INT_MAX < l)
1529 tm.tm_year = (int)l;
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;
1545 if (find_time_t(&tm, 0, &t))
1547 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(
vtm->subsecx));
1550 timew1 = timegmw(
vtm);
1552 if (!localtimew(timew1, &vtm1))
1555 n = vtmcmp(
vtm, &vtm1);
1557 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(12*3600)));
1558 if (!localtimew(timew1, &vtm1))
1566 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1567 if (!localtimew(timew1, &vtm1))
1571 timew2 = wadd(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1572 if (!localtimew(timew2, &vtm2))
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))));
1578 if (weq(timew1, timew2))
1581 if (!localtimew(timew1, &vtm1))
1583 if (
vtm->hour != vtm1.hour ||
vtm->min != vtm1.min ||
vtm->sec != vtm1.sec)
1586 if (!localtimew(timew2, &vtm2))
1588 if (
vtm->hour != vtm2.hour ||
vtm->min != vtm2.min ||
vtm->sec != vtm2.sec)
1592 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
1594 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
1598 localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *zone)
1602 if (LOCALTIME(t, tm)) {
1603 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1604 *gmtoff = tm.tm_gmtoff;
1610 u = GMTIME(t, tmbuf);
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;
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;
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
1636 *zone = zone_str(tzname[daylight && tm.tm_isdst]);
1640 strftime(buf,
sizeof(buf),
"%Z", &tm);
1641 *zone = zone_str(buf);
1653 timew_out_of_timet_range(wideval_t timew)
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)
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) {
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))
1686 localtimew(wideval_t timew,
struct vtm *result)
1688 VALUE subsecx, offset;
1692 if (!timew_out_of_timet_range(timew)) {
1698 split_second(timew, &timew2, &subsecx);
1700 t = WV2TIMET(timew2);
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;
1719 if (!gmtimew(timew, result))
1722 offset = guess_local_offset(result, &isdst, &zone);
1724 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
1727 result->utc_offset = offset;
1728 result->isdst = isdst;
1729 result->zone = zone;
1734 #define TIME_TZMODE_LOCALTIME 0
1735 #define TIME_TZMODE_UTC 1
1736 #define TIME_TZMODE_FIXOFF 2
1737 #define TIME_TZMODE_UNINITIALIZED 3
1742 unsigned int tzmode:3;
1743 unsigned int tm_got:1;
1746 #define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj))
1747 #define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj))
1749 #define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type)
1750 #define TIME_INIT_P(tobj) ((tobj)->tzmode != TIME_TZMODE_UNINITIALIZED)
1752 #define TZMODE_UTC_P(tobj) ((tobj)->tzmode == TIME_TZMODE_UTC)
1753 #define TZMODE_SET_UTC(tobj) ((tobj)->tzmode = TIME_TZMODE_UTC)
1755 #define TZMODE_LOCALTIME_P(tobj) ((tobj)->tzmode == TIME_TZMODE_LOCALTIME)
1756 #define TZMODE_SET_LOCALTIME(tobj) ((tobj)->tzmode = TIME_TZMODE_LOCALTIME)
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))
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)
1768 static int zone_localtime(
VALUE zone,
VALUE time);
1770 #define MAKE_TM(time, tobj) \
1772 if ((tobj)->tm_got == 0) { \
1773 time_get_tm((time), (tobj)); \
1776 #define MAKE_TM_ENSURE(time, tobj, cond) \
1778 MAKE_TM(time, tobj); \
1780 force_make_tm(time, tobj); \
1787 VALUE zone = tobj->vtm.zone;
1788 if (!
NIL_P(zone) && zone != str_empty && zone != str_utc) {
1789 if (zone_localtime(zone, time))
return;
1792 time_get_tm(time, tobj);
1796 time_mark(
void *ptr)
1799 if (!FIXWV_P(tobj->timew))
1808 time_memsize(
const void *tobj)
1817 (RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE),
1821 time_s_alloc(
VALUE klass)
1827 tobj->tzmode = TIME_TZMODE_UNINITIALIZED;
1829 tobj->timew = WINT2FIXWV(0);
1830 tobj->vtm.zone =
Qnil;
1836 get_timeval(
VALUE obj)
1840 if (!TIME_INIT_P(tobj)) {
1847 get_new_timeval(
VALUE obj)
1851 if (TIME_INIT_P(tobj)) {
1858 time_modify(
VALUE time)
1864 timenano2timew(time_t sec,
long nsec)
1868 timew = rb_time_magnify(TIMET2WV(sec));
1870 timew = wadd(timew, wmulquoll(WINT2WV(nsec), TIME_SCALE, 1000000000));
1875 timew2timespec(wideval_t timew)
1881 if (timew_out_of_timet_range(timew))
1883 split_second(timew, &timew2, &subsecx);
1884 ts.tv_sec = WV2TIMET(timew2);
1890 timew2timespec_exact(wideval_t timew,
struct timespec *ts)
1896 if (timew_out_of_timet_range(timew))
1898 split_second(timew, &timew2, &subsecx);
1899 ts->tv_sec = WV2TIMET(timew2);
1900 nsecv = mulquov(subsecx,
INT2FIX(1000000000),
INT2FIX(TIME_SCALE));
1910 #ifdef HAVE_CLOCK_GETTIME
1911 if (clock_gettime(CLOCK_REALTIME, ts) == -1) {
1917 if (gettimeofday(&tv, 0) < 0) {
1920 ts->tv_sec = tv.tv_sec;
1921 ts->tv_nsec = tv.tv_usec * 1000;
1933 GetNewTimeval(time, tobj);
1934 tobj->tzmode = TIME_TZMODE_LOCALTIME;
1936 tobj->timew = WINT2FIXWV(0);
1938 tobj->timew = timenano2timew(ts.tv_sec, ts.tv_nsec);
1941 time_zonelocal(time, zone);
1950 off = num_exact(off);
1953 GetTimeval(time, tobj);
1956 tobj->vtm.zone =
Qnil;
1957 TZMODE_SET_FIXOFF(tobj, off);
1963 vtm_add_offset(
struct vtm *
vtm,
VALUE off,
int sign)
1973 divmodv(off,
INT2FIX(1), &off, &subsec);
1974 divmodv(off,
INT2FIX(60), &off, &v);
1976 divmodv(off,
INT2FIX(60), &off, &v);
1978 divmodv(off,
INT2FIX(24), &off, &v);
1982 subsec = neg(subsec);
1991 vtm->subsecx = addv(
vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
2040 vtm_add_day(
vtm, day);
2044 vtm_add_day(
struct vtm *
vtm,
int day)
2048 if (
vtm->mon == 1 &&
vtm->mday == 1) {
2053 vtm->yday = leap_year_v_p(
vtm->year) ? 366 : 365;
2055 else if (
vtm->mday == 1) {
2056 const int8_t *days_in_month = days_in_month_in_v(
vtm->year);
2058 vtm->mday = days_in_month[
vtm->mon-1];
2059 if (
vtm->yday != 0)
vtm->yday--;
2063 if (
vtm->yday != 0)
vtm->yday--;
2065 if (
vtm->wday != VTM_WDAY_INITVAL)
vtm->wday = (
vtm->wday + 6) % 7;
2068 int leap = leap_year_v_p(
vtm->year);
2069 if (
vtm->mon == 12 &&
vtm->mday == 31) {
2075 else if (
vtm->mday == days_in_month_of(leap)[
vtm->mon-1]) {
2078 if (
vtm->yday != 0)
vtm->yday++;
2082 if (
vtm->yday != 0)
vtm->yday++;
2084 if (
vtm->wday != VTM_WDAY_INITVAL)
vtm->wday = (
vtm->wday + 1) % 7;
2090 maybe_tzobj_p(
VALUE obj)
2092 if (
NIL_P(obj))
return FALSE;
2098 NORETURN(
static void invalid_utc_offset(
VALUE));
2100 invalid_utc_offset(
VALUE zone)
2103 "\"A\"..\"I\",\"K\"..\"Z\" expected for utc_offset: %"PRIsVALUE,
2108 utc_offset_arg(
VALUE arg)
2113 const char *s =
RSTRING_PTR(tmp), *min = NULL, *sec = NULL;
2115 goto invalid_utc_offset;
2123 if (s[0] >=
'A' && s[0] <=
'I') {
2124 n = (int)s[0] -
'A' + 1;
2126 else if (s[0] >=
'K' && s[0] <=
'M') {
2127 n = (int)s[0] -
'A';
2129 else if (s[0] >=
'N' && s[0] <=
'Y') {
2130 n =
'M' - (int)s[0];
2133 goto invalid_utc_offset;
2157 goto invalid_utc_offset;
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);
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;
2170 if (s[0] !=
'+' && s[0] !=
'-')
goto invalid_utc_offset;
2172 n += (s[1] * 10 + s[2] -
'0' * 11) * 3600;
2174 if (n == 0)
return UTC_ZONE;
2180 return num_exact(arg);
2188 wideval_t tlocal, wideval_t tutc)
2191 wideval_t w = wsub(tlocal, tutc);
2193 validate_utc_offset(off);
2194 tobj->vtm.utc_offset = off;
2195 tobj->vtm.zone = zone;
2196 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2200 extract_time(
VALUE time)
2203 const ID id_to_i = idTo_i;
2205 #define EXTRACT_TIME() do { \
2206 t = v2w(rb_Integer(AREF(to_i))); \
2213 t = rb_time_unmagnify(tobj->timew);
2216 #define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2221 #define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2234 const ID id_to_i = idTo_i;
2236 #define EXTRACT_VTM() do { \
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))); \
2252 time_get_tm(time, tobj);
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));
2259 #define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2265 GMTIMEW(rb_time_magnify(t),
vtm);
2268 #define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2273 vtm->subsecx = subsecx;
2295 t = rb_time_unmagnify(tobj->timew);
2296 tm = tm_from_time(rb_cTimeTM, time);
2298 if (utc ==
Qundef)
return 0;
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));
2307 zone_set_dst(zone, tobj, tm);
2314 VALUE local, tm, subsecx;
2318 split_second(tobj->timew, &t, &subsecx);
2319 tm = tm_from_time(rb_cTimeTM, time);
2322 if (local ==
Qundef)
return 0;
2324 s = extract_vtm(local, &tobj->vtm, subsecx);
2326 zone_set_offset(zone, tobj, s, t);
2327 zone_set_dst(zone, tobj, tm);
2336 return rb_check_funcall_default(klass, id_find_timezone, 1, &zone,
Qnil);
2342 vtm_day_wraparound(
struct vtm *
vtm)
2344 if (
vtm->hour < 24)
return;
2349 vtm_add_day(
vtm, 1);
2359 vtm.wday = VTM_WDAY_INITVAL;
2361 vtm.zone = str_empty;
2363 vtm.year = obj2vint(year);
2365 vtm.mon =
NIL_P(mon) ? 1 : month_arg(mon);
2367 vtm.mday =
NIL_P(mday) ? 1 : obj2ubits(mday, 5);
2369 vtm.hour =
NIL_P(hour) ? 0 : obj2ubits(hour, 5);
2371 vtm.min =
NIL_P(min) ? 0 : obj2ubits(min, 6);
2379 vtm.sec = obj2subsecx(sec, &subsecx);
2380 vtm.subsecx = subsecx;
2383 vtm.isdst = VTM_ISDST_INITVAL;
2385 const VALUE arg = zone;
2392 else if (maybe_tzobj_p(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);
2403 GetNewTimeval(time, tobj);
2406 tobj->timew = timegmw(&
vtm);
2407 vtm_day_wraparound(&
vtm);
2410 TZMODE_SET_LOCALTIME(tobj);
2411 if (zone_timelocal(zone, time)) {
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);
2420 if (utc == UTC_ZONE) {
2421 tobj->timew = timegmw(&
vtm);
2423 vtm_day_wraparound(&
vtm);
2426 TZMODE_SET_UTC(tobj);
2430 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2432 tobj->timew = WINT2FIXWV(0);
2436 vtm_add_offset(&
vtm, off, -1);
2438 tobj->timew = timegmw(&
vtm);
2439 return time_set_utc_offset(time, off);
2442 tobj->timew = timelocalw(&
vtm);
2443 return time_localtime(time);
2448 subsec_normalize(time_t *secp,
long *subsecp,
const long maxsubsec)
2451 long subsec = *subsecp;
2454 if (UNLIKELY(subsec >= maxsubsec)) {
2455 sec2 = subsec / maxsubsec;
2456 if (TIMET_MAX - sec2 < sec) {
2459 subsec -= sec2 * maxsubsec;
2462 else if (UNLIKELY(subsec < 0)) {
2463 sec2 = NDIV(subsec, maxsubsec);
2464 if (sec < TIMET_MIN - sec2) {
2467 subsec -= sec2 * maxsubsec;
2470 #ifndef NEGATIVE_TIME_T
2478 #define time_usec_normalize(secp, usecp) subsec_normalize(secp, usecp, 1000000)
2479 #define time_nsec_normalize(secp, nsecp) subsec_normalize(secp, nsecp, 1000000000)
2482 nsec2timew(time_t sec,
long nsec)
2484 time_nsec_normalize(&sec, &nsec);
2485 return timenano2timew(sec, nsec);
2489 time_new_timew(
VALUE klass, wideval_t timew)
2491 VALUE time = time_s_alloc(klass);
2495 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2496 tobj->timew = timew;
2504 time_usec_normalize(&sec, &usec);
2505 return time_new_timew(
rb_cTime, timenano2timew(sec, usec * 1000));
2512 return time_new_timew(
rb_cTime, nsec2timew(sec, nsec));
2519 VALUE time = time_new_timew(
rb_cTime, nsec2timew(ts->tv_sec, ts->tv_nsec));
2521 if (-86400 < offset && offset < 86400) {
2522 GetTimeval(time, tobj);
2523 TZMODE_SET_FIXOFF(tobj,
INT2FIX(offset));
2525 else if (offset == INT_MAX) {
2527 else if (offset == INT_MAX-1) {
2528 GetTimeval(time, tobj);
2529 TZMODE_SET_UTC(tobj);
2541 VALUE time = time_new_timew(
rb_cTime, rb_time_magnify(v2w(timev)));
2546 if (maybe_tzobj_p(zone)) {
2548 if (zone_timelocal(zone, time))
return time;
2550 if (
NIL_P(off = utc_offset_arg(off))) {
2552 if (
NIL_P(zone = find_timezone(time, off))) invalid_utc_offset(off);
2554 if (!zone_timelocal(zone, time)) invalid_utc_offset(off);
2557 else if (off == UTC_ZONE) {
2558 return time_gmtime(time);
2561 validate_utc_offset(off);
2562 time_set_utc_offset(time, off);
2570 time_timespec(
VALUE num, int interval)
2573 const char *
const tstr = interval ?
"time interval" :
"time";
2576 #ifndef NEGATIVE_TIME_T
2577 # define arg_range_check(v) \
2579 rb_raise(rb_eArgError, "%s must not be negative", tstr) : \
2582 # define arg_range_check(v) \
2583 ((interval && (v) < 0) ? \
2584 rb_raise(rb_eArgError, "time interval must not be negative") : \
2589 t.tv_sec = NUM2TIMET(num);
2590 arg_range_check(t.tv_sec);
2601 t.tv_nsec = (int)(d*1e9+0.5);
2602 if (t.tv_nsec >= 1000000000) {
2603 t.tv_nsec -= 1000000000;
2607 else if ((t.tv_nsec = (
int)(-d*1e9+0.5)) > 0) {
2608 t.tv_nsec = 1000000000 - t.tv_nsec;
2611 t.tv_sec = (time_t)f;
2612 if (f != t.tv_sec) {
2617 else if (RB_BIGNUM_TYPE_P(num)) {
2618 t.tv_sec = NUM2TIMET(num);
2619 arg_range_check(t.tv_sec);
2628 t.tv_sec = NUM2TIMET(i);
2629 arg_range_check(t.tv_sec);
2639 #undef arg_range_check
2643 time_timeval(
VALUE num, int interval)
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);
2658 return time_timeval(num, TRUE);
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);
2675 return time_timeval(time, FALSE);
2684 if (IsTimeval(time)) {
2685 GetTimeval(time, tobj);
2686 t = timew2timespec(tobj->timew);
2689 return time_timespec(time, FALSE);
2695 return time_timespec(num, TRUE);
2699 get_scale(
VALUE unit)
2701 if (unit ==
ID2SYM(id_nanosecond) || unit ==
ID2SYM(id_nsec)) {
2704 else if (unit ==
ID2SYM(id_microsecond) || unit ==
ID2SYM(id_usec)) {
2707 else if (unit ==
ID2SYM(id_millisecond)) {
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);
2728 else if (IsTimeval(time)) {
2730 GetTimeval(time, tobj);
2731 t = time_new_timew(klass, tobj->timew);
2732 GetTimeval(t, tobj2);
2733 TZMODE_COPY(tobj2, tobj);
2736 timew = rb_time_magnify(v2w(num_exact(time)));
2737 t = time_new_timew(klass, timew);
2740 time_zonelocal(t, zone);
2752 static const char months[][4] = {
2753 "jan",
"feb",
"mar",
"apr",
"may",
"jun",
2754 "jul",
"aug",
"sep",
"oct",
"nov",
"dec",
2769 obj2ubits(
VALUE obj,
unsigned int bits)
2771 const unsigned int usable_mask = (1U << bits) - 1;
2772 unsigned int rv = (
unsigned int)obj2int(obj);
2774 if ((rv & usable_mask) != rv)
2776 return (uint32_t)rv;
2802 divmodv(num_exact(obj),
INT2FIX(1), &obj, &subsec);
2803 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2805 return obj2ubits(obj, 6);
2809 usec2subsecx(
VALUE obj)
2815 return mulquov(num_exact(obj),
INT2FIX(TIME_SCALE),
INT2FIX(1000000));
2819 month_arg(
VALUE arg)
2824 return obj2ubits(arg, 4);
2831 for (i=0; i<12; i++) {
2840 mon = obj2ubits(arg, 4);
2846 validate_utc_offset(
VALUE utc_offset)
2848 if (le(utc_offset,
INT2FIX(-86400)) || ge(utc_offset,
INT2FIX(86400)))
2854 validate_zone_name(
VALUE zone_name)
2861 validate_vtm(
struct vtm *
vtm)
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));
2873 if (!
NIL_P(
vtm->utc_offset)) validate_utc_offset(
vtm->utc_offset);
2874 #undef validate_vtm_range
2878 time_arg(
int argc,
const VALUE *argv,
struct vtm *
vtm)
2894 vtm->zone = str_empty;
2904 vtm->isdst =
RTEST(argv[8]) ? 1 : 0;
2907 rb_scan_args(argc, argv,
"17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
2910 vtm->wday = VTM_WDAY_INITVAL;
2911 vtm->isdst = VTM_ISDST_INITVAL;
2914 vtm->year = obj2vint(v[0]);
2920 vtm->mon = month_arg(v[1]);
2927 vtm->mday = obj2ubits(v[2], 5);
2935 unsigned int mday2 = leap_year_v_p(
vtm->year) ? 29 : 28;
2936 if (
vtm->mday > mday2) {
2946 if (
vtm->mday == 31) {
2953 vtm->hour =
NIL_P(v[3])?0:obj2ubits(v[3], 5);
2955 vtm->min =
NIL_P(v[4])?0:obj2ubits(v[4], 6);
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]);
2967 vtm->sec = obj2subsecx(v[5], &subsecx);
2970 vtm->subsecx = subsecx;
2982 unsigned long uy = (
unsigned long)(LIKELY(y >= 0) ? y : -y);
2984 if (LIKELY(uy % 4 != 0))
return 0;
2986 unsigned long century = uy / 100;
2987 if (LIKELY(uy != century * 100))
return 1;
2988 return century % 4 == 0;
2992 timegm_noleapsecond(
struct tm *tm)
2994 long tm_year = tm->tm_year;
2995 int tm_yday = calc_tm_yday(tm->tm_year, tm->tm_mon, tm->tm_mday);
3003 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
3007 DIV(tm_year-1,100) +
3008 DIV(tm_year+299,400))*86400;
3012 #define DEBUG_FIND_TIME_NUMGUESS
3013 #define DEBUG_GUESSRANGE
3016 static const bool debug_guessrange =
3017 #ifdef DEBUG_GUESSRANGE
3023 #define DEBUG_REPORT_GUESSRANGE \
3024 (debug_guessrange ? debug_report_guessrange(guess_lo, guess_hi) : (void)0)
3027 debug_report_guessrange(time_t guess_lo, time_t guess_hi)
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);
3035 static const bool debug_find_time_numguess =
3036 #ifdef DEBUG_FIND_TIME_NUMGUESS
3042 #define DEBUG_FIND_TIME_NUMGUESS_INC \
3043 (void)(debug_find_time_numguess && find_time_numguess++),
3044 static unsigned long long find_time_numguess;
3047 find_time_numguess_getter(
ID name,
VALUE *data)
3049 unsigned long long *numguess = (
void *)data;
3054 find_time_t(
struct tm *tptr,
int utc_p, time_t *tp)
3056 time_t guess, guess0, guess_lo, guess_hi;
3057 struct tm *tm, tm0, tm_lo, tm_hi;
3064 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
3066 guess_lo = TIMET_MIN;
3067 guess_hi = TIMET_MAX;
3069 find_dst = 0 < tptr->tm_isdst;
3075 if (tm0.tm_mon < 0) {
3082 else if (11 < tm0.tm_mon) {
3089 else if (tm0.tm_mday < 1) {
3095 else if ((d = days_in_month_in(1900 + tm0.tm_year)[tm0.tm_mon]) < tm0.tm_mday) {
3101 else if (tm0.tm_hour < 0) {
3106 else if (23 < tm0.tm_hour) {
3111 else if (tm0.tm_min < 0) {
3115 else if (59 < tm0.tm_min) {
3119 else if (tm0.tm_sec < 0) {
3122 else if (60 < tm0.tm_sec) {
3126 DEBUG_REPORT_GUESSRANGE;
3127 guess0 = guess = timegm_noleapsecond(&tm0);
3130 d = tmcmp(tptr, tm);
3131 if (d == 0) {
goto found; }
3134 guess -= 24 * 60 * 60;
3138 guess += 24 * 60 * 60;
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; }
3148 DEBUG_REPORT_GUESSRANGE;
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; }
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; }
3166 DEBUG_REPORT_GUESSRANGE;
3170 while (guess_lo + 1 < guess_hi) {
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;
3182 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
3183 guess = guess_hi - (guess0_hi - guess0);
3184 if (guess == guess_hi)
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)
3195 if (guess <= guess_lo || guess_hi <= guess) {
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);
3202 if (guess_hi <= guess) {
3203 fprintf(stderr,
"too big guess: %"PRI_TIMET_PREFIX
"d"\
3204 " <= %"PRI_TIMET_PREFIX
"d\n", guess_hi, guess);
3213 if (!tm)
goto error;
3215 d = tmcmp(tptr, tm);
3220 DEBUG_REPORT_GUESSRANGE;
3225 DEBUG_REPORT_GUESSRANGE;
3240 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
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) +
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));
3263 guess2 = guess - 2 * 60 * 60;
3264 tm = LOCALTIME(&guess2, result);
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) {
3288 guess2 = guess + 2 * 60 * 60;
3289 tm = LOCALTIME(&guess2, result);
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) {
3317 return "time out of range";
3320 return "gmtime/localtime error";
3324 vtmcmp(
struct vtm *a,
struct vtm *b)
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;
3345 tmcmp(
struct tm *a,
struct tm *b)
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;
3398 time_s_mkutc(
int argc,
VALUE *argv,
VALUE klass)
3402 time_arg(argc, argv, &
vtm);
3403 return time_gmtime(time_new_timew(klass, timegmw(&
vtm)));
3441 time_s_mktime(
int argc,
VALUE *argv,
VALUE klass)
3445 time_arg(argc, argv, &
vtm);
3446 return time_localtime(time_new_timew(klass, timelocalw(&
vtm)));
3464 time_to_i(
VALUE time)
3468 GetTimeval(time, tobj);
3469 return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE)));
3497 time_to_f(
VALUE time)
3501 GetTimeval(time, tobj);
3502 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3520 time_to_r(
VALUE time)
3525 GetTimeval(time, tobj);
3526 v = rb_time_unmagnify_to_rational(tobj->timew);
3554 time_usec(
VALUE time)
3559 GetTimeval(time, tobj);
3561 w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
3562 wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
3587 time_nsec(
VALUE time)
3591 GetTimeval(time, tobj);
3592 return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
3617 time_subsec(
VALUE time)
3621 GetTimeval(time, tobj);
3622 return quov(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))),
INT2FIX(TIME_SCALE));
3656 GetTimeval(time1, tobj1);
3657 if (IsTimeval(time2)) {
3658 GetTimeval(time2, tobj2);
3659 n = wcmp(tobj1->timew, tobj2->timew);
3662 return rb_invcmp(time1, time2);
3664 if (n == 0)
return INT2FIX(0);
3682 GetTimeval(time1, tobj1);
3683 if (IsTimeval(time2)) {
3684 GetTimeval(time2, tobj2);
3685 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3709 time_utc_p(
VALUE time)
3713 GetTimeval(time, tobj);
3714 return RBOOL(TZMODE_UTC_P(tobj));
3727 time_hash(
VALUE time)
3731 GetTimeval(time, tobj);
3732 return rb_hash(w2v(tobj->timew));
3742 GetTimeval(time, tobj);
3743 GetNewTimeval(copy, tcopy);
3750 time_dup(
VALUE time)
3753 time_init_copy(dup, time);
3758 time_localtime(
VALUE time)
3764 GetTimeval(time, tobj);
3765 if (TZMODE_LOCALTIME_P(tobj)) {
3773 zone = tobj->vtm.zone;
3774 if (maybe_tzobj_p(zone) && zone_localtime(zone, time)) {
3778 if (!localtimew(tobj->timew, &
vtm))
3783 TZMODE_SET_LOCALTIME(tobj);
3791 if (zone_localtime(zone, time))
return time;
3793 if (
NIL_P(off = utc_offset_arg(off))) {
3795 if (
NIL_P(zone = find_timezone(time, off))) invalid_utc_offset(off);
3796 if (!zone_localtime(zone, time)) invalid_utc_offset(off);
3799 else if (off == UTC_ZONE) {
3800 return time_gmtime(time);
3802 validate_utc_offset(off);
3804 time_set_utc_offset(time, off);
3805 return time_fixoff(time);
3832 time_localtime_m(
int argc,
VALUE *argv,
VALUE time)
3837 return time_zonelocal(time, off);
3840 return time_localtime(time);
3862 time_gmtime(
VALUE time)
3867 GetTimeval(time, tobj);
3868 if (TZMODE_UTC_P(tobj)) {
3877 GMTIMEW(tobj->timew, &
vtm);
3881 TZMODE_SET_UTC(tobj);
3886 time_fixoff(
VALUE time)
3892 GetTimeval(time, tobj);
3893 if (TZMODE_FIXOFF_P(tobj)) {
3901 if (TZMODE_FIXOFF_P(tobj))
3902 off = tobj->vtm.utc_offset;
3906 GMTIMEW(tobj->timew, &
vtm);
3908 zone = tobj->vtm.zone;
3910 tobj->vtm.zone = zone;
3911 vtm_add_offset(&tobj->vtm, off, +1);
3914 TZMODE_SET_FIXOFF(tobj, off);
3948 time_getlocaltime(
int argc,
VALUE *argv,
VALUE time)
3954 if (maybe_tzobj_p(zone)) {
3955 VALUE t = time_dup(time);
3956 if (zone_localtime(off, t))
return t;
3959 if (
NIL_P(off = utc_offset_arg(off))) {
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);
3966 else if (off == UTC_ZONE) {
3967 return time_gmtime(time_dup(time));
3969 validate_utc_offset(off);
3971 time = time_dup(time);
3972 time_set_utc_offset(time, off);
3973 return time_fixoff(time);
3976 return time_localtime(time_dup(time));
3994 time_getgmtime(
VALUE time)
3996 return time_gmtime(time_dup(time));
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);
4008 #define strftimev(fmt, time, enc) strftime_cstr((fmt), rb_strlen_lit(fmt), (time), (enc))
4022 time_asctime(
VALUE time)
4043 time_to_s(
VALUE time)
4047 GetTimeval(time, tobj);
4048 if (TZMODE_UTC_P(tobj))
4070 time_inspect(
VALUE time)
4075 GetTimeval(time, tobj);
4077 subsec = w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE)));
4089 subsec = quov(subsec,
INT2FIX(TIME_SCALE));
4092 if (TZMODE_UTC_P(tobj)) {
4098 char sign = (off < 0) ? (off = -off,
'-') :
'+';
4100 int min = (off /= 60) % 60;
4102 rb_str_catf(str,
" %c%.2d%.2d", sign, (
int)off, min);
4114 offset = num_exact(offset);
4116 result = time_new_timew(klass, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
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);
4128 return time_add0(
rb_cTime, tobj, torig, offset, sign);
4146 GetTimeval(time1, tobj);
4148 if (IsTimeval(time2)) {
4151 return time_add(tobj, time1, time2, 1);
4174 GetTimeval(time1, tobj);
4175 if (IsTimeval(time2)) {
4178 GetTimeval(time2, tobj2);
4179 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
4181 return time_add(tobj, time1, time2, -1);
4185 ndigits_denominator(
VALUE ndigits)
4229 time_round(
int argc,
VALUE *argv,
VALUE time)
4231 VALUE ndigits, v, den;
4237 den = ndigits_denominator(ndigits);
4239 GetTimeval(time, tobj);
4240 v = w2v(rb_time_unmagnify(tobj->timew));
4243 if (lt(v, quov(den,
INT2FIX(2))))
4244 return time_add(tobj, time, v, -1);
4246 return time_add(tobj, time, subv(den, v), 1);
4277 time_floor(
int argc,
VALUE *argv,
VALUE time)
4279 VALUE ndigits, v, den;
4285 den = ndigits_denominator(ndigits);
4287 GetTimeval(time, tobj);
4288 v = w2v(rb_time_unmagnify(tobj->timew));
4291 return time_add(tobj, time, v, -1);
4324 VALUE ndigits, v, den;
4330 den = ndigits_denominator(ndigits);
4332 GetTimeval(time, tobj);
4333 v = w2v(rb_time_unmagnify(tobj->timew));
4339 return time_add(tobj, time, v, 1);
4357 time_sec(
VALUE time)
4361 GetTimeval(time, tobj);
4362 MAKE_TM(time, tobj);
4363 return INT2FIX(tobj->vtm.sec);
4377 time_min(
VALUE time)
4381 GetTimeval(time, tobj);
4382 MAKE_TM(time, tobj);
4383 return INT2FIX(tobj->vtm.min);
4397 time_hour(
VALUE time)
4401 GetTimeval(time, tobj);
4402 MAKE_TM(time, tobj);
4403 return INT2FIX(tobj->vtm.hour);
4419 time_mday(
VALUE time)
4423 GetTimeval(time, tobj);
4424 MAKE_TM(time, tobj);
4425 return INT2FIX(tobj->vtm.mday);
4441 time_mon(
VALUE time)
4445 GetTimeval(time, tobj);
4446 MAKE_TM(time, tobj);
4447 return INT2FIX(tobj->vtm.mon);
4461 time_year(
VALUE time)
4465 GetTimeval(time, tobj);
4466 MAKE_TM(time, tobj);
4467 return tobj->vtm.year;
4489 time_wday(
VALUE time)
4493 GetTimeval(time, tobj);
4494 MAKE_TM_ENSURE(time, tobj, tobj->vtm.wday != VTM_WDAY_INITVAL);
4495 return INT2FIX((
int)tobj->vtm.wday);
4498 #define wday_p(n) {\
4499 return RBOOL(time_wday(time) == INT2FIX(n)); \
4513 time_sunday(
VALUE time)
4529 time_monday(
VALUE time)
4545 time_tuesday(
VALUE time)
4561 time_wednesday(
VALUE time)
4577 time_thursday(
VALUE time)
4593 time_friday(
VALUE time)
4609 time_saturday(
VALUE time)
4625 time_yday(
VALUE time)
4629 GetTimeval(time, tobj);
4630 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
4631 return INT2FIX(tobj->vtm.yday);
4660 time_isdst(
VALUE time)
4664 GetTimeval(time, tobj);
4665 MAKE_TM(time, tobj);
4666 if (tobj->vtm.isdst == VTM_ISDST_INITVAL) {
4669 return RBOOL(tobj->vtm.isdst);
4686 time_zone(
VALUE time)
4691 GetTimeval(time, tobj);
4692 MAKE_TM(time, tobj);
4694 if (TZMODE_UTC_P(tobj)) {
4697 zone = tobj->vtm.zone;
4726 GetTimeval(time, tobj);
4728 if (TZMODE_UTC_P(tobj)) {
4732 MAKE_TM(time, tobj);
4733 return tobj->vtm.utc_offset;
4755 time_to_a(
VALUE time)
4759 GetTimeval(time, tobj);
4760 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
4770 RBOOL(tobj->vtm.isdst),
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)
4781 if (!timew2timespec_exact(timew, &ts))
4782 timev = w2v(rb_time_unmagnify(timew));
4785 return rb_strftime_timespec(format, format_len, enc, time,
vtm, &ts, gmt);
4788 return rb_strftime(format, format_len, enc, time,
vtm, timev, gmt);
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));
5001 GetTimeval(time, tobj);
5002 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
5007 tmp = rb_str_tmp_frozen_acquire(format);
5012 rb_warning(
"strftime called with empty format string");
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);
5024 int ruby_marshal_write_long(
long x,
char *buf);
5026 enum {base_dump_size = 8};
5030 time_mdump(
VALUE time)
5034 char buf[base_dump_size +
sizeof(long) + 1];
5041 VALUE subsecx, nano, subnano, v, zone;
5044 const int max_year = 1900+0xffff;
5046 GetTimeval(time, tobj);
5048 gmtimew(tobj->timew, &
vtm);
5052 if (year > max_year) {
5053 year_extend =
INT2FIX(year - max_year);
5056 else if (year < 1900) {
5057 year_extend =
LONG2NUM(1900 - year);
5062 if (rb_int_positive_p(
vtm.year)) {
5063 year_extend = rb_int_minus(
vtm.year,
INT2FIX(max_year));
5067 year_extend = rb_int_minus(
INT2FIX(1900),
vtm.year);
5072 subsecx =
vtm.subsecx;
5074 nano = mulquov(subsecx,
INT2FIX(1000000000),
INT2FIX(TIME_SCALE));
5075 divmodv(nano,
INT2FIX(1), &v, &subnano);
5080 nano = addv(
LONG2FIX(nsec), subnano);
5083 TZMODE_UTC_P(tobj) << 30 |
5088 s = (
unsigned long)
vtm.min << 26 |
5092 for (i=0; i<4; i++) {
5093 buf[i] = (
unsigned char)p;
5096 for (i=4; i<8; i++) {
5097 buf[i] = (
unsigned char)s;
5101 if (!
NIL_P(year_extend)) {
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) {
5113 (year == 1900 ?
"small" :
"big"),
vtm.year);
5115 i += base_dump_size;
5128 rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
5129 rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
5145 int len = (int)
sizeof(buf);
5146 buf[1] = (char)((nsec % 10) << 4);
5148 buf[0] = (char)(nsec % 10);
5150 buf[0] |= (char)((nsec % 10) << 4);
5155 if (!TZMODE_UTC_P(tobj)) {
5157 divmodv(off,
INT2FIX(1), &div, &mod);
5162 zone = tobj->vtm.zone;
5163 if (maybe_tzobj_p(zone)) {
5177 str = time_mdump(time);
5183 mload_findzone(
VALUE arg)
5186 VALUE time = argp[0], zone = argp[1];
5187 return find_timezone(time, zone);
5197 if (
NIL_P(z))
return rb_fstring(zone);
5202 long ruby_marshal_read_long(
const char **buf,
long len);
5216 VALUE submicro, nano_num, nano_den, offset, zone, year;
5221 #define get_attr(attr, iffound) \
5222 attr = rb_attr_delete(str, id_##attr); \
5223 if (!NIL_P(attr)) { \
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)));
5241 goto invalid_format;
5245 for (i=0; i<4; i++) {
5246 p |= (
unsigned long)buf[i]<<(8*i);
5248 for (i=4; i<8; i++) {
5249 s |= (
unsigned long)buf[i]<<(8*(i-4));
5252 if ((p & (1UL<<31)) == 0) {
5258 timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
5262 gmt = (int)((p >> 30) & 0x1);
5265 year =
INT2FIX(((
int)(p >> 14) & 0xffff) + 1900);
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;
5277 year = rb_int_minus(year, year_extend);
5280 year = rb_int_plus(year, year_extend);
5283 unsigned int mon = ((int)(p >> 10) & 0xf);
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;
5297 vtm.zone = str_empty;
5299 usec = (long)(s & 0xfffff);
5304 if (nano_num !=
Qnil) {
5305 VALUE nano = quov(num_exact(nano_num), num_exact(nano_den));
5308 else if (submicro !=
Qnil) {
5316 if (10 <= (digit = ptr[0] >> 4))
goto end_submicro;
5317 nsec += digit * 100;
5318 if (10 <= (digit = ptr[0] & 0xf))
goto end_submicro;
5322 if (10 <= (digit = ptr[1] >> 4))
goto end_submicro;
5328 timew = timegmw(&
vtm);
5331 GetNewTimeval(time, tobj);
5332 tobj->tzmode = TIME_TZMODE_LOCALTIME;
5334 tobj->timew = timew;
5336 TZMODE_SET_UTC(tobj);
5338 else if (!
NIL_P(offset)) {
5339 time_set_utc_offset(time, offset);
5343 zone = mload_zone(time, zone);
5344 tobj->vtm.zone = zone;
5345 zone_localtime(zone, time);
5359 VALUE time = time_s_alloc(klass);
5361 time_mload(time, str);
5388 GetTimeval(time, tobj);
5389 tm = time_s_alloc(klass);
5392 GMTIMEW(ttm->timew = tobj->timew, v);
5393 ttm->timew = wsub(ttm->timew, v->subsecx);
5398 TZMODE_SET_UTC(ttm);
5404 GetTimeval(time, tobj);
5405 if (tobj->tm_got && TZMODE_UTC_P(tobj))
5408 GMTIMEW(tobj->timew, v = &
vtm);
5409 args[i++] = v->year;
5416 case 0: args[i++] =
Qfalse;
break;
5417 case 1: args[i++] =
Qtrue;
break;
5418 default: args[i++] =
Qnil;
break;
5420 args[i++] = w2v(rb_time_unmagnify(tobj->timew));
5434 tm_initialize(
int argc,
VALUE *argv,
VALUE tm)
5440 time_arg(argc, argv, &
vtm);
5445 tobj->tzmode = TIME_TZMODE_UTC;
5470 tm_to_time(
VALUE tm)
5480 const VALUE *p = RSTRUCT_CONST_PTR(tm);
5483 for (i = 0; i < numberof(t); ++i) {
5484 t[i] = p[numberof(t) - 1 - i];
5486 return time_s_mkutc(numberof(t), t,
rb_cTime);
5497 #define tm_subsec tm_zero
5498 #define tm_utc_offset tm_zero
5509 const VALUE *p = RSTRUCT_CONST_PTR(tm);
5511 return rb_sprintf(
"%.4"PRIsVALUE
"-%.2"PRIsVALUE
"-%.2"PRIsVALUE
" "
5512 "%.2"PRIsVALUE
":%.2"PRIsVALUE
":%.2"PRIsVALUE
" "
5514 p[5], p[4], p[3], p[2], p[1], p[0]);
5520 return time_add0(
rb_obj_class(tm), get_timeval(tm), tm, offset, +1);
5526 return time_add0(
rb_obj_class(tm), get_timeval(tm), tm, offset, -1);
5531 Init_tm(
VALUE outer,
const char *name)
5570 "sec",
"min",
"hour",
5571 "mday",
"mon",
"year",
5590 rb_time_zone_abbreviation(
VALUE zone,
VALUE time)
5592 VALUE tm, abbr, strftime_args[2];
5595 if (!
NIL_P(abbr))
return abbr;
5597 tm = tm_from_time(rb_cTimeTM, time);
5602 #ifdef SUPPORT_TZINFO_ZONE_ABBREVIATION
5609 strftime_args[0] = rb_fstring_lit(
"%Z");
5610 strftime_args[1] = tm;
5615 abbr = rb_check_funcall_default(zone, idName, 0, 0,
Qnil);
5655 str_utc = rb_fstring_lit(
"UTC");
5657 str_empty = rb_fstring_lit(
"");
5743 if (debug_find_time_numguess) {
5745 find_time_numguess_getter, NULL);
5748 rb_cTimeTM = Init_tm(
rb_cTime,
"tm");
5751 #include "timev.rbinc"
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
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.
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define T_NIL
Old name of RUBY_T_NIL.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define CLASS_OF
Old name of rb_class_of.
#define LONG2FIX
Old name of RB_INT2FIX.
#define FIX2INT
Old name of RB_FIX2INT.
#define ISDIGIT
Old name of rb_isdigit.
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define ISASCII
Old name of rb_isascii.
#define ULL2NUM
Old name of RB_ULL2NUM.
#define FIXNUM_MIN
Old name of RUBY_FIXNUM_MIN.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define NIL_P
Old name of RB_NIL_P.
#define DBL2NUM
Old name of rb_float_new.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Checks if the given object is of given kind.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
VALUE rb_eRangeError
RangeError exception.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eArgError
ArgumentError exception.
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.
void rb_warning(const char *fmt,...)
Issues a warning.
VALUE rb_cTime
Time class.
VALUE rb_Float(VALUE val)
This is the logic behind Kernel#Float.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_Integer(VALUE val)
This is the logic behind Kernel#Integer.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_mComparable
Comparable module.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
static bool rb_enc_str_asciicompat_p(VALUE str)
Queries if the passed string is in an ASCII-compatible encoding.
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.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
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.
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
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.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
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.
VALUE rb_big_minus(VALUE x, VALUE y)
Performs subtraction of the passed two objects.
VALUE rb_big_modulo(VALUE x, VALUE y)
Performs modulo of the passed two objects.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
Means either INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST, depending on the host processor'...
VALUE rb_big_plus(VALUE x, VALUE y)
Performs addition of the passed two objects.
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.
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.
VALUE rb_integer_unpack(const void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Import an integer from a buffer.
#define INTEGER_PACK_LITTLE_ENDIAN
Little endian combination.
VALUE rb_big_cmp(VALUE lhs, VALUE rhs)
Compares the passed two bignums.
VALUE rb_big_mul(VALUE x, VALUE y)
Performs multiplication of the passed two objects.
VALUE rb_big_div(VALUE x, VALUE y)
Performs division of the passed two objects.
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,...
#define rb_check_frozen
Just another name of rb_check_frozen.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
void rb_gc_mark(VALUE obj)
Marks an object.
VALUE rb_hash(VALUE obj)
Calculates a message authentication code of the passed object.
void rb_num_zerodiv(void)
Just always raises an exception.
VALUE rb_int_positive_pow(long x, unsigned long y)
Raises the passed x to the power of y.
VALUE rb_rational_new(VALUE num, VALUE den)
Constructs a Rational, with reduction.
#define rb_Rational1(x)
Shorthand of (x/1)r.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_usascii_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "US ASCII" encoding.
VALUE rb_usascii_str_new_cstr(const char *ptr)
Identical to rb_str_new_cstr(), except it generates a string of "US ASCII" encoding.
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
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.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
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...
VALUE rb_time_nano_new(time_t sec, long nsec)
Identical to rb_time_new(), except it accepts the time in nanoseconds resolution.
void rb_timespec_now(struct timespec *ts)
Fills the current time into the given struct.
VALUE rb_time_timespec_new(const struct timespec *ts, int offset)
Creates an instance of rb_cTime, with given time and offset.
struct timespec rb_time_timespec(VALUE time)
Identical to rb_time_timeval(), except for return type.
VALUE rb_time_new(time_t sec, long usec)
Creates an instance of rb_cTime with the given time and the local timezone.
struct timeval rb_time_timeval(VALUE time)
Converts an instance of rb_cTime to a struct timeval that represents the identical point of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
VALUE rb_time_num_new(VALUE timev, VALUE off)
Identical to rb_time_timespec_new(), except it takes Ruby values instead of C structs.
VALUE rb_time_utc_offset(VALUE time)
Queries the offset, in seconds between the time zone of the time and the UTC.
struct timespec rb_time_timespec_interval(VALUE num)
Identical to rb_time_interval(), except for return type.
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.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
void rb_alias(VALUE klass, ID dst, ID src)
Resembles alias.
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.
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().
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
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.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
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 ...
#define rb_long2int
Just another name of rb_long2int_inline.
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
void rb_copy_generic_ivar(VALUE clone, VALUE obj)
Copies the list of instance variables.
#define DATA_PTR(obj)
Convenient getter macro.
#define StringValue(v)
Ensures that the parameter object is a String.
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
static VALUE RSTRUCT_SET(VALUE st, int k, VALUE v)
Resembles Struct#[]=.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#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...
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool rb_integer_type_p(VALUE obj)
Queries if the object is an instance of rb_cInteger.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.