12#define _DEFAULT_SOURCE
31#if defined(HAVE_SYS_TIME_H)
38static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
39static ID id_nanosecond, id_microsecond, id_millisecond, id_nsec, id_usec;
40static ID id_local_to_utc, id_utc_to_local, id_find_timezone;
41static ID id_year, id_mon, id_mday, id_hour,
id_min, id_sec, id_isdst;
44#define id_divmod idDivmod
46#define UTC_ZONE Qundef
52#define NDIV(x,y) (-(-((x)+1)/(y))-1)
53#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
54#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
55#define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
56#define VTM_WDAY_INITVAL (7)
57#define VTM_ISDST_INITVAL (3)
72 if ((
long)x < (
long)y)
74 if ((
long)x > (
long)y)
82#define ne(x,y) (!eq((x),(y)))
83#define lt(x,y) (cmp((x),(y)) < 0)
84#define gt(x,y) (cmp((x),(y)) > 0)
85#define le(x,y) (cmp((x),(y)) <= 0)
86#define ge(x,y) (cmp((x),(y)) >= 0)
112 return rb_fix_mul_fix(x, y);
123 return rb_fix_div_fix(x, y);
135 if (
FIXNUM_P(x))
return rb_fix_mod_fix(x, y);
141#define neg(x) (subv(INT2FIX(0), (x)))
163 VALUE ret = quor(x, y);
171#define mulquov(x,y,z) (((y) == (z)) ? (x) : quov(mulv((x),(y)),(z)))
180 rb_fix_divmod_fix(
n, d, q, r);
195# define INT64toNUM(x) LONG2NUM(x)
196#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
197# define INT64toNUM(x) LL2NUM(x)
200#if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T
205# define WIDEVALUE_IS_WIDER 1
206# define UWIDEINT_MAX UINT64_MAX
207# define WIDEINT_MAX INT64_MAX
208# define WIDEINT_MIN INT64_MIN
209# define FIXWINT_P(tv) ((tv) & 1)
210# define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
211# define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG))
212# define FIXWV_MAX (((int64_t)1 << 62) - 1)
213# define FIXWV_MIN (-((int64_t)1 << 62))
214# define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi))
215# define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i))
216# define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w))
222# define WIDEVALUE_IS_WIDER 0
223# define UWIDEINT_MAX ULONG_MAX
224# define WIDEINT_MAX LONG_MAX
225# define WIDEINT_MIN LONG_MIN
226# define FIXWINT_P(v) FIXNUM_P(v)
227# define FIXWV_MAX FIXNUM_MAX
228# define FIXWV_MIN FIXNUM_MIN
229# define FIXWVABLE(i) FIXABLE(i)
230# define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i))
231# define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
234#define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
235#define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
236#define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
237#define MUL_OVERFLOW_FIXWV_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXWV_MIN, FIXWV_MAX)
246# define WIDEVAL_GET(w) ((w).value)
249# define WIDEVAL_WRAP(v) (v)
250# define WIDEVAL_GET(w) (w)
253#if WIDEVALUE_IS_WIDER
262# define WINT2WV(wi) wint2wv(wi)
264# define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi))
270#if WIDEVALUE_IS_WIDER
279#if WIDEVALUE_IS_WIDER
289 else if (sign == -1) {
293 else if (sign == +1) {
309#if WIDEVALUE_IS_WIDER
315 return v2w_bignum(
v);
324#if WIDEVALUE_IS_WIDER
338#if WIDEVALUE_IS_WIDER
355#define wne(x,y) (!weq((x),(y)))
356#define wlt(x,y) (wcmp((x),(y)) < 0)
357#define wgt(x,y) (wcmp((x),(y)) > 0)
358#define wle(x,y) (wcmp((x),(y)) <= 0)
359#define wge(x,y) (wcmp((x),(y)) >= 0)
364#if WIDEVALUE_IS_WIDER
370 return v2w(addv(w2v(wx), w2v(wy)));
376#if WIDEVALUE_IS_WIDER
382 return v2w(subv(w2v(wx), w2v(wy)));
388#if WIDEVALUE_IS_WIDER
394 return v2w(mulv(w2v(wx), w2v(wy)));
400#if WIDEVALUE_IS_WIDER
412 return v2w(quov(w2v(wx), w2v(wy)));
415#define wmulquo(x,y,z) ((WIDEVAL_GET(y) == WIDEVAL_GET(z)) ? (x) : wquo(wmul((x),(y)),(z)))
416#define wmulquoll(x,y,z) (((y) == (z)) ? (x) : wquo(wmul((x),WINT2WV(y)),WINT2WV(z)))
418#if WIDEVALUE_IS_WIDER
445 if (d > 0 ? r < 0 : r > 0) {
461#if WIDEVALUE_IS_WIDER
462 if (wdivmod0(wn, wd, wq, wr))
return;
464 divmodv(w2v(wn), w2v(wd), &vq, &vr);
477 wdivmod(wmul(wx,wy), wz, wq, wr);
483#if WIDEVALUE_IS_WIDER
485 if (wdivmod0(wx, wy, &q, &dmy))
return q;
487 return v2w(divv(w2v(wx), w2v(wy)));
493#if WIDEVALUE_IS_WIDER
495 if (wdivmod0(wx, wy, &dmy, &r))
return r;
497 return v2w(modv(w2v(wx), w2v(wy)));
557rb_time_unmagnify_to_rational(
wideval_t w)
565 return v2w(rb_time_unmagnify_to_rational(w));
572#if WIDEVALUE_IS_WIDER
604#if WIDEVALUE_IS_WIDER
620#define TIMET2WV(t) timet2wv(t)
625#if WIDEVALUE_IS_WIDER
643#define WV2TIMET(t) wv2timet(t)
646static VALUE rb_cTimeTM;
652static VALUE validate_utc_offset(
VALUE utc_offset);
653static VALUE validate_zone_name(
VALUE zone_name);
654static void validate_vtm(
struct vtm *vtm);
662static time_t timegm_noleapsecond(
struct tm *
tm);
663static int tmcmp(
struct tm *a,
struct tm *b);
664static int vtmcmp(
struct vtm *a,
struct vtm *b);
665static const char *find_time_t(
struct tm *tptr,
int utc_p,
time_t *tp);
667static struct vtm *localtimew(
wideval_t timew,
struct vtm *result);
669static int leap_year_p(
long y);
670#define leap_year_v_p(y) leap_year_p(NUM2LONG(modv((y), INT2FIX(400))))
685rb_localtime_r(
const time_t *t,
struct tm *result)
687#if defined __APPLE__ && defined __LP64__
696 if (tmp) *result = *tmp;
699#if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
703 struct tm tmp = *result;
706# if defined(HAVE_STRUCT_TM_TM_GMTOFF)
710 if (*t + gmtoff1 != t2 + gmtoff2)
716#define LOCALTIME(tm, result) rb_localtime_r((tm), &(result))
718#ifndef HAVE_STRUCT_TM_TM_GMTOFF
720rb_gmtime_r(
const time_t *t,
struct tm *result)
726 if (tmp) *result = *tmp;
728#if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM)
729 if (result && *t != timegm(result)) {
735# define GMTIME(tm, result) rb_gmtime_r((tm), &(result))
738static const int common_year_yday_offset[] = {
743 -1 + 31 + 28 + 31 + 30,
744 -1 + 31 + 28 + 31 + 30 + 31,
745 -1 + 31 + 28 + 31 + 30 + 31 + 30,
746 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
747 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
748 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
749 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
750 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
753static const int leap_year_yday_offset[] = {
758 -1 + 31 + 29 + 31 + 30,
759 -1 + 31 + 29 + 31 + 30 + 31,
760 -1 + 31 + 29 + 31 + 30 + 31 + 30,
761 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
762 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
763 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
764 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
765 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
769static const int common_year_days_in_month[] = {
770 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
772static const int leap_year_days_in_month[] = {
773 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
777 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
778 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
779 (m),(m),(m),(m),(m),(m),(m),(m)
781 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
782 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
783 (m),(m),(m),(m),(m),(m),(m),(m),(m)
785 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
786 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
787 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m)
789 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
790 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), \
791 (m),(m),(m),(m),(m),(m),(m),(m),(m),(m), (m)
793static const uint8_t common_year_mon_of_yday[] = {
797static const uint8_t leap_year_mon_of_yday[] = {
809 10,11,12,13,14,15,16,17,18,19, \
810 20,21,22,23,24,25,26,27,28
813 10,11,12,13,14,15,16,17,18,19, \
814 20,21,22,23,24,25,26,27,28,29
817 10,11,12,13,14,15,16,17,18,19, \
818 20,21,22,23,24,25,26,27,28,29,30
821 10,11,12,13,14,15,16,17,18,19, \
822 20,21,22,23,24,25,26,27,28,29,30,31
824static const uint8_t common_year_mday_of_yday[] = {
826 D31,
D28,
D31,
D30,
D31,
D30,
D31,
D31,
D30,
D31,
D30,
D31
828static const uint8_t leap_year_mday_of_yday[] = {
829 D31,
D29,
D31,
D30,
D31,
D30,
D31,
D31,
D30,
D31,
D30,
D31
843 if (leap_year_p(tm_year_mod400 + 1900))
852timegmw_noleapsecond(
struct vtm *vtm)
862 year1900 = subv(vtm->year,
INT2FIX(1900));
864 divmodv(year1900,
INT2FIX(400), &q400, &r400);
867 yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday);
880 +
DIV(year_mod400 - 69, 4)
881 -
DIV(year_mod400 - 1, 100)
882 + (year_mod400 + 299) / 400;
884 vdays = addv(vdays, mulv(q400,
INT2FIX(97)));
885 vdays = addv(vdays, mulv(year1900,
INT2FIX(365)));
886 wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)),
WINT2FIXWV(86400)));
887 wret = wadd(wret, v2w(vtm->subsecx));
893zone_str(
const char *
zone)
904 for (p =
zone; *p; p++)
920gmtimew_noleapsecond(
wideval_t timew,
struct vtm *vtm)
931 split_second(timew, &timew2, &subsecx);
932 vtm->subsecx = subsecx;
939 vtm->wday = (wday + 4) % 7;
942 vtm->sec =
n % 60;
n =
n / 60;
943 vtm->min =
n % 60;
n =
n / 60;
947 divmodv(timev,
INT2FIX(400*365 + 97), &timev, &
v);
948 vtm->year = mulv(timev,
INT2FIX(400));
960 if (30*365+7+31+29-1 <=
n) {
974 x =
n / (365*100 + 24);
975 n =
n % (365*100 + 24);
977 if (30*365+7+31+29-1 <=
n) {
990 if (365*2+31+29-1 <=
n) {
1006 vtm->year = addv(vtm->year,
INT2NUM(y));
1008 if (leap_year_p(y)) {
1009 vtm->mon = leap_year_mon_of_yday[
n];
1010 vtm->mday = leap_year_mday_of_yday[
n];
1013 vtm->mon = common_year_mon_of_yday[
n];
1014 vtm->mday = common_year_mday_of_yday[
n];
1022gmtime_with_leapsecond(
const time_t *timep,
struct tm *result)
1024#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1028 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
1043 gmtoff_sec = (
int)(gmtoff % 60);
1044 gmtoff = gmtoff / 60;
1045 gmtoff_min = (
int)(gmtoff % 60);
1046 gmtoff = gmtoff / 60;
1047 gmtoff_hour = (
int)gmtoff;
1051 gmtoff_hour *= sign;
1058 result->
tm_sec += gmtoff_sec;
1059 if (result->
tm_sec < 0) {
1063 if (60 <= result->
tm_sec) {
1069 result->
tm_min += gmtoff_min;
1070 if (result->
tm_min < 0) {
1074 if (60 <= result->
tm_min) {
1080 result->
tm_hour += gmtoff_hour;
1092 if (gmtoff_day < 0) {
1097 result->
tm_yday = leap_year_p(result->
tm_year + 1900) ? 365 : 364;
1099 else if (result->
tm_mday == 1) {
1100 const int *days_in_month = leap_year_p(result->
tm_year + 1900) ?
1101 leap_year_days_in_month :
1102 common_year_days_in_month;
1114 int leap = leap_year_p(result->
tm_year + 1900);
1115 if (result->
tm_yday == (leap ? 365 : 364)) {
1121 else if (result->
tm_mday == (leap ? leap_year_days_in_month :
1122 common_year_days_in_month)[result->
tm_mon]) {
1136#if defined(HAVE_TM_ZONE)
1137 result->
tm_zone = (
char *)
"UTC";
1141 return GMTIME(timep, *result);
1145static long this_year = 0;
1146static time_t known_leap_seconds_limit;
1147static int number_of_leap_seconds_known;
1150init_leap_second_info(
void)
1157 if (this_year == 0) {
1159 struct tm *
tm, result;
1164 tm = gmtime_with_leapsecond(&now, &result);
1171 known_leap_seconds_limit = now + (
time_t)(366*86400);
1173 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
1177 vtm.mon = result.
tm_mon + 1;
1185 timew = timegmw_noleapsecond(&vtm);
1187 number_of_leap_seconds_known =
NUM2INT(w2v(wsub(
TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
1199timegmw(
struct vtm *vtm)
1209 return timegmw_noleapsecond(vtm);
1211 init_leap_second_info();
1213 timew = timegmw_noleapsecond(vtm);
1216 if (number_of_leap_seconds_known == 0) {
1222 else if (
wlt(rb_time_magnify(
TIMET2WV(known_leap_seconds_limit)), timew)) {
1223 return wadd(timew, rb_time_magnify(
WINT2WV(number_of_leap_seconds_known)));
1234 errmsg = find_time_t(&
tm, 1, &t);
1237 return wadd(rb_time_magnify(
TIMET2WV(t)), v2w(vtm->subsecx));
1241gmtimew(
wideval_t timew,
struct vtm *result)
1249 gmtimew_noleapsecond(timew, result);
1253 init_leap_second_info();
1255 if (number_of_leap_seconds_known == 0) {
1259 gmtimew_noleapsecond(timew, result);
1262 else if (
wlt(rb_time_magnify(
TIMET2WV(known_leap_seconds_limit)), timew)) {
1263 timew = wsub(timew, rb_time_magnify(
WINT2WV(number_of_leap_seconds_known)));
1264 gmtimew_noleapsecond(timew, result);
1268 split_second(timew, &timew2, &subsecx);
1271 if (!gmtime_with_leapsecond(&t, &
tm))
1280 result->subsecx = subsecx;
1281 result->utc_offset =
INT2FIX(0);
1292#define GMTIMEW(w, v) \
1293 (gmtimew(w, v) ? (void)0 : rb_raise(rb_eArgError, "gmtime error"))
1295static struct tm *localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *
zone);
1330static const int compat_common_month_table[12][7] = {
1332 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 },
1333 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 },
1334 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1335 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1336 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 },
1337 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 },
1338 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1339 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 },
1340 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1341 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 },
1342 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1343 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1371static const int compat_leap_month_table[7] = {
1373 2032, 2016, 2028, 2012, 2024, 2036, 2020,
1377calc_wday(
int year_mod400,
int month,
int day)
1382 a = (14 - month) / 12;
1383 y = year_mod400 + 4800 - a;
1384 m = month + 12 * a - 3;
1385 wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
1391guess_local_offset(
struct vtm *vtm_utc,
int *isdst_ret,
VALUE *zone_ret)
1399 int year_mod400, wday;
1408# if defined(NEGATIVE_TIME_T)
1409# if SIZEOF_TIME_T <= 4
1411# define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
1415# define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
1417 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &
tm, &gmtoff, &
zone)) {
1424 if (localtime_with_gmtoff_zone((t = 0, &t), &
tm, &gmtoff, &
zone)) {
1442 wday = calc_wday(year_mod400, vtm_utc->mon, 1);
1443 if (vtm_utc->mon == 2 && leap_year_p(year_mod400))
1444 vtm2.year =
INT2FIX(compat_leap_month_table[wday]);
1446 vtm2.year =
INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
1448 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
1451 if (localtime_with_gmtoff_zone(&t, &
tm, &gmtoff, &
zone)) {
1462 static long now_gmtoff = 0;
1463 static int now_isdst = 0;
1464 static VALUE now_zone;
1468 localtime_with_gmtoff_zone(&now, &
tm, &now_gmtoff, &
zone);
1475 *isdst_ret = now_isdst;
1477 *zone_ret = now_zone;
1483small_vtm_sub(
struct vtm *vtm1,
struct vtm *vtm2)
1487 off = vtm1->sec - vtm2->sec;
1488 off += (vtm1->min - vtm2->min) * 60;
1489 off += (vtm1->hour - vtm2->hour) * 3600;
1490 if (
ne(vtm1->year, vtm2->year))
1491 off +=
lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
1492 else if (vtm1->mon != vtm2->mon)
1493 off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
1494 else if (vtm1->mday != vtm2->mday)
1495 off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
1501timelocalw(
struct vtm *vtm)
1507 struct vtm vtm1, vtm2;
1511 long l =
FIX2LONG(vtm->year) - 1900;
1517 v = subv(vtm->year,
INT2FIX(1900));
1530 if (find_time_t(&
tm, 0, &t))
1532 return wadd(rb_time_magnify(
TIMET2WV(t)), v2w(vtm->subsecx));
1535 timew1 = timegmw(vtm);
1537 if (!localtimew(timew1, &vtm1))
1540 n = vtmcmp(vtm, &vtm1);
1542 timew1 = wsub(timew1, rb_time_magnify(
WINT2FIXWV(12*3600)));
1543 if (!localtimew(timew1, &vtm1))
1551 timew1 = wsub(timew1, rb_time_magnify(
WINT2FIXWV(24*3600)));
1552 if (!localtimew(timew1, &vtm1))
1556 timew2 = wadd(timew1, rb_time_magnify(
WINT2FIXWV(24*3600)));
1557 if (!localtimew(timew2, &vtm2))
1560 timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
1561 timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
1563 if (weq(timew1, timew2))
1566 if (!localtimew(timew1, &vtm1))
1568 if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
1571 if (!localtimew(timew2, &vtm2))
1573 if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
1577 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
1579 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
1583localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *
zone)
1588#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1613#if defined(HAVE_TM_ZONE)
1615#elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1616# if RUBY_MSVCRT_VERSION >= 140
1617# define tzname _tzname
1618# define daylight _daylight
1638timew_out_of_timet_range(
wideval_t timew)
1641#if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T
1650#if SIZEOF_TIME_T == SIZEOF_INT64_T
1663 timexv = w2v(timew);
1671localtimew(
wideval_t timew,
struct vtm *result)
1673 VALUE subsecx, offset;
1677 if (!timew_out_of_timet_range(timew)) {
1683 split_second(timew, &timew2, &subsecx);
1687 if (localtime_with_gmtoff_zone(&t, &
tm, &gmtoff, &
zone)) {
1694 result->subsecx = subsecx;
1698 result->utc_offset =
LONG2NUM(gmtoff);
1699 result->zone =
zone;
1704 if (!gmtimew(timew, result))
1707 offset = guess_local_offset(result, &isdst, &
zone);
1709 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
1712 result->utc_offset = offset;
1713 result->isdst = isdst;
1714 result->zone =
zone;
1719#define TIME_TZMODE_LOCALTIME 0
1720#define TIME_TZMODE_UTC 1
1721#define TIME_TZMODE_FIXOFF 2
1722#define TIME_TZMODE_UNINITIALIZED 3
1727 unsigned int tzmode:3;
1728 unsigned int tm_got:1;
1731#define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj))
1732#define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj))
1734#define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type)
1735#define TIME_INIT_P(tobj) ((tobj)->tzmode != TIME_TZMODE_UNINITIALIZED)
1737#define TZMODE_UTC_P(tobj) ((tobj)->tzmode == TIME_TZMODE_UTC)
1738#define TZMODE_SET_UTC(tobj) ((tobj)->tzmode = TIME_TZMODE_UTC)
1740#define TZMODE_LOCALTIME_P(tobj) ((tobj)->tzmode == TIME_TZMODE_LOCALTIME)
1741#define TZMODE_SET_LOCALTIME(tobj) ((tobj)->tzmode = TIME_TZMODE_LOCALTIME)
1743#define TZMODE_FIXOFF_P(tobj) ((tobj)->tzmode == TIME_TZMODE_FIXOFF)
1744#define TZMODE_SET_FIXOFF(tobj, off) \
1745 ((tobj)->tzmode = TIME_TZMODE_FIXOFF, \
1746 (tobj)->vtm.utc_offset = (off))
1748#define TZMODE_COPY(tobj1, tobj2) \
1749 ((tobj1)->tzmode = (tobj2)->tzmode, \
1750 (tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \
1751 (tobj1)->vtm.zone = (tobj2)->vtm.zone)
1753static VALUE time_get_tm(
VALUE,
struct time_object *);
1754#define MAKE_TM(time, tobj) \
1756 if ((tobj)->tm_got == 0) { \
1757 time_get_tm((time), (tobj)); \
1764 struct time_object *tobj =
ptr;
1774time_memsize(
const void *tobj)
1776 return sizeof(
struct time_object);
1789 struct time_object *tobj;
1795 tobj->vtm.zone =
Qnil;
1800static struct time_object *
1803 struct time_object *tobj;
1811static struct time_object *
1814 struct time_object *tobj;
1846 if (timew_out_of_timet_range(timew))
1848 split_second(timew, &timew2, &subsecx);
1861 if (timew_out_of_timet_range(timew))
1863 split_second(timew, &timew2, &subsecx);
1875#ifdef HAVE_CLOCK_GETTIME
1894 struct time_object *tobj;
1903 tobj->timew = timespec2timew(&ts);
1911 struct time_object *tobj;
1912 off = num_exact(off);
1918 tobj->vtm.zone =
Qnil;
1925vtm_add_offset(
struct vtm *vtm,
VALUE off,
int sign)
1935 divmodv(off,
INT2FIX(1), &off, &subsec);
1936 divmodv(off,
INT2FIX(60), &off, &
v);
1938 divmodv(off,
INT2FIX(60), &off, &
v);
1940 divmodv(off,
INT2FIX(24), &off, &
v);
1944 subsec =
neg(subsec);
1953 vtm->subsecx = addv(vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
2006 if (vtm->mon == 1 && vtm->mday == 1) {
2009 vtm->year = subv(vtm->year,
INT2FIX(1));
2012 else if (vtm->mday == 1) {
2014 leap_year_days_in_month :
2015 common_year_days_in_month;
2017 vtm->mday = days_in_month[vtm->mon-1];
2024 vtm->wday = (vtm->wday + 6) % 7;
2028 if (vtm->mon == 12 && vtm->mday == 31) {
2029 vtm->year = addv(vtm->year,
INT2FIX(1));
2034 else if (vtm->mday == (leap ? leap_year_days_in_month :
2035 common_year_days_in_month)[vtm->mon-1]) {
2044 vtm->wday = (vtm->wday + 1) % 7;
2060invalid_utc_offset(
void)
2062 static const char message[] =
"\"+HH:MM\", \"-HH:MM\", \"UTC\" "
2063 "or \"A\"..\"I\",\"K\"..\"Z\" expected for utc_offset";
2085 if (s[0] >=
'A' && s[0] <=
'I') {
2086 n = (
int)s[0] -
'A' + 1;
2088 else if (s[0] >=
'K' && s[0] <=
'M') {
2089 n = (
int)s[0] -
'A';
2091 else if (s[0] >=
'N' && s[0] <=
'Y') {
2092 n =
'M' - (
int)s[0];
2095 goto invalid_utc_offset;
2119 goto invalid_utc_offset;
2122 if (sec == s+7 && *(sec-1) !=
':')
goto invalid_utc_offset;
2123 if (!
ISDIGIT(sec[0]) || !
ISDIGIT(sec[1]))
goto invalid_utc_offset;
2124 n += (sec[0] * 10 + sec[1] -
'0' * 11);
2127 if (min == s+4 && *(min-1) !=
':')
goto invalid_utc_offset;
2128 if (!
ISDIGIT(min[0]) || !
ISDIGIT(min[1]))
goto invalid_utc_offset;
2129 if (min[0] >
'5')
goto invalid_utc_offset;
2130 n += (min[0] * 10 + min[1] -
'0' * 11) * 60;
2132 if (s[0] !=
'+' && s[0] !=
'-')
goto invalid_utc_offset;
2134 n += (s[1] * 10 + s[2] -
'0' * 11) * 3600;
2140 return num_exact(
arg);
2145zone_set_offset(
VALUE zone,
struct time_object *tobj,
2151 validate_utc_offset(off);
2152 tobj->vtm.utc_offset = off;
2153 tobj->vtm.zone =
zone;
2163#define EXTRACT_TIME() do { \
2164 t = v2w(rb_Integer(AREF(to_i))); \
2171 t = rb_time_unmagnify(tobj->timew);
2174#define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2179#define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2194#define EXTRACT_VTM() do { \
2196 vtm->year = obj2vint(AREF(year)); \
2197 vtm->mon = month_arg(AREF(mon)); \
2198 vtm->mday = obj2ubits(AREF(mday), 5); \
2199 vtm->hour = obj2ubits(AREF(hour), 5); \
2200 vtm->min = obj2ubits(AREF(min), 6); \
2201 vtm->sec = obj2subsecx(AREF(sec), &subsecx); \
2202 vtm->isdst = RTEST(AREF(isdst)); \
2203 vtm->utc_offset = Qnil; \
2204 t = v2w(rb_Integer(AREF(to_i))); \
2210 time_get_tm(
time, tobj);
2212 t = rb_time_unmagnify(tobj->timew);
2214 t = wadd(t, v2w(vtm->utc_offset));
2217#define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2221 else if (rb_integer_type_p(
time)) {
2223 GMTIMEW(rb_time_magnify(t), vtm);
2226#define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2231 vtm->subsecx = subsecx;
2253 t = rb_time_unmagnify(tobj->timew);
2254 tm = tm_from_time(rb_cTimeTM,
time);
2256 if (utc ==
Qundef)
return 0;
2258 s = extract_time(utc);
2259 zone_set_offset(
zone, tobj, t, s);
2260 s = rb_time_magnify(s);
2261 if (tobj->vtm.subsecx !=
INT2FIX(0)) {
2262 s = wadd(s, v2w(tobj->vtm.subsecx));
2265 zone_set_dst(
zone, tobj,
tm);
2276 split_second(tobj->timew, &t, &subsecx);
2277 tm = tm_from_time(rb_cTimeTM,
time);
2280 if (local ==
Qundef)
return 0;
2282 s = extract_vtm(local, &tobj->vtm, subsecx);
2284 zone_set_offset(
zone, tobj, s, t);
2285 zone_set_dst(
zone, tobj,
tm);
2304 struct time_object *tobj;
2313 vtm.year = obj2vint(
v[0]);
2315 vtm.mon =
NIL_P(
v[1]) ? 1 : month_arg(
v[1]);
2317 vtm.mday =
NIL_P(
v[2]) ? 1 : obj2ubits(
v[2], 5);
2319 vtm.hour =
NIL_P(
v[3]) ? 0 : obj2ubits(
v[3], 5);
2321 vtm.min =
NIL_P(
v[4]) ? 0 : obj2ubits(
v[4], 6);
2329 vtm.sec = obj2subsecx(
v[5], &subsecx);
2330 vtm.subsecx = subsecx;
2334 vtm.utc_offset =
Qnil;
2341 else if (maybe_tzobj_p(
arg))
2343 else if (!
NIL_P(utc = utc_offset_arg(
arg)))
2346 invalid_utc_offset();
2355 tobj->timew = timegmw(&vtm);
2362 else if (
NIL_P(vtm.utc_offset = utc_offset_arg(
zone))) {
2364 invalid_utc_offset();
2369 tobj->timew = timegmw(&vtm);
2380 if (!
NIL_P(vtm.utc_offset)) {
2381 VALUE off = vtm.utc_offset;
2382 vtm_add_offset(&vtm, off, -1);
2383 vtm.utc_offset =
Qnil;
2384 tobj->timew = timegmw(&vtm);
2385 return time_set_utc_offset(
time, off);
2388 tobj->timew = timelocalw(&vtm);
2389 return time_localtime(
time);
2446 return time_init_0(
time);
2452time_overflow_p(
time_t *secp,
long *nsecp)
2458 if (nsec >= 1000000000) {
2459 sec2 = nsec / 1000000000;
2463 nsec -= sec2 * 1000000000;
2466 else if (nsec < 0) {
2467 sec2 =
NDIV(nsec,1000000000);
2471 nsec -= sec2 * 1000000000;
2474#ifndef NEGATIVE_TIME_T
2483nsec2timew(
time_t sec,
long nsec)
2486 time_overflow_p(&sec, &nsec);
2489 return timespec2timew(&ts);
2496 struct time_object *tobj;
2500 tobj->timew = timew;
2510 if (usec >= 1000000) {
2511 long sec2 = usec / 1000000;
2515 usec -= sec2 * 1000000;
2518 else if (usec < 0) {
2519 long sec2 =
NDIV(usec,1000000);
2523 usec -= sec2 * 1000000;
2527 timew = nsec2timew(sec, usec * 1000);
2528 return time_new_timew(
rb_cTime, timew);
2535 return time_new_timew(
rb_cTime, nsec2timew(sec, nsec));
2546 struct time_object *tobj;
2549 if (-86400 < offset && offset < 86400) {
2555 else if (offset ==
INT_MAX-1) {
2574 if (maybe_tzobj_p(
zone)) {
2578 if (
NIL_P(off = utc_offset_arg(off))) {
2581 if (!zone_timelocal(
zone,
time)) invalid_utc_offset();
2585 return time_gmtime(
time);
2588 validate_utc_offset(off);
2589 time_set_utc_offset(
time, off);
2597time_timespec(
VALUE num,
int interval)
2600 const char *
const tstr = interval ?
"time interval" :
"time";
2603#ifndef NEGATIVE_TIME_T
2604# define arg_range_check(v) \
2606 rb_raise(rb_eArgError, "%s must not be negative", tstr) : \
2609# define arg_range_check(v) \
2610 ((interval && (v) < 0) ? \
2611 rb_raise(rb_eArgError, "time interval must not be negative") : \
2628 t.tv_nsec = (
int)(d*1e9+0.5);
2629 if (t.tv_nsec >= 1000000000) {
2630 t.tv_nsec -= 1000000000;
2634 else if ((t.tv_nsec = (
int)(-d*1e9+0.5)) > 0) {
2635 t.tv_nsec = 1000000000 - t.tv_nsec;
2639 if (
f != t.tv_sec) {
2666#undef arg_range_check
2670time_timeval(
VALUE num,
int interval)
2675 ts = time_timespec(num, interval);
2685 return time_timeval(num,
TRUE);
2691 struct time_object *tobj;
2697 ts = timew2timespec(tobj->timew);
2708 struct time_object *tobj;
2713 t = timew2timespec(tobj->timew);
2722 return time_timespec(num,
TRUE);
2735 if (
NIL_P(opts))
return false;
2759 time_zonelocal(t,
zone);
2765get_scale(
VALUE unit)
2767 if (unit ==
ID2SYM(id_nanosecond) || unit ==
ID2SYM(id_nsec)) {
2770 else if (unit ==
ID2SYM(id_microsecond) || unit ==
ID2SYM(id_usec)) {
2773 else if (unit ==
ID2SYM(id_millisecond)) {
2827 if (get_tmopt(opts, vals)) {
2831 int scale =
argc == 3 ? get_scale(unit) : 1000000;
2835 t = time_new_timew(
klass, timew);
2838 struct time_object *tobj, *tobj2;
2840 t = time_new_timew(
klass, tobj->timew);
2845 timew = rb_time_magnify(v2w(num_exact(
time)));
2846 t = time_new_timew(
klass, timew);
2849 time_zonelocal(t,
zone);
2855static const char months[][4] = {
2856 "jan",
"feb",
"mar",
"apr",
"may",
"jun",
2857 "jul",
"aug",
"sep",
"oct",
"nov",
"dec",
2874 const uint32_t usable_mask = ~(u32max << bits);
2876 int tmp = obj2int(
obj);
2881 if ((rv & usable_mask) != rv)
2910 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2912 return obj2ubits(
obj, 6);
2933 for (
i=0;
i<12;
i++) {
2943 if (
'0' <= c && c <=
'9') {
2944 mon = obj2ubits(s, 4);
2949 mon = obj2ubits(
arg, 4);
2955validate_utc_offset(
VALUE utc_offset)
2963validate_zone_name(
VALUE zone_name)
2970validate_vtm(
struct vtm *vtm)
2972#define validate_vtm_range(mem, b, e) \
2973 ((vtm->mem < b || vtm->mem > e) ? \
2974 rb_raise(rb_eArgError, #mem" out of range") : (void)0)
2982 if (!
NIL_P(vtm->utc_offset)) validate_utc_offset(vtm->utc_offset);
2983#undef validate_vtm_range
2999 vtm->utc_offset =
Qnil;
3016 rb_scan_args(
argc,
argv,
"17", &
v[0],&
v[1],&
v[2],&
v[3],&
v[4],&
v[5],&
v[6],&
v[7]);
3023 vtm->year = obj2vint(
v[0]);
3029 vtm->mon = month_arg(
v[1]);
3036 vtm->mday = obj2ubits(
v[2], 5);
3045 if (vtm->mday > mday2) {
3055 if (vtm->mday == 31) {
3062 vtm->hour =
NIL_P(
v[3])?0:obj2ubits(
v[3], 5);
3064 vtm->min =
NIL_P(
v[4])?0:obj2ubits(
v[4], 6);
3067 vtm->sec =
NIL_P(
v[5])?0:obj2ubits(
v[5],6);
3068 subsecx = usec2subsecx(
v[6]);
3076 vtm->sec = obj2subsecx(
v[5], &subsecx);
3079 vtm->subsecx = subsecx;
3091 unsigned long uy = (
unsigned long)(
LIKELY(y >= 0) ? y : -y);
3093 if (
LIKELY(uy % 4 != 0))
return 0;
3095 unsigned long century = uy / 100;
3096 if (
LIKELY(uy != century * 100))
return 1;
3097 return century % 4 == 0;
3101timegm_noleapsecond(
struct tm *
tm)
3116 DIV(tm_year-1,100) +
3117 DIV(tm_year+299,400))*86400;
3121#define DEBUG_FIND_TIME_NUMGUESS
3122#define DEBUG_GUESSRANGE
3125#ifdef DEBUG_GUESSRANGE
3126#define DEBUG_REPORT_GUESSRANGE fprintf(stderr, "find time guess range: %ld - %ld : %"PRI_TIMET_PREFIX"u\n", guess_lo, guess_hi, (unsigned_time_t)(guess_hi-guess_lo))
3128#define DEBUG_REPORT_GUESSRANGE
3131#ifdef DEBUG_FIND_TIME_NUMGUESS
3132#define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
3133static unsigned long long find_time_numguess;
3135static VALUE find_time_numguess_getter(
void)
3137 return ULL2NUM(find_time_numguess);
3140#define DEBUG_FIND_TIME_NUMGUESS_INC
3144find_time_t(
struct tm *tptr,
int utc_p,
time_t *tp)
3146 time_t guess, guess0, guess_lo, guess_hi;
3147 struct tm *
tm, tm0, tm_lo, tm_hi;
3154#define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
3172 else if (11 < tm0.
tm_mon) {
3185 else if ((d = (leap_year_p(1900 + tm0.
tm_year) ?
3186 leap_year_days_in_month :
3203 else if (tm0.
tm_min < 0) {
3207 else if (59 < tm0.
tm_min) {
3211 else if (tm0.
tm_sec < 0) {
3214 else if (60 < tm0.
tm_sec) {
3219 guess0 = guess = timegm_noleapsecond(&tm0);
3222 d = tmcmp(tptr,
tm);
3223 if (d == 0) {
goto found; }
3226 guess -= 24 * 60 * 60;
3230 guess += 24 * 60 * 60;
3233 if (guess_lo < guess && guess < guess_hi && (
tm =
GUESS(&guess)) !=
NULL) {
3234 d = tmcmp(tptr,
tm);
3235 if (d == 0) {
goto found; }
3246 d = tmcmp(tptr,
tm);
3247 if (d < 0)
goto out_of_range;
3248 if (d == 0) { guess = guess_lo;
goto found; }
3253 d = tmcmp(tptr,
tm);
3254 if (d > 0)
goto out_of_range;
3255 if (d == 0) { guess = guess_hi;
goto found; }
3262 while (guess_lo + 1 < guess_hi) {
3265 guess = guess_lo / 2 + guess_hi / 2;
3266 if (guess <= guess_lo)
3267 guess = guess_lo + 1;
3268 else if (guess >= guess_hi)
3269 guess = guess_hi - 1;
3274 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
3275 guess = guess_hi - (guess0_hi - guess0);
3276 if (guess == guess_hi)
3280 else if (status == 2) {
3281 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
3282 guess = guess_lo + (guess0 - guess0_lo);
3283 if (guess == guess_lo)
3287 if (guess <= guess_lo || guess_hi <= guess) {
3289#ifdef DEBUG_GUESSRANGE
3290 if (guess <= guess_lo)
fprintf(
stderr,
"too small guess: %ld <= %ld\n", guess, guess_lo);
3291 if (guess_hi <= guess)
fprintf(
stderr,
"too big guess: %ld <= %ld\n", guess_hi, guess);
3300 d = tmcmp(tptr,
tm);
3318 guess2 = guess - 2 * 60 * 60;
3328 guess2 += 24 * 60 * 60;
3329 if (guess != guess2) {
3331 if (
tm && tmcmp(tptr,
tm) == 0) {
3343 guess2 = guess + 2 * 60 * 60;
3353 guess2 -= 24 * 60 * 60;
3354 if (guess != guess2) {
3356 if (
tm && tmcmp(tptr,
tm) == 0) {
3400 return "time out of range";
3403 return "gmtime/localtime error";
3407vtmcmp(
struct vtm *a,
struct vtm *b)
3409 if (
ne(a->year, b->year))
3410 return lt(a->year, b->year) ? -1 : 1;
3411 else if (a->mon != b->mon)
3412 return a->mon < b->mon ? -1 : 1;
3413 else if (a->mday != b->mday)
3414 return a->mday < b->mday ? -1 : 1;
3415 else if (a->hour != b->hour)
3416 return a->hour < b->hour ? -1 : 1;
3417 else if (a->min != b->min)
3418 return a->min < b->min ? -1 : 1;
3419 else if (a->sec != b->sec)
3420 return a->sec < b->sec ? -1 : 1;
3421 else if (
ne(a->subsecx, b->subsecx))
3422 return lt(a->subsecx, b->subsecx) ? -1 : 1;
3428tmcmp(
struct tm *a,
struct tm *b)
3484 return time_gmtime(time_new_timew(
klass, timegmw(&vtm)));
3518 return time_localtime(time_new_timew(
klass, timelocalw(&vtm)));
3537 struct time_object *tobj;
3561 struct time_object *tobj;
3564 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3585 struct time_object *tobj;
3589 v = rb_time_unmagnify_to_rational(tobj->timew);
3611 struct time_object *tobj;
3642 struct time_object *tobj;
3670 struct time_object *tobj;
3704 struct time_object *tobj1, *tobj2;
3710 n = wcmp(tobj1->timew, tobj2->timew);
3731 struct time_object *tobj1, *tobj2;
3736 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3762 struct time_object *tobj;
3781 struct time_object *tobj;
3784 return rb_hash(w2v(tobj->timew));
3791 struct time_object *tobj, *tcopy;
3796 MEMCPY(tcopy, tobj,
struct time_object, 1);
3812 struct time_object *tobj;
3825 zone = tobj->vtm.zone;
3826 if (maybe_tzobj_p(
zone) && zone_localtime(
zone,
time)) {
3830 if (!localtimew(tobj->timew, &vtm))
3845 if (
NIL_P(off = utc_offset_arg(off))) {
3847 if (!zone_localtime(
zone,
time)) invalid_utc_offset();
3851 return time_gmtime(
time);
3853 validate_utc_offset(off);
3855 time_set_utc_offset(
time, off);
3856 return time_fixoff(
time);
3888 return time_zonelocal(
time, off);
3891 return time_localtime(
time);
3915 struct time_object *tobj;
3939 struct time_object *tobj;
3953 off = tobj->vtm.utc_offset;
3959 zone = tobj->vtm.zone;
3961 tobj->vtm.zone =
zone;
3962 vtm_add_offset(&tobj->vtm, off, +1);
4005 if (maybe_tzobj_p(
zone)) {
4007 if (zone_localtime(off, t))
return t;
4010 if (
NIL_P(off = utc_offset_arg(off))) {
4013 if (!zone_localtime(
zone,
time)) invalid_utc_offset();
4017 return time_gmtime(time_dup(
time));
4019 validate_utc_offset(off);
4022 time_set_utc_offset(
time, off);
4023 return time_fixoff(
time);
4026 return time_localtime(time_dup(
time));
4046 return time_gmtime(time_dup(
time));
4050time_get_tm(
VALUE time,
struct time_object *tobj)
4054 return time_localtime(
time);
4058#define strftimev(fmt, time, enc) strftime_cstr((fmt), rb_strlen_lit(fmt), (time), (enc))
4095 struct time_object *tobj;
4122 struct time_object *tobj;
4155 struct time_object *result_tobj;
4157 offset = num_exact(offset);
4159 result = time_new_timew(
klass, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
4161 result = time_new_timew(
klass, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
4169time_add(
const struct time_object *tobj,
VALUE torig,
VALUE offset,
int sign)
4171 return time_add0(
rb_cTime, tobj, torig, offset, sign);
4188 struct time_object *tobj;
4194 return time_add(tobj, time1, time2, 1);
4215 struct time_object *tobj;
4219 struct time_object *tobj2;
4222 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
4224 return time_add(tobj, time1, time2, -1);
4245 struct time_object *tobj;
4246 struct time_object *tobj2;
4248 rb_warn(
"Time#succ is obsolete; use time + 1");
4254 zone_localtime(tobj2->vtm.zone,
time);
4259#define time_succ rb_time_succ
4262ndigits_denominator(
VALUE ndigits)
4311 struct time_object *tobj;
4316 den = ndigits_denominator(ndigits);
4319 v = w2v(rb_time_unmagnify(tobj->timew));
4323 return time_add(tobj,
time,
v, -1);
4325 return time_add(tobj,
time, subv(den,
v), 1);
4361 struct time_object *tobj;
4366 den = ndigits_denominator(ndigits);
4369 v = w2v(rb_time_unmagnify(tobj->timew));
4372 return time_add(tobj,
time,
v, -1);
4408 struct time_object *tobj;
4413 den = ndigits_denominator(ndigits);
4416 v = w2v(rb_time_unmagnify(tobj->timew));
4419 return time_add(tobj,
time, subv(den,
v), 1);
4439 struct time_object *tobj;
4443 return INT2FIX(tobj->vtm.sec);
4459 struct time_object *tobj;
4463 return INT2FIX(tobj->vtm.min);
4479 struct time_object *tobj;
4483 return INT2FIX(tobj->vtm.hour);
4501 struct time_object *tobj;
4505 return INT2FIX(tobj->vtm.mday);
4523 struct time_object *tobj;
4527 return INT2FIX(tobj->vtm.mon);
4543 struct time_object *tobj;
4547 return tobj->vtm.year;
4571 struct time_object *tobj;
4579 return INT2FIX((
int)tobj->vtm.wday);
4583 return (time_wday(time) == INT2FIX(n)) ? Qtrue : Qfalse; \
4711 struct time_object *tobj;
4715 if (tobj->vtm.yday == 0) {
4719 return INT2FIX(tobj->vtm.yday);
4750 struct time_object *tobj;
4776 struct time_object *tobj;
4785 zone = tobj->vtm.zone;
4812 struct time_object *tobj;
4821 return tobj->vtm.utc_offset;
4845 struct time_object *tobj;
4863rb_strftime_alloc(
const char *format,
size_t format_len,
rb_encoding *enc,
4869 if (!timew2timespec_exact(timew, &ts))
4870 timev = w2v(rb_time_unmagnify(timew));
4883 struct time_object *tobj;
5083 struct time_object *tobj;
5100 rb_warning(
"strftime called with empty format string");
5120 struct time_object *tobj;
5132 const int max_year = 1900+0xffff;
5136 gmtimew(tobj->timew, &vtm);
5140 if (year > max_year) {
5141 year_extend =
INT2FIX(year - max_year);
5144 else if (year < 1900) {
5145 year_extend =
LONG2NUM(1900 - year);
5160 subsecx = vtm.subsecx;
5163 divmodv(nano,
INT2FIX(1), &
v, &subnano);
5168 nano = addv(
LONG2FIX(nsec), subnano);
5176 s = (
unsigned long)vtm.min << 26 |
5180 for (
i=0;
i<4;
i++) {
5184 for (
i=4;
i<8;
i++) {
5189 if (!
NIL_P(year_extend)) {
5201 (year == 1900 ?
"small" :
"big"), vtm.year);
5234 buf[1] = (
char)((nsec % 10) << 4);
5238 buf[0] |= (
char)((nsec % 10) << 4);
5250 zone = tobj->vtm.zone;
5251 if (maybe_tzobj_p(
zone)) {
5296 struct time_object *tobj;
5304 VALUE submicro, nano_num, nano_den, offset,
zone, year;
5309#define get_attr(attr, iffound) \
5310 attr = rb_attr_delete(str, id_##attr); \
5311 if (!NIL_P(attr)) { \
5334 for (
i=0;
i<4;
i++) {
5337 for (
i=4;
i<8;
i++) {
5341 if ((p & (1UL<<31)) == 0) {
5351 gmt = (
int)((p >> 30) & 0x1);
5354 year =
INT2FIX(((
int)(p >> 14) & 0xffff) + 1900);
5362 len -= ybuf - (
const char *)
buf;
5363 if (ysize < 0 || ysize >
len)
goto invalid_format;
5373 vtm.mon = ((
int)(p >> 10) & 0xf) + 1;
5374 vtm.mday = (
int)(p >> 5) & 0x1f;
5375 vtm.hour = (
int) p & 0x1f;
5376 vtm.min = (
int)(s >> 26) & 0x3f;
5377 vtm.sec = (
int)(s >> 20) & 0x3f;
5379 vtm.yday = vtm.wday = 0;
5383 usec = (
long)(s & 0xfffff);
5388 if (nano_num !=
Qnil) {
5389 VALUE nano = quov(num_exact(nano_num), num_exact(nano_den));
5392 else if (submicro !=
Qnil) {
5400 if (10 <= (
digit =
ptr[0] >> 4))
goto end_submicro;
5401 nsec +=
digit * 100;
5402 if (10 <= (
digit =
ptr[0] & 0xf))
goto end_submicro;
5406 if (10 <= (
digit =
ptr[1] >> 4))
goto end_submicro;
5412 timew = timegmw(&vtm);
5418 tobj->timew = timew;
5422 else if (!
NIL_P(offset)) {
5423 time_set_utc_offset(
time, offset);
5428 tobj->vtm.zone =
zone;
5462 struct time_object *tobj;
5466 struct time_object *ttm;
5472 GMTIMEW(ttm->timew = tobj->timew,
v);
5473 ttm->timew = wsub(ttm->timew,
v->subsecx);
5489 args[
i++] =
v->year;
5496 case 0: args[
i++] =
Qfalse;
break;
5497 case 1: args[
i++] =
Qtrue;
break;
5498 default: args[
i++] =
Qnil;
break;
5500 args[
i++] = w2v(rb_time_unmagnify(tobj->timew));
5553 struct time_object *torig = get_timeval(
tm);
5577#define tm_subsec tm_zero
5578#define tm_utc_offset tm_zero
5594 p[5], p[4], p[3], p[2], p[1], p[0]);
5650 "sec",
"min",
"hour",
5651 "mday",
"mon",
"year",
5672 VALUE tm, abbr, strftime_args[2];
5675 if (!
NIL_P(abbr))
return abbr;
5677 tm = tm_from_time(rb_cTimeTM,
time);
5682#ifdef SUPPORT_TZINFO_ZONE_ABBREVIATION
5690 strftime_args[1] =
tm;
5833#define rb_intern(str) rb_intern_const(str)
5840 id_nanosecond =
rb_intern(
"nanosecond");
5841 id_microsecond =
rb_intern(
"microsecond");
5842 id_millisecond =
rb_intern(
"millisecond");
5845 id_local_to_utc =
rb_intern(
"local_to_utc");
5846 id_utc_to_local =
rb_intern(
"utc_to_local");
5854 id_find_timezone =
rb_intern(
"find_timezone");
5943#ifdef DEBUG_FIND_TIME_NUMGUESS
5947 rb_cTimeTM = Init_tm(
rb_cTime,
"tm");
rb_encoding * rb_enc_get(VALUE obj)
rb_encoding * rb_locale_encoding(void)
rb_encoding * rb_usascii_encoding(void)
#define rb_enc_str_asciicompat_p(str)
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
#define rb_cmpint(cmp, a, b)
char str[HTML_ESCAPE_MAX_LEN+1]
void rb_include_module(VALUE, VALUE)
VALUE rb_define_class(const char *, VALUE)
Defines a top-level class.
VALUE rb_singleton_class(VALUE)
Returns the singleton class of obj.
VALUE rb_define_class_under(VALUE, const char *, VALUE)
Defines a class under the namespace of outer.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *)
VALUE rb_cObject
Object class.
void rb_raise(VALUE exc, const char *fmt,...)
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
void rb_warn(const char *fmt,...)
VALUE rb_exc_new_str(VALUE, VALUE)
VALUE rb_rescue(VALUE(*)(VALUE), VALUE, VALUE(*)(VALUE, VALUE), VALUE)
An equivalent of rescue clause.
void rb_sys_fail(const char *mesg)
VALUE rb_Float(VALUE)
Equivalent to Kernel#Float in Ruby.
VALUE rb_check_to_int(VALUE)
Tries to convert val into Integer.
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
VALUE rb_obj_class(VALUE)
Equivalent to Object#class in Ruby.
VALUE rb_equal(VALUE, VALUE)
Same as Object#===, case equality.
VALUE rb_to_int(VALUE)
Converts val into Integer.
unsigned char buf[MIME_BUF_SIZE]
void rb_num_zerodiv(void)
VALUE rb_enc_sprintf(rb_encoding *enc, const char *format,...)
VALUE rb_strftime_timespec(const char *format, size_t format_len, rb_encoding *enc, VALUE time, const struct vtm *vtm, struct timespec *ts, int gmt)
VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc, VALUE time, const struct vtm *vtm, VALUE timev, int gmt)
#define MUL_OVERFLOW_FIXWV_P(a, b)
int ruby_marshal_write_long(long x, char *buf)
#define GMTIME(tm, result)
#define wmulquoll(x, y, z)
#define validate_vtm_range(mem, b, e)
#define TZMODE_SET_LOCALTIME(tobj)
#define TIME_TZMODE_UNINITIALIZED
VALUE rb_time_nano_new(time_t sec, long nsec)
#define TZMODE_UTC_P(tobj)
long ruby_marshal_read_long(const char **buf, long len)
#define TZMODE_COPY(tobj1, tobj2)
void rb_timespec_now(struct timespec *ts)
void ruby_reset_leap_second_info(void)
VALUE rb_time_zone_abbreviation(VALUE zone, VALUE time)
NORETURN(static void invalid_utc_offset(void))
SIGNED_VALUE SIGNED_WIDEVALUE
#define GetTimeval(obj, tobj)
VALUE rb_time_succ(VALUE time)
#define DEBUG_REPORT_GUESSRANGE
VALUE rb_time_timespec_new(const struct timespec *ts, int offset)
Returns a time object with UTC/localtime/fixed offset.
struct timespec rb_time_timespec(VALUE time)
PACKED_STRUCT_UNALIGNED(struct time_object { wideval_t timew;struct vtm vtm;unsigned int tzmode:3;unsigned int tm_got:1;})
#define arg_range_check(v)
#define TIME_TZMODE_LOCALTIME
#define LOCALTIME(tm, result)
#define strftimev(fmt, time, enc)
#define TZMODE_SET_UTC(tobj)
VALUE rb_time_new(time_t sec, long usec)
struct timeval rb_time_timeval(VALUE time)
struct timeval rb_time_interval(VALUE num)
VALUE rb_time_num_new(VALUE timev, VALUE off)
#define TZMODE_LOCALTIME_P(tobj)
#define TZMODE_FIXOFF_P(tobj)
#define GetNewTimeval(obj, tobj)
VALUE rb_time_utc_offset(VALUE time)
#define TZMODE_SET_FIXOFF(tobj, off)
struct timespec rb_time_timespec_interval(VALUE num)
#define TIME_INIT_P(tobj)
#define get_attr(attr, iffound)
#define VTM_ISDST_INITVAL
#define MAKE_TM(time, tobj)
#define TYPEOF_TIMEVAL_TV_USEC
#define TYPEOF_TIMEVAL_TV_SEC
int gettimeofday(struct timeval *, struct timezone *)