12#define _DEFAULT_SOURCE
14#include "ruby/internal/config.h"
30#if defined(HAVE_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"
48static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
49static ID id_nanosecond, id_microsecond, id_millisecond, id_nsec, id_usec;
50static ID id_local_to_utc, id_utc_to_local, id_find_timezone;
51static ID id_year, id_mon, id_mday, id_hour, id_min, id_sec, id_isdst;
52static VALUE str_utc, str_empty;
56#define id_divmod idDivmod
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)
101addv(VALUE x, VALUE y)
111subv(VALUE x, VALUE y)
121mulv(VALUE x, VALUE y)
124 return rb_fix_mul_fix(x, y);
126 if (RB_BIGNUM_TYPE_P(x))
132divv(VALUE x, VALUE y)
135 return rb_fix_div_fix(x, y);
137 if (RB_BIGNUM_TYPE_P(x))
143modv(VALUE x, VALUE y)
147 if (
FIXNUM_P(x))
return rb_fix_mod_fix(x, y);
153#define neg(x) (subv(INT2FIX(0), (x)))
156quor(VALUE x, VALUE y)
169 return rb_numeric_quo(x, y);
173quov(VALUE x, VALUE 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)))
186divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
192 rb_fix_divmod_fix(n, d, q, r);
199 rb_raise(rb_eTypeError,
"unexpected divmod result: into %"PRIsVALUE,
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)
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);
313static 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);
334weq(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));
347wcmp(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)
374wadd(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)));
386wsub(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)));
398wmul(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)));
410wquo(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
432wdivmod0(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) {
470wdivmod(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);
482wmuldivmod(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);
493wdiv(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)));
503wmod(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);
539 else if (!
NIL_P(tmp = rb_check_to_int(v))) {
545 rb_raise(rb_eTypeError,
"can't convert %"PRIsVALUE
" into an exact number",
553rb_time_magnify(wideval_t w)
555 return wmul(w, WINT2FIXWV(TIME_SCALE));
559rb_time_unmagnify_to_rational(wideval_t w)
561 return quor(w2v(w),
INT2FIX(TIME_SCALE));
565rb_time_unmagnify(wideval_t w)
567 return v2w(rb_time_unmagnify_to_rational(w));
571rb_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));
589 return rb_Float(quov(v,
INT2FIX(TIME_SCALE)));
591 return quov(v,
DBL2NUM(TIME_SCALE));
595split_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)
627#if WIDEVALUE_IS_WIDER
629 wideint_t wi = FIXWV2WINT(w);
630 if (TIMET_MIN == 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'");
637 if (wi < TIMET_MIN || TIMET_MAX < wi)
638 rb_raise(rb_eRangeError,
"too big to convert into `time_t'");
643 return NUM2TIMET(w2v(w));
645#define WV2TIMET(t) wv2timet(t)
648static VALUE rb_cTimeTM;
650static int obj2int(VALUE obj);
651static uint32_t obj2ubits(VALUE obj,
unsigned int bits);
652static VALUE obj2vint(VALUE obj);
653static uint32_t month_arg(VALUE arg);
654static VALUE validate_utc_offset(VALUE utc_offset);
655static VALUE validate_zone_name(VALUE zone_name);
656static void validate_vtm(
struct vtm *
vtm);
657static void vtm_add_day(
struct vtm *
vtm,
int day);
658static uint32_t obj2subsecx(VALUE obj, VALUE *subsecx);
660static VALUE time_gmtime(VALUE);
661static VALUE time_localtime(VALUE);
662static VALUE time_fixoff(VALUE);
663static VALUE time_zonelocal(VALUE time, VALUE off);
665static time_t timegm_noleapsecond(
struct tm *
tm);
666static int tmcmp(
struct tm *a,
struct tm *b);
667static int vtmcmp(
struct vtm *a,
struct vtm *b);
668static const char *find_time_t(
struct tm *tptr,
int utc_p, time_t *tp);
670static struct vtm *localtimew(wideval_t timew,
struct vtm *result);
672static int leap_year_p(
long y);
673#define leap_year_v_p(y) leap_year_p(NUM2LONG(modv((y), INT2FIX(400))))
675static VALUE tm_from_time(VALUE klass, VALUE time);
677bool ruby_tz_uptodate_p;
680ruby_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;
695rb_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
730rb_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))
748static 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
763static 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
779static const int8_t common_year_days_in_month[] = {
780 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
782static 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)
807static 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)
811static 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
838static const uint8_t common_year_mday_of_yday[] = {
840 D31, D28, D31, D30, D31, D30, D31, D31, D30, D31, D30, D31
842static const uint8_t leap_year_mday_of_yday[] = {
843 D31, D29, D31, D30, D31, D30, D31, D31, D30, D31, D30, D31
852calc_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];
866timegmw_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));
907zone_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);
934gmtimew_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;
1036gmtime_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);
1156static long this_year = 0;
1157static time_t known_leap_seconds_limit;
1158static int number_of_leap_seconds_known;
1161init_leap_second_info(
void)
1168 if (this_year == 0) {
1170 struct tm *
tm, result;
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))));
1208ruby_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);
1251 rb_raise(rb_eArgError,
"%s", errmsg);
1252 return wadd(rb_time_magnify(TIMET2WV(t)), v2w(
vtm->subsecx));
1256gmtimew(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"))
1310static struct tm *localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff, VALUE *zone);
1345static 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 },
1386static const int compat_leap_month_table[7] = {
1388 2032, 2016, 2028, 2012, 2024, 2036, 2020,
1392calc_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;
1406guess_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;
1498small_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;
1516timelocalw(
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))
1553 rb_raise(rb_eArgError,
"localtimew error");
1555 n = vtmcmp(
vtm, &vtm1);
1557 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(12*3600)));
1558 if (!localtimew(timew1, &vtm1))
1559 rb_raise(rb_eArgError,
"localtimew error");
1566 timew1 = wsub(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1567 if (!localtimew(timew1, &vtm1))
1568 rb_raise(rb_eArgError,
"localtimew error");
1571 timew2 = wadd(timew1, rb_time_magnify(WINT2FIXWV(24*3600)));
1572 if (!localtimew(timew2, &vtm2))
1573 rb_raise(rb_eArgError,
"localtimew error");
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))
1582 rb_raise(rb_eArgError,
"localtimew error");
1583 if (
vtm->hour != vtm1.hour ||
vtm->min != vtm1.min ||
vtm->sec != vtm1.sec)
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)
1592 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
1594 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
1598localtime_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);
1653timew_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))
1686localtimew(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)
1768static VALUE time_get_tm(VALUE,
struct time_object *);
1769#define MAKE_TM(time, tobj) \
1771 if ((tobj)->tm_got == 0) { \
1772 time_get_tm((time), (tobj)); \
1775#define MAKE_TM_ENSURE(time, tobj, cond) \
1777 MAKE_TM(time, tobj); \
1779 VALUE zone = (tobj)->vtm.zone; \
1780 if (!NIL_P(zone)) zone_localtime(zone, (time)); \
1788 if (!FIXWV_P(tobj->timew))
1797time_memsize(
const void *tobj)
1806 (RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE),
1810time_s_alloc(VALUE klass)
1816 tobj->tzmode = TIME_TZMODE_UNINITIALIZED;
1818 tobj->timew = WINT2FIXWV(0);
1819 tobj->vtm.zone =
Qnil;
1825get_timeval(VALUE obj)
1829 if (!TIME_INIT_P(tobj)) {
1830 rb_raise(rb_eTypeError,
"uninitialized %"PRIsVALUE, rb_obj_class(obj));
1836get_new_timeval(VALUE obj)
1840 if (TIME_INIT_P(tobj)) {
1841 rb_raise(rb_eTypeError,
"already initialized %"PRIsVALUE, rb_obj_class(obj));
1847time_modify(VALUE time)
1853timenano2timew(time_t sec,
long nsec)
1857 timew = rb_time_magnify(TIMET2WV(sec));
1859 timew = wadd(timew, wmulquoll(WINT2WV(nsec), TIME_SCALE, 1000000000));
1864timew2timespec(wideval_t timew)
1870 if (timew_out_of_timet_range(timew))
1871 rb_raise(rb_eArgError,
"time out of system range");
1872 split_second(timew, &timew2, &subsecx);
1873 ts.tv_sec = WV2TIMET(timew2);
1879timew2timespec_exact(wideval_t timew,
struct timespec *ts)
1885 if (timew_out_of_timet_range(timew))
1887 split_second(timew, &timew2, &subsecx);
1888 ts->tv_sec = WV2TIMET(timew2);
1889 nsecv = mulquov(subsecx,
INT2FIX(1000000000),
INT2FIX(TIME_SCALE));
1899#ifdef HAVE_CLOCK_GETTIME
1900 if (clock_gettime(CLOCK_REALTIME, ts) == -1) {
1906 if (gettimeofday(&tv, 0) < 0) {
1909 ts->tv_sec = tv.tv_sec;
1910 ts->tv_nsec = tv.tv_usec * 1000;
1922 GetNewTimeval(time, tobj);
1923 tobj->tzmode = TIME_TZMODE_LOCALTIME;
1925 tobj->timew = WINT2FIXWV(0);
1927 tobj->timew = timenano2timew(ts.tv_sec, ts.tv_nsec);
1930 time_zonelocal(time, zone);
1936time_set_utc_offset(VALUE time, VALUE off)
1939 off = num_exact(off);
1942 GetTimeval(time, tobj);
1945 tobj->vtm.zone =
Qnil;
1946 TZMODE_SET_FIXOFF(tobj, off);
1952vtm_add_offset(
struct vtm *
vtm, VALUE off,
int sign)
1962 divmodv(off,
INT2FIX(1), &off, &subsec);
1963 divmodv(off,
INT2FIX(60), &off, &v);
1965 divmodv(off,
INT2FIX(60), &off, &v);
1967 divmodv(off,
INT2FIX(24), &off, &v);
1971 subsec = neg(subsec);
1979 if (!rb_equal(subsec,
INT2FIX(0))) {
1980 vtm->subsecx = addv(
vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
2029 vtm_add_day(
vtm, day);
2033vtm_add_day(
struct vtm *
vtm,
int day)
2037 if (
vtm->mon == 1 &&
vtm->mday == 1) {
2041 vtm->yday = leap_year_v_p(
vtm->year) ? 366 : 365;
2043 else if (
vtm->mday == 1) {
2044 const int8_t *days_in_month = days_in_month_in_v(
vtm->year);
2046 vtm->mday = days_in_month[
vtm->mon-1];
2053 vtm->wday = (
vtm->wday + 6) % 7;
2056 int leap = leap_year_v_p(
vtm->year);
2057 if (
vtm->mon == 12 &&
vtm->mday == 31) {
2063 else if (
vtm->mday == days_in_month_of(leap)[
vtm->mon-1]) {
2072 vtm->wday = (
vtm->wday + 1) % 7;
2078maybe_tzobj_p(VALUE obj)
2080 if (
NIL_P(obj))
return FALSE;
2086NORETURN(
static void invalid_utc_offset(VALUE));
2088invalid_utc_offset(VALUE zone)
2090 rb_raise(rb_eArgError,
"\"+HH:MM\", \"-HH:MM\", \"UTC\" or "
2091 "\"A\"..\"I\",\"K\"..\"Z\" expected for utc_offset: %"PRIsVALUE,
2096utc_offset_arg(VALUE arg)
2101 const char *s =
RSTRING_PTR(tmp), *min = NULL, *sec = NULL;
2103 goto invalid_utc_offset;
2111 if (s[0] >=
'A' && s[0] <=
'I') {
2112 n = (int)s[0] -
'A' + 1;
2114 else if (s[0] >=
'K' && s[0] <=
'M') {
2115 n = (int)s[0] -
'A';
2117 else if (s[0] >=
'N' && s[0] <=
'Y') {
2118 n =
'M' - (int)s[0];
2121 goto invalid_utc_offset;
2145 goto invalid_utc_offset;
2148 if (sec == s+7 && *(sec-1) !=
':')
goto invalid_utc_offset;
2149 if (!
ISDIGIT(sec[0]) || !
ISDIGIT(sec[1]))
goto invalid_utc_offset;
2150 n += (sec[0] * 10 + sec[1] -
'0' * 11);
2153 if (min == s+4 && *(min-1) !=
':')
goto invalid_utc_offset;
2154 if (!
ISDIGIT(min[0]) || !
ISDIGIT(min[1]))
goto invalid_utc_offset;
2155 if (min[0] >
'5')
goto invalid_utc_offset;
2156 n += (min[0] * 10 + min[1] -
'0' * 11) * 60;
2158 if (s[0] !=
'+' && s[0] !=
'-')
goto invalid_utc_offset;
2160 n += (s[1] * 10 + s[2] -
'0' * 11) * 3600;
2162 if (n == 0)
return UTC_ZONE;
2168 return num_exact(arg);
2175zone_set_offset(VALUE zone,
struct time_object *tobj,
2176 wideval_t tlocal, wideval_t tutc)
2179 wideval_t w = wsub(tlocal, tutc);
2181 validate_utc_offset(off);
2182 tobj->vtm.utc_offset = off;
2183 tobj->vtm.zone = zone;
2184 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2188extract_time(VALUE time)
2191 const ID id_to_i = idTo_i;
2193#define EXTRACT_TIME() do { \
2194 t = v2w(rb_Integer(AREF(to_i))); \
2197 if (rb_typeddata_is_kind_of(time, &time_data_type)) {
2201 t = rb_time_unmagnify(tobj->timew);
2204#define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2209#define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2219extract_vtm(VALUE time,
struct vtm *
vtm, VALUE subsecx)
2222 const ID id_to_i = idTo_i;
2224#define EXTRACT_VTM() do { \
2226 vtm->year = obj2vint(AREF(year)); \
2227 vtm->mon = month_arg(AREF(mon)); \
2228 vtm->mday = obj2ubits(AREF(mday), 5); \
2229 vtm->hour = obj2ubits(AREF(hour), 5); \
2230 vtm->min = obj2ubits(AREF(min), 6); \
2231 vtm->sec = obj2subsecx(AREF(sec), &subsecx); \
2232 vtm->isdst = RTEST(AREF(isdst)); \
2233 vtm->utc_offset = Qnil; \
2234 t = v2w(rb_Integer(AREF(to_i))); \
2237 if (rb_typeddata_is_kind_of(time, &time_data_type)) {
2240 time_get_tm(time, tobj);
2242 t = rb_time_unmagnify(tobj->timew);
2243 if (TZMODE_FIXOFF_P(tobj) &&
vtm->utc_offset !=
INT2FIX(0))
2244 t = wadd(t, v2w(
vtm->utc_offset));
2247#define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2253 GMTIMEW(rb_time_magnify(t),
vtm);
2256#define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2261 vtm->subsecx = subsecx;
2277zone_timelocal(VALUE zone, VALUE time)
2283 t = rb_time_unmagnify(tobj->timew);
2284 tm = tm_from_time(rb_cTimeTM, time);
2286 if (utc ==
Qundef)
return 0;
2288 s = extract_time(utc);
2289 zone_set_offset(zone, tobj, t, s);
2290 s = rb_time_magnify(s);
2291 if (tobj->vtm.subsecx !=
INT2FIX(0)) {
2292 s = wadd(s, v2w(tobj->vtm.subsecx));
2295 zone_set_dst(zone, tobj,
tm);
2300zone_localtime(VALUE zone, VALUE time)
2302 VALUE local,
tm, subsecx;
2306 split_second(tobj->timew, &t, &subsecx);
2307 tm = tm_from_time(rb_cTimeTM, time);
2310 if (local ==
Qundef)
return 0;
2312 s = extract_vtm(local, &tobj->vtm, subsecx);
2314 zone_set_offset(zone, tobj, s, t);
2315 zone_set_dst(zone, tobj,
tm);
2320find_timezone(VALUE time, VALUE zone)
2324 return rb_check_funcall_default(klass, id_find_timezone, 1, &zone,
Qnil);
2330vtm_day_wraparound(
struct vtm *
vtm)
2332 if (
vtm->hour < 24)
return;
2337 vtm_add_day(
vtm, 1);
2341time_init_args(
rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VALUE mday, VALUE hour, VALUE min, VALUE sec, VALUE zone)
2347 vtm.wday = VTM_WDAY_INITVAL;
2349 vtm.zone = str_empty;
2351 vtm.year = obj2vint(year);
2353 vtm.mon =
NIL_P(mon) ? 1 : month_arg(mon);
2355 vtm.mday =
NIL_P(mday) ? 1 : obj2ubits(mday, 5);
2357 vtm.hour =
NIL_P(hour) ? 0 : obj2ubits(hour, 5);
2359 vtm.min =
NIL_P(min) ? 0 : obj2ubits(min, 6);
2367 vtm.sec = obj2subsecx(sec, &subsecx);
2368 vtm.subsecx = subsecx;
2371 vtm.isdst = VTM_ISDST_INITVAL;
2373 const VALUE arg = zone;
2380 else if (maybe_tzobj_p(arg))
2382 else if (!
NIL_P(utc = utc_offset_arg(arg)))
2383 vtm.utc_offset = utc == UTC_ZONE ?
INT2FIX(0) : utc;
2384 else if (
NIL_P(zone = find_timezone(time, arg)))
2385 invalid_utc_offset(arg);
2391 GetNewTimeval(time, tobj);
2394 tobj->timew = timegmw(&
vtm);
2395 vtm_day_wraparound(&
vtm);
2398 TZMODE_SET_LOCALTIME(tobj);
2399 if (zone_timelocal(zone, time)) {
2402 else if (
NIL_P(
vtm.utc_offset = utc_offset_arg(zone))) {
2403 if (
NIL_P(zone = find_timezone(time, zone)) || !zone_timelocal(zone, time))
2404 invalid_utc_offset(arg);
2408 if (utc == UTC_ZONE) {
2409 tobj->timew = timegmw(&
vtm);
2410 vtm_day_wraparound(&
vtm);
2413 TZMODE_SET_UTC(tobj);
2417 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2419 tobj->timew = WINT2FIXWV(0);
2422 VALUE off =
vtm.utc_offset;
2423 vtm_add_offset(&
vtm, off, -1);
2425 tobj->timew = timegmw(&
vtm);
2426 return time_set_utc_offset(time, off);
2429 tobj->timew = timelocalw(&
vtm);
2430 return time_localtime(time);
2435subsec_normalize(time_t *secp,
long *subsecp,
const long maxsubsec)
2438 long subsec = *subsecp;
2441 if (UNLIKELY(subsec >= maxsubsec)) {
2442 sec2 = subsec / maxsubsec;
2443 if (TIMET_MAX - sec2 < sec) {
2444 rb_raise(rb_eRangeError,
"out of Time range");
2446 subsec -= sec2 * maxsubsec;
2449 else if (UNLIKELY(subsec < 0)) {
2450 sec2 = NDIV(subsec, maxsubsec);
2451 if (sec < TIMET_MIN - sec2) {
2452 rb_raise(rb_eRangeError,
"out of Time range");
2454 subsec -= sec2 * maxsubsec;
2457#ifndef NEGATIVE_TIME_T
2459 rb_raise(rb_eArgError,
"time must be positive");
2465#define time_usec_normalize(secp, usecp) subsec_normalize(secp, usecp, 1000000)
2466#define time_nsec_normalize(secp, nsecp) subsec_normalize(secp, nsecp, 1000000000)
2469nsec2timew(time_t sec,
long nsec)
2471 time_nsec_normalize(&sec, &nsec);
2472 return timenano2timew(sec, nsec);
2476time_new_timew(VALUE klass, wideval_t timew)
2478 VALUE time = time_s_alloc(klass);
2482 tobj->tzmode = TIME_TZMODE_LOCALTIME;
2483 tobj->timew = timew;
2491 time_usec_normalize(&sec, &usec);
2492 return time_new_timew(
rb_cTime, timenano2timew(sec, usec * 1000));
2499 return time_new_timew(
rb_cTime, nsec2timew(sec, nsec));
2506 VALUE time = time_new_timew(
rb_cTime, nsec2timew(ts->tv_sec, ts->tv_nsec));
2508 if (-86400 < offset && offset < 86400) {
2509 GetTimeval(time, tobj);
2510 TZMODE_SET_FIXOFF(tobj,
INT2FIX(offset));
2512 else if (offset == INT_MAX) {
2514 else if (offset == INT_MAX-1) {
2515 GetTimeval(time, tobj);
2516 TZMODE_SET_UTC(tobj);
2519 rb_raise(rb_eArgError,
"utc_offset out of range");
2528 VALUE time = time_new_timew(
rb_cTime, rb_time_magnify(v2w(timev)));
2533 if (maybe_tzobj_p(zone)) {
2535 if (zone_timelocal(zone, time))
return time;
2537 if (
NIL_P(off = utc_offset_arg(off))) {
2539 if (
NIL_P(zone = find_timezone(time, off))) invalid_utc_offset(off);
2541 if (!zone_timelocal(zone, time)) invalid_utc_offset(off);
2544 else if (off == UTC_ZONE) {
2545 return time_gmtime(time);
2548 validate_utc_offset(off);
2549 time_set_utc_offset(time, off);
2557time_timespec(VALUE num, int interval)
2560 const char *
const tstr = interval ?
"time interval" :
"time";
2563#ifndef NEGATIVE_TIME_T
2564# define arg_range_check(v) \
2566 rb_raise(rb_eArgError, "%s must not be negative", tstr) : \
2569# define arg_range_check(v) \
2570 ((interval && (v) < 0) ? \
2571 rb_raise(rb_eArgError, "time interval must not be negative") : \
2576 t.tv_sec = NUM2TIMET(num);
2577 arg_range_check(t.tv_sec);
2588 t.tv_nsec = (int)(d*1e9+0.5);
2589 if (t.tv_nsec >= 1000000000) {
2590 t.tv_nsec -= 1000000000;
2594 else if ((t.tv_nsec = (
int)(-d*1e9+0.5)) > 0) {
2595 t.tv_nsec = 1000000000 - t.tv_nsec;
2598 t.tv_sec = (time_t)f;
2599 if (f != t.tv_sec) {
2600 rb_raise(rb_eRangeError,
"%f out of Time range", x);
2604 else if (RB_BIGNUM_TYPE_P(num)) {
2605 t.tv_sec = NUM2TIMET(num);
2606 arg_range_check(t.tv_sec);
2615 t.tv_sec = NUM2TIMET(i);
2616 arg_range_check(t.tv_sec);
2621 rb_raise(rb_eTypeError,
"can't convert %"PRIsVALUE
" into %s",
2622 rb_obj_class(num), tstr);
2626#undef arg_range_check
2630time_timeval(VALUE num, int interval)
2635 ts = time_timespec(num, interval);
2636 tv.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
2637 tv.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
2645 return time_timeval(num, TRUE);
2655 if (IsTimeval(time)) {
2656 GetTimeval(time, tobj);
2657 ts = timew2timespec(tobj->timew);
2658 t.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
2659 t.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
2662 return time_timeval(time, FALSE);
2671 if (IsTimeval(time)) {
2672 GetTimeval(time, tobj);
2673 t = timew2timespec(tobj->timew);
2676 return time_timespec(time, FALSE);
2682 return time_timespec(num, TRUE);
2686get_scale(VALUE unit)
2688 if (unit ==
ID2SYM(id_nanosecond) || unit ==
ID2SYM(id_nsec)) {
2691 else if (unit ==
ID2SYM(id_microsecond) || unit ==
ID2SYM(id_usec)) {
2694 else if (unit ==
ID2SYM(id_millisecond)) {
2698 rb_raise(rb_eArgError,
"unexpected unit: %"PRIsVALUE, unit);
2709 int scale = get_scale(unit);
2710 time = num_exact(time);
2711 t = num_exact(subsec);
2712 timew = wadd(rb_time_magnify(v2w(time)), wmulquoll(v2w(t), TIME_SCALE, scale));
2713 t = time_new_timew(klass, timew);
2715 else if (IsTimeval(time)) {
2717 GetTimeval(time, tobj);
2718 t = time_new_timew(klass, tobj->timew);
2719 GetTimeval(t, tobj2);
2720 TZMODE_COPY(tobj2, tobj);
2723 timew = rb_time_magnify(v2w(num_exact(time)));
2724 t = time_new_timew(klass, timew);
2727 time_zonelocal(t, zone);
2739static const char months[][4] = {
2740 "jan",
"feb",
"mar",
"apr",
"may",
"jun",
2741 "jul",
"aug",
"sep",
"oct",
"nov",
"dec",
2756obj2ubits(VALUE obj,
unsigned int bits)
2758 const unsigned int usable_mask = (1U << bits) - 1;
2759 unsigned int rv = (
unsigned int)obj2int(obj);
2761 if ((rv & usable_mask) != rv)
2762 rb_raise(rb_eArgError,
"argument out of range");
2763 return (uint32_t)rv;
2773 obj = rb_to_int(obj);
2780obj2subsecx(VALUE obj, VALUE *subsecx)
2789 divmodv(num_exact(obj),
INT2FIX(1), &obj, &subsec);
2790 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2792 return obj2ubits(obj, 6);
2796usec2subsecx(VALUE obj)
2802 return mulquov(num_exact(obj),
INT2FIX(TIME_SCALE),
INT2FIX(1000000));
2811 return obj2ubits(arg, 4);
2818 for (i=0; i<12; i++) {
2827 mon = obj2ubits(arg, 4);
2833validate_utc_offset(VALUE utc_offset)
2835 if (le(utc_offset,
INT2FIX(-86400)) || ge(utc_offset,
INT2FIX(86400)))
2836 rb_raise(rb_eArgError,
"utc_offset out of range");
2841validate_zone_name(VALUE zone_name)
2848validate_vtm(
struct vtm *
vtm)
2850#define validate_vtm_range(mem, b, e) \
2851 ((vtm->mem < b || vtm->mem > e) ? \
2852 rb_raise(rb_eArgError, #mem" out of range") : (void)0)
2853 validate_vtm_range(mon, 1, 12);
2854 validate_vtm_range(mday, 1, 31);
2855 validate_vtm_range(hour, 0, 24);
2856 validate_vtm_range(min, 0, (
vtm->hour == 24 ? 0 : 59));
2857 validate_vtm_range(sec, 0, (
vtm->hour == 24 ? 0 : 60));
2859 rb_raise(rb_eArgError,
"subsecx out of range");
2860 if (!
NIL_P(
vtm->utc_offset)) validate_utc_offset(
vtm->utc_offset);
2861#undef validate_vtm_range
2865time_arg(
int argc,
const VALUE *argv,
struct vtm *
vtm)
2881 vtm->zone = str_empty;
2891 vtm->isdst =
RTEST(argv[8]) ? 1 : 0;
2894 rb_scan_args(argc, argv,
"17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
2897 vtm->wday = VTM_WDAY_INITVAL;
2898 vtm->isdst = VTM_ISDST_INITVAL;
2901 vtm->year = obj2vint(v[0]);
2907 vtm->mon = month_arg(v[1]);
2914 vtm->mday = obj2ubits(v[2], 5);
2922 unsigned int mday2 = leap_year_v_p(
vtm->year) ? 29 : 28;
2923 if (
vtm->mday > mday2) {
2933 if (
vtm->mday == 31) {
2940 vtm->hour =
NIL_P(v[3])?0:obj2ubits(v[3], 5);
2942 vtm->min =
NIL_P(v[4])?0:obj2ubits(v[4], 6);
2944 if (!
NIL_P(v[6]) && argc == 7) {
2945 vtm->sec =
NIL_P(v[5])?0:obj2ubits(v[5],6);
2946 subsecx = usec2subsecx(v[6]);
2954 vtm->sec = obj2subsecx(v[5], &subsecx);
2957 vtm->subsecx = subsecx;
2969 unsigned long uy = (
unsigned long)(LIKELY(y >= 0) ? y : -y);
2971 if (LIKELY(uy % 4 != 0))
return 0;
2973 unsigned long century = uy / 100;
2974 if (LIKELY(uy != century * 100))
return 1;
2975 return century % 4 == 0;
2979timegm_noleapsecond(
struct tm *
tm)
2981 long tm_year =
tm->tm_year;
2982 int tm_yday = calc_tm_yday(
tm->tm_year,
tm->tm_mon,
tm->tm_mday);
2990 return tm->tm_sec +
tm->tm_min*60 +
tm->tm_hour*3600 +
2994 DIV(tm_year-1,100) +
2995 DIV(tm_year+299,400))*86400;
2999#define DEBUG_FIND_TIME_NUMGUESS
3000#define DEBUG_GUESSRANGE
3003static const bool debug_guessrange =
3004#ifdef DEBUG_GUESSRANGE
3010#define DEBUG_REPORT_GUESSRANGE \
3011 (debug_guessrange ? debug_report_guessrange(guess_lo, guess_hi) : (void)0)
3014debug_report_guessrange(time_t guess_lo, time_t guess_hi)
3016 unsigned_time_t guess_diff = (unsigned_time_t)(guess_hi-guess_lo);
3017 fprintf(stderr,
"find time guess range: %"PRI_TIMET_PREFIX
"d - "
3018 "%"PRI_TIMET_PREFIX
"d : %"PRI_TIMET_PREFIX
"u\n",
3019 guess_lo, guess_hi, guess_diff);
3022static const bool debug_find_time_numguess =
3023#ifdef DEBUG_FIND_TIME_NUMGUESS
3029#define DEBUG_FIND_TIME_NUMGUESS_INC \
3030 (void)(debug_find_time_numguess && find_time_numguess++),
3031static unsigned long long find_time_numguess;
3034find_time_numguess_getter(ID name, VALUE *data)
3036 unsigned long long *numguess = (
void *)data;
3041find_time_t(
struct tm *tptr,
int utc_p, time_t *tp)
3043 time_t guess, guess0, guess_lo, guess_hi;
3044 struct tm *
tm, tm0, tm_lo, tm_hi;
3051#define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
3053 guess_lo = TIMET_MIN;
3054 guess_hi = TIMET_MAX;
3056 find_dst = 0 < tptr->tm_isdst;
3062 if (tm0.tm_mon < 0) {
3069 else if (11 < tm0.tm_mon) {
3076 else if (tm0.tm_mday < 1) {
3082 else if ((d = days_in_month_in(1900 + tm0.tm_year)[tm0.tm_mon]) < tm0.tm_mday) {
3088 else if (tm0.tm_hour < 0) {
3093 else if (23 < tm0.tm_hour) {
3098 else if (tm0.tm_min < 0) {
3102 else if (59 < tm0.tm_min) {
3106 else if (tm0.tm_sec < 0) {
3109 else if (60 < tm0.tm_sec) {
3113 DEBUG_REPORT_GUESSRANGE;
3114 guess0 = guess = timegm_noleapsecond(&tm0);
3117 d = tmcmp(tptr,
tm);
3118 if (d == 0) {
goto found; }
3121 guess -= 24 * 60 * 60;
3125 guess += 24 * 60 * 60;
3127 DEBUG_REPORT_GUESSRANGE;
3128 if (guess_lo < guess && guess < guess_hi && (
tm = GUESS(&guess)) != NULL) {
3129 d = tmcmp(tptr,
tm);
3130 if (d == 0) {
goto found; }
3135 DEBUG_REPORT_GUESSRANGE;
3139 tm = GUESS(&guess_lo);
3140 if (!
tm)
goto error;
3141 d = tmcmp(tptr,
tm);
3142 if (d < 0)
goto out_of_range;
3143 if (d == 0) { guess = guess_lo;
goto found; }
3146 tm = GUESS(&guess_hi);
3147 if (!
tm)
goto error;
3148 d = tmcmp(tptr,
tm);
3149 if (d > 0)
goto out_of_range;
3150 if (d == 0) { guess = guess_hi;
goto found; }
3153 DEBUG_REPORT_GUESSRANGE;
3157 while (guess_lo + 1 < guess_hi) {
3160 guess = guess_lo / 2 + guess_hi / 2;
3161 if (guess <= guess_lo)
3162 guess = guess_lo + 1;
3163 else if (guess >= guess_hi)
3164 guess = guess_hi - 1;
3169 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
3170 guess = guess_hi - (guess0_hi - guess0);
3171 if (guess == guess_hi)
3175 else if (status == 2) {
3176 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
3177 guess = guess_lo + (guess0 - guess0_lo);
3178 if (guess == guess_lo)
3182 if (guess <= guess_lo || guess_hi <= guess) {
3184 if (debug_guessrange) {
3185 if (guess <= guess_lo) {
3186 fprintf(stderr,
"too small guess: %"PRI_TIMET_PREFIX
"d"\
3187 " <= %"PRI_TIMET_PREFIX
"d\n", guess, guess_lo);
3189 if (guess_hi <= guess) {
3190 fprintf(stderr,
"too big guess: %"PRI_TIMET_PREFIX
"d"\
3191 " <= %"PRI_TIMET_PREFIX
"d\n", guess_hi, guess);
3200 if (!
tm)
goto error;
3202 d = tmcmp(tptr,
tm);
3207 DEBUG_REPORT_GUESSRANGE;
3212 DEBUG_REPORT_GUESSRANGE;
3227 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
3230 ((tptr->tm_year - tm_lo.tm_year) * 365 +
3231 DIV((tptr->tm_year-69), 4) -
3232 DIV((tptr->tm_year-1), 100) +
3233 DIV((tptr->tm_year+299), 400) -
3234 DIV((tm_lo.tm_year-69), 4) +
3235 DIV((tm_lo.tm_year-1), 100) -
3236 DIV((tm_lo.tm_year+299), 400) +
3238 tm_lo.tm_yday) * 86400 +
3239 (tptr->tm_hour - tm_lo.tm_hour) * 3600 +
3240 (tptr->tm_min - tm_lo.tm_min) * 60 +
3241 (tptr->tm_sec - (tm_lo.tm_sec == 60 ? 59 : tm_lo.tm_sec));
3250 guess2 = guess - 2 * 60 * 60;
3251 tm = LOCALTIME(&guess2, result);
3253 if (tptr->tm_hour != (
tm->tm_hour + 2) % 24 ||
3254 tptr->tm_min !=
tm->tm_min ||
3255 tptr->tm_sec !=
tm->tm_sec) {
3256 guess2 -= (
tm->tm_hour - tptr->tm_hour) * 60 * 60 +
3257 (
tm->tm_min - tptr->tm_min) * 60 +
3258 (
tm->tm_sec - tptr->tm_sec);
3259 if (tptr->tm_mday !=
tm->tm_mday)
3260 guess2 += 24 * 60 * 60;
3261 if (guess != guess2) {
3262 tm = LOCALTIME(&guess2, result);
3263 if (
tm && tmcmp(tptr,
tm) == 0) {
3275 guess2 = guess + 2 * 60 * 60;
3276 tm = LOCALTIME(&guess2, result);
3278 if ((tptr->tm_hour + 2) % 24 !=
tm->tm_hour ||
3279 tptr->tm_min !=
tm->tm_min ||
3280 tptr->tm_sec !=
tm->tm_sec) {
3281 guess2 -= (
tm->tm_hour - tptr->tm_hour) * 60 * 60 +
3282 (
tm->tm_min - tptr->tm_min) * 60 +
3283 (
tm->tm_sec - tptr->tm_sec);
3284 if (tptr->tm_mday !=
tm->tm_mday)
3285 guess2 -= 24 * 60 * 60;
3286 if (guess != guess2) {
3287 tm = LOCALTIME(&guess2, result);
3288 if (
tm && tmcmp(tptr,
tm) == 0) {
3304 return "time out of range";
3307 return "gmtime/localtime error";
3311vtmcmp(
struct vtm *a,
struct vtm *b)
3313 if (ne(a->year, b->year))
3314 return lt(a->year, b->year) ? -1 : 1;
3315 else if (a->mon != b->mon)
3316 return a->mon < b->mon ? -1 : 1;
3317 else if (a->mday != b->mday)
3318 return a->mday < b->mday ? -1 : 1;
3319 else if (a->hour != b->hour)
3320 return a->hour < b->hour ? -1 : 1;
3321 else if (a->min != b->min)
3322 return a->min < b->min ? -1 : 1;
3323 else if (a->sec != b->sec)
3324 return a->sec < b->sec ? -1 : 1;
3325 else if (ne(a->subsecx, b->subsecx))
3326 return lt(a->subsecx, b->subsecx) ? -1 : 1;
3332tmcmp(
struct tm *a,
struct tm *b)
3334 if (a->tm_year != b->tm_year)
3335 return a->tm_year < b->tm_year ? -1 : 1;
3336 else if (a->tm_mon != b->tm_mon)
3337 return a->tm_mon < b->tm_mon ? -1 : 1;
3338 else if (a->tm_mday != b->tm_mday)
3339 return a->tm_mday < b->tm_mday ? -1 : 1;
3340 else if (a->tm_hour != b->tm_hour)
3341 return a->tm_hour < b->tm_hour ? -1 : 1;
3342 else if (a->tm_min != b->tm_min)
3343 return a->tm_min < b->tm_min ? -1 : 1;
3344 else if (a->tm_sec != b->tm_sec)
3345 return a->tm_sec < b->tm_sec ? -1 : 1;
3385time_s_mkutc(
int argc, VALUE *argv, VALUE klass)
3389 time_arg(argc, argv, &
vtm);
3390 return time_gmtime(time_new_timew(klass, timegmw(&
vtm)));
3428time_s_mktime(
int argc, VALUE *argv, VALUE klass)
3432 time_arg(argc, argv, &
vtm);
3433 return time_localtime(time_new_timew(klass, timelocalw(&
vtm)));
3451time_to_i(VALUE time)
3455 GetTimeval(time, tobj);
3456 return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE)));
3484time_to_f(VALUE time)
3488 GetTimeval(time, tobj);
3489 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3507time_to_r(VALUE time)
3512 GetTimeval(time, tobj);
3513 v = rb_time_unmagnify_to_rational(tobj->timew);
3541time_usec(VALUE time)
3546 GetTimeval(time, tobj);
3548 w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
3549 wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
3550 return rb_to_int(w2v(q));
3574time_nsec(VALUE time)
3578 GetTimeval(time, tobj);
3579 return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
3604time_subsec(VALUE time)
3608 GetTimeval(time, tobj);
3609 return quov(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))),
INT2FIX(TIME_SCALE));
3638time_cmp(VALUE time1, VALUE time2)
3643 GetTimeval(time1, tobj1);
3644 if (IsTimeval(time2)) {
3645 GetTimeval(time2, tobj2);
3646 n = wcmp(tobj1->timew, tobj2->timew);
3649 return rb_invcmp(time1, time2);
3651 if (n == 0)
return INT2FIX(0);
3665time_eql(VALUE time1, VALUE time2)
3669 GetTimeval(time1, tobj1);
3670 if (IsTimeval(time2)) {
3671 GetTimeval(time2, tobj2);
3672 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3696time_utc_p(VALUE time)
3700 GetTimeval(time, tobj);
3701 return RBOOL(TZMODE_UTC_P(tobj));
3714time_hash(VALUE time)
3718 GetTimeval(time, tobj);
3719 return rb_hash(w2v(tobj->timew));
3724time_init_copy(VALUE copy, VALUE time)
3729 GetTimeval(time, tobj);
3730 GetNewTimeval(copy, tcopy);
3739 VALUE dup = time_s_alloc(rb_obj_class(time));
3740 time_init_copy(dup, time);
3745time_localtime(VALUE time)
3751 GetTimeval(time, tobj);
3752 if (TZMODE_LOCALTIME_P(tobj)) {
3760 zone = tobj->vtm.zone;
3761 if (maybe_tzobj_p(zone) && zone_localtime(zone, time)) {
3765 if (!localtimew(tobj->timew, &
vtm))
3766 rb_raise(rb_eArgError,
"localtime error");
3770 TZMODE_SET_LOCALTIME(tobj);
3775time_zonelocal(VALUE time, VALUE off)
3778 if (zone_localtime(zone, time))
return time;
3780 if (
NIL_P(off = utc_offset_arg(off))) {
3782 if (
NIL_P(zone = find_timezone(time, off))) invalid_utc_offset(off);
3783 if (!zone_localtime(zone, time)) invalid_utc_offset(off);
3786 else if (off == UTC_ZONE) {
3787 return time_gmtime(time);
3789 validate_utc_offset(off);
3791 time_set_utc_offset(time, off);
3792 return time_fixoff(time);
3819time_localtime_m(
int argc, VALUE *argv, VALUE time)
3824 return time_zonelocal(time, off);
3827 return time_localtime(time);
3849time_gmtime(VALUE time)
3854 GetTimeval(time, tobj);
3855 if (TZMODE_UTC_P(tobj)) {
3864 GMTIMEW(tobj->timew, &
vtm);
3868 TZMODE_SET_UTC(tobj);
3873time_fixoff(VALUE time)
3879 GetTimeval(time, tobj);
3880 if (TZMODE_FIXOFF_P(tobj)) {
3888 if (TZMODE_FIXOFF_P(tobj))
3889 off = tobj->vtm.utc_offset;
3893 GMTIMEW(tobj->timew, &
vtm);
3895 zone = tobj->vtm.zone;
3897 tobj->vtm.zone = zone;
3898 vtm_add_offset(&tobj->vtm, off, +1);
3901 TZMODE_SET_FIXOFF(tobj, off);
3935time_getlocaltime(
int argc, VALUE *argv, VALUE time)
3941 if (maybe_tzobj_p(zone)) {
3942 VALUE t = time_dup(time);
3943 if (zone_localtime(off, t))
return t;
3946 if (
NIL_P(off = utc_offset_arg(off))) {
3948 if (
NIL_P(zone = find_timezone(time, off))) invalid_utc_offset(off);
3949 time = time_dup(time);
3950 if (!zone_localtime(zone, time)) invalid_utc_offset(off);
3953 else if (off == UTC_ZONE) {
3954 return time_gmtime(time_dup(time));
3956 validate_utc_offset(off);
3958 time = time_dup(time);
3959 time_set_utc_offset(time, off);
3960 return time_fixoff(time);
3963 return time_localtime(time_dup(time));
3981time_getgmtime(VALUE time)
3983 return time_gmtime(time_dup(time));
3989 if (TZMODE_UTC_P(tobj))
return time_gmtime(time);
3990 if (TZMODE_FIXOFF_P(tobj))
return time_fixoff(time);
3991 return time_localtime(time);
3994static VALUE strftime_cstr(
const char *fmt,
size_t len, VALUE time,
rb_encoding *enc);
3995#define strftimev(fmt, time, enc) strftime_cstr((fmt), rb_strlen_lit(fmt), (time), (enc))
4009time_asctime(VALUE time)
4030time_to_s(VALUE time)
4034 GetTimeval(time, tobj);
4035 if (TZMODE_UTC_P(tobj))
4057time_inspect(VALUE time)
4062 GetTimeval(time, tobj);
4064 subsec = w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE)));
4076 subsec = quov(subsec,
INT2FIX(TIME_SCALE));
4079 if (TZMODE_UTC_P(tobj)) {
4085 char sign = (off < 0) ? (off = -off,
'-') :
'+';
4087 int min = (off /= 60) % 60;
4089 rb_str_catf(str,
" %c%.2d%.2d", sign, (
int)off, min);
4096time_add0(VALUE klass,
const struct time_object *tobj, VALUE torig, VALUE offset,
int sign)
4101 offset = num_exact(offset);
4103 result = time_new_timew(klass, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
4105 result = time_new_timew(klass, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
4106 GetTimeval(result, result_tobj);
4107 TZMODE_COPY(result_tobj, tobj);
4113time_add(
const struct time_object *tobj, VALUE torig, VALUE offset,
int sign)
4115 return time_add0(
rb_cTime, tobj, torig, offset, sign);
4130time_plus(VALUE time1, VALUE time2)
4133 GetTimeval(time1, tobj);
4135 if (IsTimeval(time2)) {
4136 rb_raise(rb_eTypeError,
"time + time?");
4138 return time_add(tobj, time1, time2, 1);
4157time_minus(VALUE time1, VALUE time2)
4161 GetTimeval(time1, tobj);
4162 if (IsTimeval(time2)) {
4165 GetTimeval(time2, tobj2);
4166 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
4168 return time_add(tobj, time1, time2, -1);
4172ndigits_denominator(VALUE ndigits)
4177 rb_raise(rb_eArgError,
"negative ndigits given");
4216time_round(
int argc, VALUE *argv, VALUE time)
4218 VALUE ndigits, v, den;
4224 den = ndigits_denominator(ndigits);
4226 GetTimeval(time, tobj);
4227 v = w2v(rb_time_unmagnify(tobj->timew));
4230 if (lt(v, quov(den,
INT2FIX(2))))
4231 return time_add(tobj, time, v, -1);
4233 return time_add(tobj, time, subv(den, v), 1);
4264time_floor(
int argc, VALUE *argv, VALUE time)
4266 VALUE ndigits, v, den;
4272 den = ndigits_denominator(ndigits);
4274 GetTimeval(time, tobj);
4275 v = w2v(rb_time_unmagnify(tobj->timew));
4278 return time_add(tobj, time, v, -1);
4309time_ceil(
int argc, VALUE *argv, VALUE time)
4311 VALUE ndigits, v, den;
4317 den = ndigits_denominator(ndigits);
4319 GetTimeval(time, tobj);
4320 v = w2v(rb_time_unmagnify(tobj->timew));
4323 if (!rb_equal(v,
INT2FIX(0))) {
4326 return time_add(tobj, time, v, 1);
4348 GetTimeval(time, tobj);
4349 MAKE_TM(time, tobj);
4350 return INT2FIX(tobj->vtm.sec);
4368 GetTimeval(time, tobj);
4369 MAKE_TM(time, tobj);
4370 return INT2FIX(tobj->vtm.min);
4384time_hour(VALUE time)
4388 GetTimeval(time, tobj);
4389 MAKE_TM(time, tobj);
4390 return INT2FIX(tobj->vtm.hour);
4406time_mday(VALUE time)
4410 GetTimeval(time, tobj);
4411 MAKE_TM(time, tobj);
4412 return INT2FIX(tobj->vtm.mday);
4432 GetTimeval(time, tobj);
4433 MAKE_TM(time, tobj);
4434 return INT2FIX(tobj->vtm.mon);
4448time_year(VALUE time)
4452 GetTimeval(time, tobj);
4453 MAKE_TM(time, tobj);
4454 return tobj->vtm.year;
4476time_wday(VALUE time)
4480 GetTimeval(time, tobj);
4481 MAKE_TM_ENSURE(time, tobj, tobj->vtm.wday != VTM_WDAY_INITVAL);
4482 return INT2FIX((
int)tobj->vtm.wday);
4486 return RBOOL(time_wday(time) == INT2FIX(n)); \
4500time_sunday(VALUE time)
4516time_monday(VALUE time)
4532time_tuesday(VALUE time)
4548time_wednesday(VALUE time)
4564time_thursday(VALUE time)
4580time_friday(VALUE time)
4596time_saturday(VALUE time)
4612time_yday(VALUE time)
4616 GetTimeval(time, tobj);
4617 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
4618 return INT2FIX(tobj->vtm.yday);
4647time_isdst(VALUE time)
4651 GetTimeval(time, tobj);
4652 MAKE_TM(time, tobj);
4653 if (tobj->vtm.isdst == VTM_ISDST_INITVAL) {
4654 rb_raise(rb_eRuntimeError,
"isdst is not set yet");
4656 return RBOOL(tobj->vtm.isdst);
4673time_zone(VALUE time)
4678 GetTimeval(time, tobj);
4679 MAKE_TM(time, tobj);
4681 if (TZMODE_UTC_P(tobj)) {
4684 zone = tobj->vtm.zone;
4713 GetTimeval(time, tobj);
4715 if (TZMODE_UTC_P(tobj)) {
4719 MAKE_TM(time, tobj);
4720 return tobj->vtm.utc_offset;
4742time_to_a(VALUE time)
4746 GetTimeval(time, tobj);
4747 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
4757 RBOOL(tobj->vtm.isdst),
4762rb_strftime_alloc(
const char *format,
size_t format_len,
rb_encoding *enc,
4763 VALUE time,
struct vtm *
vtm, wideval_t timew,
int gmt)
4768 if (!timew2timespec_exact(timew, &ts))
4769 timev = w2v(rb_time_unmagnify(timew));
4772 return rb_strftime_timespec(format, format_len, enc, time,
vtm, &ts, gmt);
4775 return rb_strftime(format, format_len, enc, time,
vtm, timev, gmt);
4780strftime_cstr(
const char *fmt,
size_t len, VALUE time,
rb_encoding *enc)
4785 GetTimeval(time, tobj);
4786 MAKE_TM(time, tobj);
4787 str = rb_strftime_alloc(fmt, len, enc, time, &tobj->vtm, tobj->timew, TZMODE_UTC_P(tobj));
4788 if (!str)
rb_raise(rb_eArgError,
"invalid format: %s", fmt);
4980time_strftime(VALUE time, VALUE format)
4988 GetTimeval(time, tobj);
4989 MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
4992 rb_raise(rb_eArgError,
"format should have ASCII compatible encoding");
4994 tmp = rb_str_tmp_frozen_acquire(format);
4999 rb_warning(
"strftime called with empty format string");
5003 VALUE str = rb_strftime_alloc(fmt, len, enc, time, &tobj->vtm, tobj->timew,
5004 TZMODE_UTC_P(tobj));
5005 rb_str_tmp_frozen_release(format, tmp);
5006 if (!str)
rb_raise(rb_eArgError,
"invalid format: %"PRIsVALUE, format);
5011int ruby_marshal_write_long(
long x,
char *buf);
5013enum {base_dump_size = 8};
5017time_mdump(VALUE time)
5021 char buf[base_dump_size +
sizeof(long) + 1];
5028 VALUE subsecx, nano, subnano, v, zone;
5030 VALUE year_extend =
Qnil;
5031 const int max_year = 1900+0xffff;
5033 GetTimeval(time, tobj);
5035 gmtimew(tobj->timew, &
vtm);
5039 if (year > max_year) {
5040 year_extend =
INT2FIX(year - max_year);
5043 else if (year < 1900) {
5044 year_extend =
LONG2NUM(1900 - year);
5049 if (rb_int_positive_p(
vtm.year)) {
5050 year_extend = rb_int_minus(
vtm.year,
INT2FIX(max_year));
5054 year_extend = rb_int_minus(
INT2FIX(1900),
vtm.year);
5059 subsecx =
vtm.subsecx;
5061 nano = mulquov(subsecx,
INT2FIX(1000000000),
INT2FIX(TIME_SCALE));
5062 divmodv(nano,
INT2FIX(1), &v, &subnano);
5067 nano = addv(
LONG2FIX(nsec), subnano);
5070 TZMODE_UTC_P(tobj) << 30 |
5075 s = (
unsigned long)
vtm.min << 26 |
5079 for (i=0; i<4; i++) {
5080 buf[i] = (
unsigned char)p;
5083 for (i=4; i<8; i++) {
5084 buf[i] = (
unsigned char)s;
5088 if (!
NIL_P(year_extend)) {
5096 char *p, *
const buf_year_extend = buf + base_dump_size;
5097 if (ysize > LONG_MAX ||
5098 (i = ruby_marshal_write_long((
long)ysize, buf_year_extend)) < 0) {
5099 rb_raise(rb_eArgError,
"year too %s to marshal: %"PRIsVALUE
" UTC",
5100 (year == 1900 ?
"small" :
"big"),
vtm.year);
5102 i += base_dump_size;
5113 if (!rb_equal(nano,
INT2FIX(0))) {
5115 rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
5116 rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
5132 int len = (int)
sizeof(buf);
5133 buf[1] = (char)((nsec % 10) << 4);
5135 buf[0] = (char)(nsec % 10);
5137 buf[0] |= (char)((nsec % 10) << 4);
5142 if (!TZMODE_UTC_P(tobj)) {
5144 divmodv(off,
INT2FIX(1), &div, &mod);
5145 if (rb_equal(mod,
INT2FIX(0)))
5146 off = rb_Integer(div);
5149 zone = tobj->vtm.zone;
5150 if (maybe_tzobj_p(zone)) {
5159time_dump(
int argc, VALUE *argv, VALUE time)
5164 str = time_mdump(time);
5170mload_findzone(VALUE arg)
5172 VALUE *argp = (VALUE *)arg;
5173 VALUE time = argp[0], zone = argp[1];
5174 return find_timezone(time, zone);
5178mload_zone(VALUE time, VALUE zone)
5184 if (
NIL_P(z))
return rb_fstring(zone);
5189long ruby_marshal_read_long(
const char **buf,
long len);
5193time_mload(VALUE time, VALUE str)
5203 VALUE submicro, nano_num, nano_den, offset, zone, year;
5208#define get_attr(attr, iffound) \
5209 attr = rb_attr_delete(str, id_##attr); \
5210 if (!NIL_P(attr)) { \
5214 get_attr(nano_num, {});
5215 get_attr(nano_den, {});
5216 get_attr(submicro, {});
5217 get_attr(offset, (offset =
rb_rescue(validate_utc_offset, offset, 0,
Qnil)));
5218 get_attr(zone, (zone =
rb_rescue(validate_zone_name, zone, 0,
Qnil)));
5228 goto invalid_format;
5232 for (i=0; i<4; i++) {
5233 p |= (
unsigned long)buf[i]<<(8*i);
5235 for (i=4; i<8; i++) {
5236 s |= (
unsigned long)buf[i]<<(8*(i-4));
5239 if ((p & (1UL<<31)) == 0) {
5245 timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
5249 gmt = (int)((p >> 30) & 0x1);
5252 year =
INT2FIX(((
int)(p >> 14) & 0xffff) + 1900);
5258 const char *ybuf = (
const char *)(buf += base_dump_size);
5259 ysize = ruby_marshal_read_long(&ybuf, len);
5260 len -= ybuf - (
const char *)buf;
5261 if (ysize < 0 || ysize > len)
goto invalid_format;
5264 year = rb_int_minus(year, year_extend);
5267 year = rb_int_plus(year, year_extend);
5270 unsigned int mon = ((int)(p >> 10) & 0xf);
5277 vtm.mday = (int)(p >> 5) & 0x1f;
5278 vtm.hour = (int) p & 0x1f;
5279 vtm.min = (int)(s >> 26) & 0x3f;
5280 vtm.sec = (int)(s >> 20) & 0x3f;
5284 vtm.zone = str_empty;
5286 usec = (long)(s & 0xfffff);
5291 if (nano_num !=
Qnil) {
5292 VALUE nano = quov(num_exact(nano_num), num_exact(nano_den));
5295 else if (submicro !=
Qnil) {
5303 if (10 <= (digit = ptr[0] >> 4))
goto end_submicro;
5304 nsec += digit * 100;
5305 if (10 <= (digit = ptr[0] & 0xf))
goto end_submicro;
5309 if (10 <= (digit = ptr[1] >> 4))
goto end_submicro;
5315 timew = timegmw(&
vtm);
5318 GetNewTimeval(time, tobj);
5319 tobj->tzmode = TIME_TZMODE_LOCALTIME;
5321 tobj->timew = timew;
5323 TZMODE_SET_UTC(tobj);
5325 else if (!
NIL_P(offset)) {
5326 time_set_utc_offset(time, offset);
5330 zone = mload_zone(time, zone);
5331 tobj->vtm.zone = zone;
5332 zone_localtime(zone, time);
5338 rb_raise(rb_eTypeError,
"marshaled time format differ");
5344time_load(VALUE klass, VALUE str)
5346 VALUE time = time_s_alloc(klass);
5348 time_mload(time, str);
5367tm_from_time(VALUE klass, VALUE time)
5375 GetTimeval(time, tobj);
5376 tm = time_s_alloc(klass);
5379 GMTIMEW(ttm->timew = tobj->timew, v);
5380 ttm->timew = wsub(ttm->timew, v->subsecx);
5385 TZMODE_SET_UTC(ttm);
5391 GetTimeval(time, tobj);
5392 if (tobj->tm_got && TZMODE_UTC_P(tobj))
5395 GMTIMEW(tobj->timew, v = &
vtm);
5396 args[i++] = v->year;
5403 case 0: args[i++] =
Qfalse;
break;
5404 case 1: args[i++] =
Qtrue;
break;
5405 default: args[i++] =
Qnil;
break;
5407 args[i++] = w2v(rb_time_unmagnify(tobj->timew));
5408 return rb_class_new_instance(i, args, klass);
5421tm_initialize(
int argc, VALUE *argv, VALUE
tm)
5427 time_arg(argc, argv, &
vtm);
5432 tobj->tzmode = TIME_TZMODE_UTC;
5461 VALUE dup = time_s_alloc(
rb_cTime);
5467 const VALUE *p = RSTRUCT_CONST_PTR(
tm);
5470 for (i = 0; i < numberof(t); ++i) {
5471 t[i] = p[numberof(t) - 1 - i];
5473 return time_s_mkutc(numberof(t), t,
rb_cTime);
5484#define tm_subsec tm_zero
5485#define tm_utc_offset tm_zero
5496 const VALUE *p = RSTRUCT_CONST_PTR(
tm);
5498 return rb_sprintf(
"%.4"PRIsVALUE
"-%.2"PRIsVALUE
"-%.2"PRIsVALUE
" "
5499 "%.2"PRIsVALUE
":%.2"PRIsVALUE
":%.2"PRIsVALUE
" "
5501 p[5], p[4], p[3], p[2], p[1], p[0]);
5505tm_plus(VALUE
tm, VALUE offset)
5507 return time_add0(rb_obj_class(
tm), get_timeval(
tm),
tm, offset, +1);
5511tm_minus(VALUE
tm, VALUE offset)
5513 return time_add0(rb_obj_class(
tm), get_timeval(
tm),
tm, offset, -1);
5518Init_tm(VALUE outer,
const char *name)
5557 "sec",
"min",
"hour",
5558 "mday",
"mon",
"year",
5577rb_time_zone_abbreviation(VALUE zone, VALUE time)
5579 VALUE
tm, abbr, strftime_args[2];
5582 if (!
NIL_P(abbr))
return abbr;
5584 tm = tm_from_time(rb_cTimeTM, time);
5589#ifdef SUPPORT_TZINFO_ZONE_ABBREVIATION
5596 strftime_args[0] = rb_fstring_lit(
"%Z");
5597 strftime_args[1] =
tm;
5602 abbr = rb_check_funcall_default(zone, idName, 0, 0,
Qnil);
5642 str_utc = rb_fstring_lit(
"UTC");
5644 str_empty = rb_fstring_lit(
"");
5730 if (debug_find_time_numguess) {
5732 find_time_numguess_getter, NULL);
5735 rb_cTimeTM = Init_tm(
rb_cTime,
"tm");
5738#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_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.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
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_mComparable
Comparable module.
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
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.
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 long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer 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.
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.