12 #define _DEFAULT_SOURCE 15 #include <sys/types.h> 30 #if defined(HAVE_SYS_TIME_H) 37 static ID id_divmod, id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
39 static ID id_nanosecond, id_microsecond, id_millisecond, id_nsec, id_usec;
41 #define NDIV(x,y) (-(-((x)+1)/(y))-1) 42 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) 43 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) 44 #define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d)) 45 #define VTM_WDAY_INITVAL (7) 46 #define VTM_ISDST_INITVAL (3) 47 #define TO_GMT_INITVAL (3) 62 if ((
long)x < (
long)y)
64 if ((
long)x > (
long)y)
72 #define ne(x,y) (!eq((x),(y))) 73 #define lt(x,y) (cmp((x),(y)) < 0) 74 #define gt(x,y) (cmp((x),(y)) > 0) 75 #define le(x,y) (cmp((x),(y)) <= 0) 76 #define ge(x,y) (cmp((x),(y)) >= 0) 102 return rb_fix_mul_fix(x, y);
113 return rb_fix_div_fix(x, y);
125 if (
FIXNUM_P(x))
return rb_fix_mod_fix(x, y);
131 #define neg(x) (subv(INT2FIX(0), (x))) 156 #define mulquov(x,y,z) (((y) == (z)) ? (x) : quov(mulv((x),(y)),(z))) 165 rb_fix_divmod_fix(n, d, q, r);
180 # define INT64toNUM(x) LONG2NUM(x) 181 #elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 182 # define INT64toNUM(x) LL2NUM(x) 185 #if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T 190 # define WIDEVALUE_IS_WIDER 1 191 # define UWIDEINT_MAX UINT64_MAX 192 # define WIDEINT_MAX INT64_MAX 193 # define WIDEINT_MIN INT64_MIN 194 # define FIXWINT_P(tv) ((tv) & 1) 195 # define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1) 196 # define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG)) 197 # define FIXWV_MAX (((int64_t)1 << 62) - 1) 198 # define FIXWV_MIN (-((int64_t)1 << 62)) 199 # define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi)) 200 # define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i)) 201 # define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w)) 207 # define WIDEVALUE_IS_WIDER 0 208 # define UWIDEINT_MAX ULONG_MAX 209 # define WIDEINT_MAX LONG_MAX 210 # define WIDEINT_MIN LONG_MIN 211 # define FIXWINT_P(v) FIXNUM_P(v) 212 # define FIXWV_MAX FIXNUM_MAX 213 # define FIXWV_MIN FIXNUM_MIN 214 # define FIXWVABLE(i) FIXABLE(i) 215 # define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i)) 216 # define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w)) 219 #define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1) 220 #define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN) 221 #define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w)) 222 #define MUL_OVERFLOW_FIXWV_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXWV_MIN, FIXWV_MAX) 225 #ifdef STRUCT_WIDEVAL 231 # define WIDEVAL_GET(w) ((w).value) 234 # define WIDEVAL_WRAP(v) (v) 235 # define WIDEVAL_GET(w) (w) 238 #if WIDEVALUE_IS_WIDER 247 # define WINT2WV(wi) wint2wv(wi) 249 # define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi)) 255 #if WIDEVALUE_IS_WIDER 264 #if WIDEVALUE_IS_WIDER 274 else if (sign == -1) {
278 else if (sign == +1) {
294 #if WIDEVALUE_IS_WIDER 300 return v2w_bignum(v);
309 #if WIDEVALUE_IS_WIDER 323 #if WIDEVALUE_IS_WIDER 340 #define wne(x,y) (!weq((x),(y))) 341 #define wlt(x,y) (wcmp((x),(y)) < 0) 342 #define wgt(x,y) (wcmp((x),(y)) > 0) 343 #define wle(x,y) (wcmp((x),(y)) <= 0) 344 #define wge(x,y) (wcmp((x),(y)) >= 0) 349 #if WIDEVALUE_IS_WIDER 355 return v2w(addv(w2v(wx), w2v(wy)));
361 #if WIDEVALUE_IS_WIDER 367 return v2w(subv(w2v(wx), w2v(wy)));
373 #if WIDEVALUE_IS_WIDER 379 return v2w(mulv(w2v(wx), w2v(wy)));
385 #if WIDEVALUE_IS_WIDER 397 return v2w(quov(w2v(wx), w2v(wy)));
400 #define wmulquo(x,y,z) ((WIDEVAL_GET(y) == WIDEVAL_GET(z)) ? (x) : wquo(wmul((x),(y)),(z))) 401 #define wmulquoll(x,y,z) (((y) == (z)) ? (x) : wquo(wmul((x),WINT2WV(y)),WINT2WV(z))) 403 #if WIDEVALUE_IS_WIDER 430 if (d > 0 ? r < 0 : r > 0) {
446 #if WIDEVALUE_IS_WIDER 447 if (wdivmod0(wn, wd, wq, wr))
return;
449 divmodv(w2v(wn), w2v(wd), &vq, &vr);
462 wdivmod(wmul(wx,wy), wz, wq, wr);
468 #if WIDEVALUE_IS_WIDER 470 if (wdivmod0(wx, wy, &q, &dmy))
return q;
472 return v2w(divv(w2v(wx), w2v(wy)));
478 #if WIDEVALUE_IS_WIDER 480 if (wdivmod0(wx, wy, &dmy, &r))
return r;
482 return v2w(modv(w2v(wx), w2v(wy)));
551 #if WIDEVALUE_IS_WIDER 583 #if WIDEVALUE_IS_WIDER 584 if (TIMET_MIN == 0) {
597 return v2w(TIMET2NUM(t));
599 #define TIMET2WV(t) timet2wv(t) 604 #if WIDEVALUE_IS_WIDER 607 if (TIMET_MIN == 0) {
614 if (wi < TIMET_MIN || TIMET_MAX < wi)
620 return NUM2TIMET(w2v(w));
622 #define WV2TIMET(t) wv2timet(t) 627 static int obj2int(
VALUE obj);
631 static VALUE validate_utc_offset(
VALUE utc_offset);
632 static VALUE validate_zone_name(
VALUE zone_name);
633 static void validate_vtm(
struct vtm *vtm);
640 static time_t timegm_noleapsecond(
struct tm *tm);
641 static int tmcmp(
struct tm *a,
struct tm *b);
642 static int vtmcmp(
struct vtm *a,
struct vtm *b);
643 static const char *find_time_t(
struct tm *tptr,
int utc_p, time_t *tp);
645 static struct vtm *localtimew(
wideval_t timew,
struct vtm *result);
647 static int leap_year_p(
long y);
648 #define leap_year_v_p(y) leap_year_p(NUM2LONG(modv((y), INT2FIX(400)))) 651 rb_localtime_r(
const time_t *t,
struct tm *result)
653 #if defined __APPLE__ && defined __LP64__ 654 if (*t != (time_t)(
int)*t)
return NULL;
660 struct tm *tmp = localtime(t);
661 if (tmp) *result = *tmp;
664 #if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM) 668 struct tm tmp = *result;
671 # if defined(HAVE_STRUCT_TM_TM_GMTOFF) 672 gmtoff1 = result->tm_gmtoff;
673 gmtoff2 = tmp.tm_gmtoff;
675 if (*t + gmtoff1 != t2 + gmtoff2)
681 #define LOCALTIME(tm, result) (tzset(),rb_localtime_r((tm), &(result))) 683 #ifndef HAVE_STRUCT_TM_TM_GMTOFF 685 rb_gmtime_r(
const time_t *t,
struct tm *result)
690 struct tm *tmp = gmtime(t);
691 if (tmp) *result = *tmp;
693 #if defined(HAVE_TIMEGM) && defined(LOCALTIME_OVERFLOW_PROBLEM) 694 if (result && *t != timegm(result)) {
700 # define GMTIME(tm, result) rb_gmtime_r((tm), &(result)) 703 static const int common_year_yday_offset[] = {
708 -1 + 31 + 28 + 31 + 30,
709 -1 + 31 + 28 + 31 + 30 + 31,
710 -1 + 31 + 28 + 31 + 30 + 31 + 30,
711 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
712 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
713 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
714 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
715 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
718 static const int leap_year_yday_offset[] = {
723 -1 + 31 + 29 + 31 + 30,
724 -1 + 31 + 29 + 31 + 30 + 31,
725 -1 + 31 + 29 + 31 + 30 + 31 + 30,
726 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
727 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
728 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
729 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
730 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
734 static const int common_year_days_in_month[] = {
735 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
737 static const int leap_year_days_in_month[] = {
738 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
742 calc_tm_yday(
long tm_year,
int tm_mon,
int tm_mday)
744 int tm_year_mod400 = (int)
MOD(tm_year, 400);
745 int tm_yday = tm_mday;
747 if (leap_year_p(tm_year_mod400 + 1900))
748 tm_yday += leap_year_yday_offset[tm_mon];
750 tm_yday += common_year_yday_offset[tm_mon];
756 timegmw_noleapsecond(
struct vtm *vtm)
766 year1900 = subv(vtm->year,
INT2FIX(1900));
768 divmodv(year1900,
INT2FIX(400), &q400, &r400);
771 yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday);
784 +
DIV(year_mod400 - 69, 4)
785 -
DIV(year_mod400 - 1, 100)
786 + (year_mod400 + 299) / 400;
788 vdays = addv(vdays, mulv(q400,
INT2FIX(97)));
789 vdays = addv(vdays, mulv(year1900,
INT2FIX(365)));
790 wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)),
WINT2FIXWV(86400)));
791 wret = wadd(wret, v2w(vtm->subsecx));
801 const char *s = (
const char *)*key;
802 const char **ret = (
const char **)arg;
805 *ret = (
const char *)*value;
814 zone_str(
const char *s)
824 gmtimew_noleapsecond(
wideval_t timew,
struct vtm *vtm)
828 const int *yday_offset;
836 split_second(timew, &timew2, &subsecx);
837 vtm->subsecx = subsecx;
844 vtm->wday = (wday + 4) % 7;
847 vtm->sec = n % 60; n = n / 60;
848 vtm->min = n % 60; n = n / 60;
852 divmodv(timev,
INT2FIX(400*365 + 97), &timev, &v);
853 vtm->year = mulv(timev,
INT2FIX(400));
865 if (30*365+7+31+29-1 <= n) {
879 x = n / (365*100 + 24);
880 n = n % (365*100 + 24);
882 if (30*365+7+31+29-1 <= n) {
895 if (365*2+31+29-1 <= n) {
911 vtm->year = addv(vtm->year,
INT2NUM(y));
914 yday_offset = leap_year_yday_offset;
916 yday_offset = common_year_yday_offset;
918 for (i = 0; i < 12; i++) {
919 if (yday_offset[i] < n) {
921 vtm->mday = n - yday_offset[i];
932 gmtime_with_leapsecond(
const time_t *timep,
struct tm *result)
934 #if defined(HAVE_STRUCT_TM_TM_GMTOFF) 938 int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
945 if (t->tm_gmtoff < 0) {
947 gmtoff = -t->tm_gmtoff;
951 gmtoff = t->tm_gmtoff;
953 gmtoff_sec = (int)(gmtoff % 60);
954 gmtoff = gmtoff / 60;
955 gmtoff_min = (int)(gmtoff % 60);
956 gmtoff = gmtoff / 60;
957 gmtoff_hour = (int)gmtoff;
968 result->tm_sec += gmtoff_sec;
969 if (result->tm_sec < 0) {
970 result->tm_sec += 60;
973 if (60 <= result->tm_sec) {
974 result->tm_sec -= 60;
979 result->tm_min += gmtoff_min;
980 if (result->tm_min < 0) {
981 result->tm_min += 60;
984 if (60 <= result->tm_min) {
985 result->tm_min -= 60;
990 result->tm_hour += gmtoff_hour;
991 if (result->tm_hour < 0) {
992 result->tm_hour += 24;
995 if (24 <= result->tm_hour) {
996 result->tm_hour -= 24;
1002 if (gmtoff_day < 0) {
1003 if (result->tm_yday == 0) {
1004 result->tm_mday = 31;
1005 result->tm_mon = 11;
1007 result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
1009 else if (result->tm_mday == 1) {
1010 const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
1011 leap_year_days_in_month :
1012 common_year_days_in_month;
1014 result->tm_mday = days_in_month[result->tm_mon];
1021 result->tm_wday = (result->tm_wday + 6) % 7;
1024 int leap = leap_year_p(result->tm_year + 1900);
1025 if (result->tm_yday == (leap ? 365 : 364)) {
1028 result->tm_mday = 1;
1029 result->tm_yday = 0;
1031 else if (result->tm_mday == (leap ? leap_year_days_in_month :
1032 common_year_days_in_month)[result->tm_mon]) {
1034 result->tm_mday = 1;
1041 result->tm_wday = (result->tm_wday + 1) % 7;
1044 result->tm_isdst = 0;
1045 result->tm_gmtoff = 0;
1046 #if defined(HAVE_TM_ZONE) 1047 result->tm_zone = (
char *)
"UTC";
1051 return GMTIME(timep, *result);
1055 static long this_year = 0;
1056 static time_t known_leap_seconds_limit;
1057 static int number_of_leap_seconds_known;
1060 init_leap_second_info(
void)
1067 if (this_year == 0) {
1069 struct tm *tm, result;
1074 tm = gmtime_with_leapsecond(&now, &result);
1076 this_year = tm->tm_year;
1078 if (TIMET_MAX - now < (time_t)(366*86400))
1079 known_leap_seconds_limit = TIMET_MAX;
1081 known_leap_seconds_limit = now + (time_t)(366*86400);
1083 if (!gmtime_with_leapsecond(&known_leap_seconds_limit, &result))
1086 vtm.year =
LONG2NUM(result.tm_year + 1900);
1087 vtm.mon = result.tm_mon + 1;
1088 vtm.mday = result.tm_mday;
1089 vtm.hour = result.tm_hour;
1090 vtm.min = result.tm_min;
1091 vtm.sec = result.tm_sec;
1095 timew = timegmw_noleapsecond(&vtm);
1097 number_of_leap_seconds_known =
NUM2INT(w2v(wsub(
TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
1102 timegmw(
struct vtm *vtm)
1112 return timegmw_noleapsecond(vtm);
1114 init_leap_second_info();
1116 timew = timegmw_noleapsecond(vtm);
1118 if (
wlt(rb_time_magnify(
TIMET2WV(known_leap_seconds_limit)), timew)) {
1119 return wadd(timew, rb_time_magnify(
WINT2WV(number_of_leap_seconds_known)));
1123 tm.tm_mon = vtm->mon - 1;
1124 tm.tm_mday = vtm->mday;
1125 tm.tm_hour = vtm->hour;
1126 tm.tm_min = vtm->min;
1127 tm.tm_sec = vtm->sec;
1130 errmsg = find_time_t(&tm, 1, &t);
1133 return wadd(rb_time_magnify(
TIMET2WV(t)), v2w(vtm->subsecx));
1137 gmtimew(
wideval_t timew,
struct vtm *result)
1145 gmtimew_noleapsecond(timew, result);
1149 init_leap_second_info();
1151 if (
wlt(rb_time_magnify(
TIMET2WV(known_leap_seconds_limit)), timew)) {
1152 timew = wsub(timew, rb_time_magnify(
WINT2WV(number_of_leap_seconds_known)));
1153 gmtimew_noleapsecond(timew, result);
1157 split_second(timew, &timew2, &subsecx);
1160 if (!gmtime_with_leapsecond(&t, &tm))
1163 result->year =
LONG2NUM((
long)tm.tm_year + 1900);
1164 result->mon = tm.tm_mon + 1;
1165 result->mday = tm.tm_mday;
1166 result->hour = tm.tm_hour;
1167 result->min = tm.tm_min;
1168 result->sec = tm.tm_sec;
1169 result->subsecx = subsecx;
1170 result->utc_offset =
INT2FIX(0);
1171 result->wday = tm.tm_wday;
1172 result->yday = tm.tm_yday+1;
1173 result->isdst = tm.tm_isdst;
1174 result->zone =
"UTC";
1179 static struct tm *localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
const char **
zone);
1214 static int compat_common_month_table[12][7] = {
1216 { 2034, 2035, 2036, 2031, 2032, 2027, 2033 },
1217 { 2026, 2027, 2033, 2034, 2035, 2030, 2031 },
1218 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1219 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1220 { 2033, 2034, 2035, 2030, 2036, 2026, 2032 },
1221 { 2036, 2026, 2032, 2033, 2034, 2035, 2030 },
1222 { 2035, 2030, 2036, 2026, 2032, 2033, 2034 },
1223 { 2032, 2033, 2034, 2035, 2030, 2036, 2026 },
1224 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1225 { 2034, 2035, 2030, 2036, 2026, 2032, 2033 },
1226 { 2026, 2032, 2033, 2034, 2035, 2030, 2036 },
1227 { 2030, 2036, 2026, 2032, 2033, 2034, 2035 },
1255 static int compat_leap_month_table[7] = {
1257 2032, 2016, 2028, 2012, 2024, 2036, 2020,
1261 calc_wday(
int year,
int month,
int day)
1266 a = (14 - month) / 12;
1267 y = year + 4800 - a;
1268 m = month + 12 * a - 3;
1269 wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
1275 guess_local_offset(
struct vtm *vtm_utc,
int *isdst_ret,
const char **zone_ret)
1292 # if defined(NEGATIVE_TIME_T) 1293 # if SIZEOF_TIME_T <= 4 1295 # define THE_TIME_OLD_ENOUGH ((time_t)0x80000000) 1299 # define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60) 1301 if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
1303 isdst = tm.tm_isdst;
1308 if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
1310 isdst = tm.tm_isdst;
1326 wday = calc_wday(y, vtm_utc->mon, 1);
1327 if (vtm_utc->mon == 2 && leap_year_p(y))
1328 vtm2.year =
INT2FIX(compat_leap_month_table[wday]);
1330 vtm2.year =
INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
1332 timev = w2v(rb_time_unmagnify(timegmw(&vtm2)));
1333 t = NUM2TIMET(timev);
1335 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1337 *isdst_ret = tm.tm_isdst;
1345 static time_t now = 0;
1346 static long now_gmtoff = 0;
1347 static const char *now_zone =
"UTC";
1350 localtime_with_gmtoff_zone(&now, &tm, &now_gmtoff, &now_zone);
1353 *isdst_ret = tm.tm_isdst;
1355 *zone_ret = now_zone;
1361 small_vtm_sub(
struct vtm *vtm1,
struct vtm *vtm2)
1365 off = vtm1->sec - vtm2->sec;
1366 off += (vtm1->min - vtm2->min) * 60;
1367 off += (vtm1->hour - vtm2->hour) * 3600;
1368 if (
ne(vtm1->year, vtm2->year))
1369 off +=
lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
1370 else if (vtm1->mon != vtm2->mon)
1371 off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
1372 else if (vtm1->mday != vtm2->mday)
1373 off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
1379 timelocalw(
struct vtm *vtm)
1385 struct vtm vtm1, vtm2;
1389 long l =
FIX2LONG(vtm->year) - 1900;
1390 if (l < INT_MIN || INT_MAX < l)
1392 tm.tm_year = (int)l;
1395 v = subv(vtm->year,
INT2FIX(1900));
1401 tm.tm_mon = vtm->mon-1;
1402 tm.tm_mday = vtm->mday;
1403 tm.tm_hour = vtm->hour;
1404 tm.tm_min = vtm->min;
1405 tm.tm_sec = vtm->sec;
1408 if (find_time_t(&tm, 0, &t))
1410 return wadd(rb_time_magnify(
TIMET2WV(t)), v2w(vtm->subsecx));
1413 timew1 = timegmw(vtm);
1415 if (!localtimew(timew1, &vtm1))
1418 n = vtmcmp(vtm, &vtm1);
1420 timew1 = wsub(timew1, rb_time_magnify(
WINT2FIXWV(12*3600)));
1421 if (!localtimew(timew1, &vtm1))
1429 timew1 = wsub(timew1, rb_time_magnify(
WINT2FIXWV(24*3600)));
1430 if (!localtimew(timew1, &vtm1))
1434 timew2 = wadd(timew1, rb_time_magnify(
WINT2FIXWV(24*3600)));
1435 if (!localtimew(timew2, &vtm2))
1438 timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
1439 timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
1441 if (weq(timew1, timew2))
1444 if (!localtimew(timew1, &vtm1))
1446 if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
1449 if (!localtimew(timew2, &vtm2))
1451 if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
1455 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew2 : timew1;
1457 return lt(vtm1.utc_offset, vtm2.utc_offset) ? timew1 : timew2;
1461 localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
const char **zone)
1466 #if defined(HAVE_STRUCT_TM_TM_GMTOFF) 1467 *gmtoff = tm.tm_gmtoff;
1476 if (l->tm_year != u->tm_year)
1477 off = l->tm_year < u->tm_year ? -1 : 1;
1478 else if (l->tm_mon != u->tm_mon)
1479 off = l->tm_mon < u->tm_mon ? -1 : 1;
1480 else if (l->tm_mday != u->tm_mday)
1481 off = l->tm_mday < u->tm_mday ? -1 : 1;
1484 off = off * 24 + l->tm_hour - u->tm_hour;
1485 off = off * 60 + l->tm_min - u->tm_min;
1486 off = off * 60 + l->tm_sec - u->tm_sec;
1491 #if defined(HAVE_TM_ZONE) 1493 *zone = zone_str(tm.tm_zone);
1495 *zone = zone_str(
"(NO-TIMEZONE-ABBREVIATION)");
1496 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT) 1497 # if RUBY_MSVCRT_VERSION >= 140 1498 # define tzname _tzname 1499 # define daylight _daylight 1502 *zone = zone_str(tzname[daylight && tm.tm_isdst]);
1506 strftime(buf,
sizeof(buf),
"%Z", &tm);
1507 *zone = zone_str(buf);
1519 timew_out_of_timet_range(
wideval_t timew)
1522 #if WIDEVALUE_IS_WIDER && SIZEOF_TIME_T < SIZEOF_INT64_T 1531 #if SIZEOF_TIME_T == SIZEOF_INT64_T 1534 if (~(time_t)0 <= 0) {
1544 timexv = w2v(timew);
1552 localtimew(
wideval_t timew,
struct vtm *result)
1554 VALUE subsecx, offset;
1558 if (!timew_out_of_timet_range(timew)) {
1564 split_second(timew, &timew2, &subsecx);
1568 if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1569 result->year =
LONG2NUM((
long)tm.tm_year + 1900);
1570 result->mon = tm.tm_mon + 1;
1571 result->mday = tm.tm_mday;
1572 result->hour = tm.tm_hour;
1573 result->min = tm.tm_min;
1574 result->sec = tm.tm_sec;
1575 result->subsecx = subsecx;
1576 result->wday = tm.tm_wday;
1577 result->yday = tm.tm_yday+1;
1578 result->isdst = tm.tm_isdst;
1579 result->utc_offset =
LONG2NUM(gmtoff);
1580 result->zone = zone;
1585 if (!gmtimew(timew, result))
1588 offset = guess_local_offset(result, &isdst, &zone);
1590 if (!gmtimew(wadd(timew, rb_time_magnify(v2w(offset))), result))
1593 result->utc_offset = offset;
1594 result->isdst = isdst;
1595 result->zone = zone;
1607 #define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj)) 1608 #define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj)) 1610 #define IsTimeval(obj) rb_typeddata_is_kind_of((obj), &time_data_type) 1611 #define TIME_INIT_P(tobj) ((tobj)->gmt != TO_GMT_INITVAL) 1613 #define TIME_UTC_P(tobj) ((tobj)->gmt == 1) 1614 #define TIME_SET_UTC(tobj) ((tobj)->gmt = 1) 1616 #define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0) 1617 #define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0) 1619 #define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2) 1620 #define TIME_SET_FIXOFF(tobj, off) \ 1622 (tobj)->vtm.utc_offset = (off), \ 1623 (tobj)->vtm.zone = NULL) 1625 #define TIME_COPY_GMT(tobj1, tobj2) \ 1626 ((tobj1)->gmt = (tobj2)->gmt, \ 1627 (tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \ 1628 (tobj1)->vtm.zone = (tobj2)->vtm.zone) 1630 static VALUE time_get_tm(
VALUE,
struct time_object *);
1631 #define MAKE_TM(time, tobj) \ 1633 if ((tobj)->tm_got == 0) { \ 1634 time_get_tm((time), (tobj)); \ 1639 time_mark(
void *ptr)
1641 struct time_object *tobj = ptr;
1650 time_memsize(
const void *tobj)
1652 return sizeof(
struct time_object);
1662 time_s_alloc(
VALUE klass)
1665 struct time_object *tobj;
1675 static struct time_object *
1676 get_timeval(
VALUE obj)
1678 struct time_object *tobj;
1686 static struct time_object *
1687 get_new_timeval(
VALUE obj)
1689 struct time_object *tobj;
1698 time_modify(
VALUE time)
1705 timespec2timew(
struct timespec *ts)
1716 timew2timespec(wideval_t timew)
1722 if (timew_out_of_timet_range(timew))
1724 split_second(timew, &timew2, &subsecx);
1731 timew2timespec_exact(wideval_t timew,
struct timespec *ts)
1737 if (timew_out_of_timet_range(timew))
1739 split_second(timew, &timew2, &subsecx);
1751 #ifdef HAVE_CLOCK_GETTIME 1768 time_init_0(
VALUE time)
1770 struct time_object *tobj;
1779 tobj->timew = timespec2timew(&ts);
1787 struct time_object *tobj;
1788 off = num_exact(off);
1800 vtm_add_offset(
struct vtm *vtm,
VALUE off)
1807 vtm->utc_offset = subv(vtm->utc_offset, off);
1816 divmodv(off,
INT2FIX(1), &off, &subsec);
1817 divmodv(off,
INT2FIX(60), &off, &v);
1819 divmodv(off,
INT2FIX(60), &off, &v);
1821 divmodv(off,
INT2FIX(24), &off, &v);
1825 subsec =
neg(subsec);
1834 vtm->subsecx = addv(vtm->subsecx, w2v(rb_time_magnify(v2w(subsec))));
1887 if (vtm->mon == 1 && vtm->mday == 1) {
1890 vtm->year = subv(vtm->year,
INT2FIX(1));
1893 else if (vtm->mday == 1) {
1895 leap_year_days_in_month :
1896 common_year_days_in_month;
1898 vtm->mday = days_in_month[vtm->mon-1];
1905 vtm->wday = (vtm->wday + 6) % 7;
1909 if (vtm->mon == 12 && vtm->mday == 31) {
1910 vtm->year = addv(vtm->year,
INT2FIX(1));
1915 else if (vtm->mday == (leap ? leap_year_days_in_month :
1916 common_year_days_in_month)[vtm->mon-1]) {
1925 vtm->wday = (vtm->wday + 1) % 7;
1931 utc_offset_arg(
VALUE arg)
1943 if (s[6] !=
':')
goto invalid_utc_offset;
1945 n += (s[7] * 10 + s[8] -
'0' * 11);
1947 if (s[0] !=
'+' && s[0] !=
'-')
goto invalid_utc_offset;
1949 if (s[3] !=
':')
goto invalid_utc_offset;
1951 if (s[4] >
'5')
goto invalid_utc_offset;
1954 goto invalid_utc_offset;
1956 n += (s[1] * 10 + s[2] -
'0' * 11) * 3600;
1957 n += (s[4] * 10 + s[5] -
'0' * 11) * 60;
1963 return num_exact(arg);
1972 struct time_object *tobj;
1979 rb_scan_args(argc, argv,
"16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
1981 vtm.year = obj2vint(v[0]);
1983 vtm.mon =
NIL_P(v[1]) ? 1 : month_arg(v[1]);
1985 vtm.mday =
NIL_P(v[2]) ? 1 : obj2ubits(v[2], 5);
1987 vtm.hour =
NIL_P(v[3]) ? 0 : obj2ubits(v[3], 5);
1989 vtm.min =
NIL_P(v[4]) ? 0 : obj2ubits(v[4], 6);
1997 vtm.sec = obj2subsecx(v[5], &subsecx);
1998 vtm.subsecx = subsecx;
2002 vtm.utc_offset =
Qnil;
2010 vtm.utc_offset = utc_offset_arg(arg);
2021 if (!
NIL_P(vtm.utc_offset)) {
2022 VALUE off = vtm.utc_offset;
2023 vtm_add_offset(&vtm,
neg(off));
2024 vtm.utc_offset =
Qnil;
2025 tobj->timew = timegmw(&vtm);
2026 return time_set_utc_offset(time, off);
2029 tobj->timew = timelocalw(&vtm);
2030 return time_localtime(time);
2083 return time_init_0(time);
2085 return time_init_1(argc, argv, time);
2089 time_overflow_p(time_t *secp,
long *nsecp)
2095 if (nsec >= 1000000000) {
2096 sec2 = nsec / 1000000000;
2097 if (TIMET_MAX - sec2 < sec) {
2100 nsec -= sec2 * 1000000000;
2103 else if (nsec < 0) {
2104 sec2 =
NDIV(nsec,1000000000);
2105 if (sec < TIMET_MIN - sec2) {
2108 nsec -= sec2 * 1000000000;
2111 #ifndef NEGATIVE_TIME_T 2120 nsec2timew(time_t sec,
long nsec)
2123 time_overflow_p(&sec, &nsec);
2126 return timespec2timew(&ts);
2130 time_new_timew(
VALUE klass, wideval_t timew)
2132 VALUE time = time_s_alloc(klass);
2133 struct time_object *tobj;
2137 tobj->timew = timew;
2147 if (usec >= 1000000) {
2148 long sec2 = usec / 1000000;
2149 if (sec > TIMET_MAX - sec2) {
2152 usec -= sec2 * 1000000;
2155 else if (usec < 0) {
2156 long sec2 =
NDIV(usec,1000000);
2157 if (sec < TIMET_MIN - sec2) {
2160 usec -= sec2 * 1000000;
2164 timew = nsec2timew(sec, usec * 1000);
2165 return time_new_timew(
rb_cTime, timew);
2172 return time_new_timew(
rb_cTime, nsec2timew(sec, nsec));
2183 struct time_object *tobj;
2186 if (-86400 < offset && offset < 86400) {
2190 else if (offset == INT_MAX) {
2192 else if (offset == INT_MAX-1) {
2206 VALUE time = time_new_timew(
rb_cTime, rb_time_magnify(v2w(timev)));
2209 off = utc_offset_arg(off);
2210 validate_utc_offset(off);
2211 time_set_utc_offset(time, off);
2219 time_timespec(VALUE num, int interval)
2222 const char *
const tstr = interval ?
"time interval" :
"time";
2225 #ifndef NEGATIVE_TIME_T 2230 t.
tv_sec = NUM2TIMET(num);
2231 if (interval && t.
tv_sec < 0)
2244 if (t.
tv_nsec >= 1000000000) {
2249 else if ((t.
tv_nsec = (
int)(-d*1e9+0.5)) > 0) {
2260 t.
tv_sec = NUM2TIMET(num);
2261 if (interval && t.
tv_sec < 0)
2272 if (interval && t.
tv_sec < 0)
2286 time_timeval(VALUE num, int interval)
2291 ts = time_timespec(num, interval);
2301 return time_timeval(num,
TRUE);
2307 struct time_object *tobj;
2313 ts = timew2timespec(tobj->timew);
2318 return time_timeval(time,
FALSE);
2324 struct time_object *tobj;
2329 t = timew2timespec(tobj->timew);
2332 return time_timespec(time,
FALSE);
2346 time_s_now(VALUE klass)
2352 get_scale(VALUE unit) {
2353 if (unit ==
ID2SYM(id_nanosecond) || unit ==
ID2SYM(id_nsec)) {
2356 else if (unit ==
ID2SYM(id_microsecond) || unit ==
ID2SYM(id_usec)) {
2359 else if (unit ==
ID2SYM(id_millisecond)) {
2397 time_s_at(
int argc, VALUE *argv, VALUE klass)
2399 VALUE time, t, unit =
Qundef;
2402 if (
rb_scan_args(argc, argv,
"12", &time, &t, &unit) >= 2) {
2403 int scale = argc == 3 ? get_scale(unit) : 1000000;
2404 time = num_exact(time);
2407 t = time_new_timew(klass, timew);
2410 struct time_object *tobj, *tobj2;
2412 t = time_new_timew(klass, tobj->timew);
2417 timew = rb_time_magnify(v2w(num_exact(time)));
2418 t = time_new_timew(klass, timew);
2424 static const char months[][4] = {
2425 "jan",
"feb",
"mar",
"apr",
"may",
"jun",
2426 "jul",
"aug",
"sep",
"oct",
"nov",
"dec",
2440 obj2ubits(VALUE obj,
size_t bits)
2443 const uint32_t usable_mask = ~(u32max << bits);
2445 int tmp = obj2int(obj);
2450 if ((rv & usable_mask) != rv)
2469 obj2subsecx(VALUE obj, VALUE *subsecx)
2478 divmodv(num_exact(obj),
INT2FIX(1), &obj, &subsec);
2479 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2481 return obj2ubits(obj, 6);
2485 usec2subsecx(VALUE obj)
2495 month_arg(VALUE arg)
2502 for (i=0; i<12; i++) {
2512 if (
'0' <= c && c <=
'9') {
2513 mon = obj2ubits(s, 4);
2518 mon = obj2ubits(arg, 4);
2524 validate_utc_offset(VALUE utc_offset)
2532 validate_zone_name(VALUE zone_name)
2539 validate_vtm(
struct vtm *vtm)
2541 #define validate_vtm_range(mem, b, e) \ 2542 ((vtm->mem < b || vtm->mem > e) ? \ 2543 rb_raise(rb_eArgError, #mem" out of range") : (void)0) 2551 if (!
NIL_P(vtm->utc_offset)) validate_utc_offset(vtm->utc_offset);
2552 #undef validate_vtm_range 2556 time_arg(
int argc, VALUE *argv,
struct vtm *vtm)
2568 vtm->utc_offset =
Qnil;
2582 vtm->isdst =
RTEST(argv[8]) ? 1 : 0;
2585 rb_scan_args(argc, argv,
"17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
2592 vtm->year = obj2vint(v[0]);
2598 vtm->mon = month_arg(v[1]);
2605 vtm->mday = obj2ubits(v[2], 5);
2608 vtm->hour =
NIL_P(v[3])?0:obj2ubits(v[3], 5);
2610 vtm->min =
NIL_P(v[4])?0:obj2ubits(v[4], 6);
2612 if (!
NIL_P(v[6]) && argc == 7) {
2613 vtm->sec =
NIL_P(v[5])?0:obj2ubits(v[5],6);
2614 subsecx = usec2subsecx(v[6]);
2622 vtm->sec = obj2subsecx(v[5], &subsecx);
2625 vtm->subsecx = subsecx;
2634 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
2638 timegm_noleapsecond(
struct tm *tm)
2640 long tm_year = tm->tm_year;
2641 int tm_yday = tm->tm_mday;
2642 if (leap_year_p(tm_year + 1900))
2643 tm_yday += leap_year_yday_offset[tm->tm_mon];
2645 tm_yday += common_year_yday_offset[tm->tm_mon];
2653 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
2657 DIV(tm_year-1,100) +
2658 DIV(tm_year+299,400))*86400;
2662 #define DEBUG_FIND_TIME_NUMGUESS 2663 #define DEBUG_GUESSRANGE 2666 #ifdef DEBUG_GUESSRANGE 2667 #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)) 2669 #define DEBUG_REPORT_GUESSRANGE 2672 #ifdef DEBUG_FIND_TIME_NUMGUESS 2673 #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++, 2674 static unsigned long long find_time_numguess;
2676 static VALUE find_time_numguess_getter(
void)
2678 return ULL2NUM(find_time_numguess);
2681 #define DEBUG_FIND_TIME_NUMGUESS_INC 2685 find_time_t(
struct tm *tptr,
int utc_p, time_t *tp)
2687 time_t guess, guess0, guess_lo, guess_hi;
2688 struct tm *tm, tm0, tm_lo, tm_hi;
2695 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result))) 2697 guess_lo = TIMET_MIN;
2698 guess_hi = TIMET_MAX;
2700 find_dst = 0 < tptr->tm_isdst;
2702 #if defined(HAVE_MKTIME) 2704 if (!utc_p && (guess = mktime(&tm0)) != -1) {
2706 if (tm && tmcmp(tptr, tm) == 0) {
2713 if (tm0.tm_mon < 0) {
2720 else if (11 < tm0.tm_mon) {
2727 else if (tm0.tm_mday < 1) {
2733 else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
2734 leap_year_days_in_month :
2735 common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
2741 else if (tm0.tm_hour < 0) {
2746 else if (23 < tm0.tm_hour) {
2751 else if (tm0.tm_min < 0) {
2755 else if (59 < tm0.tm_min) {
2759 else if (tm0.tm_sec < 0) {
2762 else if (60 < tm0.tm_sec) {
2767 guess0 = guess = timegm_noleapsecond(&tm0);
2770 d = tmcmp(tptr, tm);
2771 if (d == 0) {
goto found; }
2774 guess -= 24 * 60 * 60;
2778 guess += 24 * 60 * 60;
2781 if (guess_lo < guess && guess < guess_hi && (tm =
GUESS(&guess)) !=
NULL) {
2782 d = tmcmp(tptr, tm);
2783 if (d == 0) {
goto found; }
2792 tm =
GUESS(&guess_lo);
2793 if (!tm)
goto error;
2794 d = tmcmp(tptr, tm);
2795 if (d < 0)
goto out_of_range;
2796 if (d == 0) { guess = guess_lo;
goto found; }
2799 tm =
GUESS(&guess_hi);
2800 if (!tm)
goto error;
2801 d = tmcmp(tptr, tm);
2802 if (d > 0)
goto out_of_range;
2803 if (d == 0) { guess = guess_hi;
goto found; }
2810 while (guess_lo + 1 < guess_hi) {
2813 guess = guess_lo / 2 + guess_hi / 2;
2814 if (guess <= guess_lo)
2815 guess = guess_lo + 1;
2816 else if (guess >= guess_hi)
2817 guess = guess_hi - 1;
2822 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
2823 guess = guess_hi - (guess0_hi - guess0);
2824 if (guess == guess_hi)
2828 else if (status == 2) {
2829 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
2830 guess = guess_lo + (guess0 - guess0_lo);
2831 if (guess == guess_lo)
2835 if (guess <= guess_lo || guess_hi <= guess) {
2837 #ifdef DEBUG_GUESSRANGE 2838 if (guess <= guess_lo) fprintf(stderr,
"too small guess: %ld <= %ld\n", guess, guess_lo);
2839 if (guess_hi <= guess) fprintf(stderr,
"too big guess: %ld <= %ld\n", guess_hi, guess);
2846 if (!tm)
goto error;
2848 d = tmcmp(tptr, tm);
2866 guess2 = guess - 2 * 60 * 60;
2869 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
2870 tptr->tm_min != tm->tm_min ||
2871 tptr->tm_sec != tm->tm_sec) {
2872 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
2873 (tm->tm_min - tptr->tm_min) * 60 +
2874 (tm->tm_sec - tptr->tm_sec);
2875 if (tptr->tm_mday != tm->tm_mday)
2876 guess2 += 24 * 60 * 60;
2877 if (guess != guess2) {
2879 if (tm && tmcmp(tptr, tm) == 0) {
2891 guess2 = guess + 2 * 60 * 60;
2894 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
2895 tptr->tm_min != tm->tm_min ||
2896 tptr->tm_sec != tm->tm_sec) {
2897 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
2898 (tm->tm_min - tptr->tm_min) * 60 +
2899 (tm->tm_sec - tptr->tm_sec);
2900 if (tptr->tm_mday != tm->tm_mday)
2901 guess2 -= 24 * 60 * 60;
2902 if (guess != guess2) {
2904 if (tm && tmcmp(tptr, tm) == 0) {
2929 tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
2932 ((tptr->tm_year - tm_lo.tm_year) * 365 +
2933 ((tptr->tm_year-69)/4) -
2934 ((tptr->tm_year-1)/100) +
2935 ((tptr->tm_year+299)/400) -
2936 ((tm_lo.tm_year-69)/4) +
2937 ((tm_lo.tm_year-1)/100) -
2938 ((tm_lo.tm_year+299)/400) +
2940 tm_lo.tm_yday) * 86400 +
2941 (tptr->tm_hour - tm_lo.tm_hour) * 3600 +
2942 (tptr->tm_min - tm_lo.tm_min) * 60 +
2943 (tptr->tm_sec - (tm_lo.tm_sec == 60 ? 59 : tm_lo.tm_sec));
2948 return "time out of range";
2951 return "gmtime/localtime error";
2955 vtmcmp(
struct vtm *a,
struct vtm *b)
2957 if (
ne(a->year, b->year))
2958 return lt(a->year, b->year) ? -1 : 1;
2959 else if (a->mon != b->mon)
2960 return a->mon < b->mon ? -1 : 1;
2961 else if (a->mday != b->mday)
2962 return a->mday < b->mday ? -1 : 1;
2963 else if (a->hour != b->hour)
2964 return a->hour < b->hour ? -1 : 1;
2965 else if (a->min != b->min)
2966 return a->min < b->min ? -1 : 1;
2967 else if (a->sec != b->sec)
2968 return a->sec < b->sec ? -1 : 1;
2969 else if (
ne(a->subsecx, b->subsecx))
2970 return lt(a->subsecx, b->subsecx) ? -1 : 1;
2976 tmcmp(
struct tm *a,
struct tm *b)
2978 if (a->tm_year != b->tm_year)
2979 return a->tm_year < b->tm_year ? -1 : 1;
2980 else if (a->tm_mon != b->tm_mon)
2981 return a->tm_mon < b->tm_mon ? -1 : 1;
2982 else if (a->tm_mday != b->tm_mday)
2983 return a->tm_mday < b->tm_mday ? -1 : 1;
2984 else if (a->tm_hour != b->tm_hour)
2985 return a->tm_hour < b->tm_hour ? -1 : 1;
2986 else if (a->tm_min != b->tm_min)
2987 return a->tm_min < b->tm_min ? -1 : 1;
2988 else if (a->tm_sec != b->tm_sec)
2989 return a->tm_sec < b->tm_sec ? -1 : 1;
2995 time_utc_or_local(
int argc, VALUE *argv,
int utc_p, VALUE klass)
3000 time_arg(argc, argv, &vtm);
3002 time = time_new_timew(klass, timegmw(&vtm));
3004 time = time_new_timew(klass, timelocalw(&vtm));
3005 if (utc_p)
return time_gmtime(time);
3006 return time_localtime(time);
3042 time_s_mkutc(
int argc, VALUE *argv, VALUE klass)
3044 return time_utc_or_local(argc, argv,
TRUE, klass);
3073 time_s_mktime(
int argc, VALUE *argv, VALUE klass)
3075 return time_utc_or_local(argc, argv,
FALSE, klass);
3092 time_to_i(VALUE time)
3094 struct time_object *tobj;
3116 time_to_f(VALUE time)
3118 struct time_object *tobj;
3121 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3140 time_to_r(VALUE time)
3142 struct time_object *tobj;
3146 v = w2v(rb_time_unmagnify(tobj->timew));
3166 time_usec(VALUE time)
3168 struct time_object *tobj;
3197 time_nsec(VALUE time)
3199 struct time_object *tobj;
3225 time_subsec(VALUE time)
3227 struct time_object *tobj;
3259 time_cmp(VALUE time1, VALUE time2)
3261 struct time_object *tobj1, *tobj2;
3267 n = wcmp(tobj1->timew, tobj2->timew);
3272 if (n == 0)
return INT2FIX(0);
3286 time_eql(VALUE time1, VALUE time2)
3288 struct time_object *tobj1, *tobj2;
3293 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3317 time_utc_p(VALUE time)
3319 struct time_object *tobj;
3336 time_hash(VALUE time)
3338 struct time_object *tobj;
3341 return rb_hash(w2v(tobj->timew));
3346 time_init_copy(VALUE copy, VALUE time)
3348 struct time_object *tobj, *tcopy;
3353 MEMCPY(tcopy, tobj,
struct time_object, 1);
3359 time_dup(VALUE time)
3362 time_init_copy(dup, time);
3367 time_localtime(VALUE time)
3369 struct time_object *tobj;
3381 if (!localtimew(tobj->timew, &vtm))
3411 time_localtime_m(
int argc, VALUE *argv, VALUE time)
3417 off = utc_offset_arg(off);
3418 validate_utc_offset(off);
3420 time_set_utc_offset(time, off);
3421 return time_fixoff(time);
3424 return time_localtime(time);
3446 time_gmtime(VALUE time)
3448 struct time_object *tobj;
3460 if (!gmtimew(tobj->timew, &vtm))
3470 time_fixoff(VALUE time)
3472 struct time_object *tobj;
3486 off = tobj->vtm.utc_offset;
3490 if (!gmtimew(tobj->timew, &vtm))
3494 vtm_add_offset(&tobj->vtm, off);
3530 time_getlocaltime(
int argc, VALUE *argv, VALUE time)
3536 off = utc_offset_arg(off);
3537 validate_utc_offset(off);
3539 time = time_dup(time);
3540 time_set_utc_offset(time, off);
3541 return time_fixoff(time);
3544 return time_localtime(time_dup(time));
3562 time_getgmtime(VALUE time)
3564 return time_gmtime(time_dup(time));
3568 time_get_tm(VALUE time,
struct time_object *tobj)
3570 if (
TIME_UTC_P(tobj))
return time_gmtime(time);
3572 return time_localtime(time);
3575 static VALUE strftime_cstr(
const char *fmt,
size_t len, VALUE time,
rb_encoding *enc);
3576 #define strftimev(fmt, time, enc) strftime_cstr((fmt), rb_strlen_lit(fmt), (time), (enc)) 3590 time_asctime(VALUE time)
3612 time_to_s(VALUE time)
3614 struct time_object *tobj;
3624 time_add(
struct time_object *tobj, VALUE torig, VALUE offset,
int sign)
3627 offset = num_exact(offset);
3629 result = time_new_timew(
rb_cTime, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
3631 result = time_new_timew(
rb_cTime, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
3637 VALUE off = tobj->vtm.utc_offset;
3661 time_plus(VALUE time1, VALUE time2)
3663 struct time_object *tobj;
3669 return time_add(tobj, time1, time2, 1);
3688 time_minus(VALUE time1, VALUE time2)
3690 struct time_object *tobj;
3694 struct time_object *tobj2;
3697 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
3699 return time_add(tobj, time1, time2, -1);
3720 struct time_object *tobj;
3721 struct time_object *tobj2;
3723 rb_warn(
"Time#succ is obsolete; use time + 1");
3731 #define time_succ rb_time_succ 3771 time_round(
int argc, VALUE *argv, VALUE time)
3773 VALUE ndigits, v, a, b, den;
3775 struct time_object *tobj;
3789 v = w2v(rb_time_unmagnify(tobj->timew));
3802 return time_add(tobj, time, v, -1);
3804 return time_add(tobj, time, subv(den, v), 1);
3822 time_sec(VALUE time)
3824 struct time_object *tobj;
3828 return INT2FIX(tobj->vtm.sec);
3842 time_min(VALUE time)
3844 struct time_object *tobj;
3848 return INT2FIX(tobj->vtm.min);
3862 time_hour(VALUE time)
3864 struct time_object *tobj;
3868 return INT2FIX(tobj->vtm.hour);
3884 time_mday(VALUE time)
3886 struct time_object *tobj;
3890 return INT2FIX(tobj->vtm.mday);
3906 time_mon(VALUE time)
3908 struct time_object *tobj;
3912 return INT2FIX(tobj->vtm.mon);
3926 time_year(VALUE time)
3928 struct time_object *tobj;
3932 return tobj->vtm.year;
3954 time_wday(VALUE time)
3956 struct time_object *tobj;
3960 return INT2FIX((
int)tobj->vtm.wday);
3963 #define wday_p(n) {\ 3964 struct time_object *tobj;\ 3965 GetTimeval(time, tobj);\ 3966 MAKE_TM(time, tobj);\ 3967 return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\ 3981 time_sunday(VALUE time)
3997 time_monday(VALUE time)
4013 time_tuesday(VALUE time)
4029 time_wednesday(VALUE time)
4045 time_thursday(VALUE time)
4061 time_friday(VALUE time)
4077 time_saturday(VALUE time)
4093 time_yday(VALUE time)
4095 struct time_object *tobj;
4099 return INT2FIX(tobj->vtm.yday);
4128 time_isdst(VALUE time)
4130 struct time_object *tobj;
4138 time_zone_name(
const char *zone)
4164 time_zone(VALUE time)
4166 struct time_object *tobj;
4174 if (tobj->vtm.zone ==
NULL)
4177 return time_zone_name(tobj->vtm.zone);
4196 time_utc_offset(VALUE time)
4198 struct time_object *tobj;
4207 return tobj->vtm.utc_offset;
4229 time_to_a(VALUE time)
4231 struct time_object *tobj;
4249 rb_strftime_alloc(
const char *format,
size_t format_len,
rb_encoding *enc,
4250 struct vtm *vtm, wideval_t timew,
int gmt)
4255 if (!timew2timespec_exact(timew, &ts))
4256 timev = w2v(rb_time_unmagnify(timew));
4262 return rb_strftime(format, format_len, enc, vtm, timev, gmt);
4267 strftime_cstr(
const char *fmt,
size_t len, VALUE time,
rb_encoding *enc)
4269 struct time_object *tobj;
4274 str = rb_strftime_alloc(fmt, len, enc, &tobj->vtm, tobj->timew,
TIME_UTC_P(tobj));
4467 time_strftime(VALUE time, VALUE format)
4469 struct time_object *tobj;
4486 rb_warning(
"strftime called with empty format string");
4490 VALUE str = rb_strftime_alloc(fmt, len, enc, &tobj->vtm, tobj->timew,
4500 time_mdump(VALUE time)
4502 struct time_object *tobj;
4511 VALUE subsecx, nano, subnano, v;
4515 gmtimew(tobj->timew, &vtm);
4519 if (year < 1900 || 1900+0xffff < year)
4526 subsecx = vtm.subsecx;
4529 divmodv(nano,
INT2FIX(1), &v, &subnano);
4534 nano = addv(
LONG2FIX(nsec), subnano);
4542 s = (
unsigned long)vtm.min << 26 |
4546 for (i=0; i<4; i++) {
4547 buf[i] = (
unsigned char)p;
4550 for (i=4; i<8; i++) {
4551 buf[i] = (
unsigned char)s;
4576 int len = (int)
sizeof(buf);
4577 buf[1] = (char)((nsec % 10) << 4);
4579 buf[0] = (char)(nsec % 10);
4581 buf[0] |= (char)((nsec % 10) << 4);
4587 VALUE off = time_utc_offset(time),
div,
mod;
4593 if (tobj->vtm.zone) {
4594 rb_ivar_set(str, id_zone, time_zone_name(tobj->vtm.zone));
4601 time_dump(
int argc, VALUE *argv, VALUE time)
4606 str = time_mdump(time);
4613 time_mload(VALUE time, VALUE str)
4615 struct time_object *tobj;
4623 VALUE submicro, nano_num, nano_den, offset, zone;
4628 #define get_attr(attr, iffound) \ 4629 attr = rb_attr_delete(str, id_##attr); \ 4630 if (!NIL_P(attr)) { \ 4651 for (i=0; i<4; i++) {
4652 p |= (
unsigned long)buf[i]<<(8*i);
4654 for (i=4; i<8; i++) {
4655 s |= (
unsigned long)buf[i]<<(8*(i-4));
4658 if ((p & (1UL<<31)) == 0) {
4668 gmt = (int)((p >> 30) & 0x1);
4670 vtm.year =
INT2FIX(((
int)(p >> 14) & 0xffff) + 1900);
4671 vtm.mon = ((int)(p >> 10) & 0xf) + 1;
4672 vtm.mday = (int)(p >> 5) & 0x1f;
4673 vtm.hour = (int) p & 0x1f;
4674 vtm.min = (int)(s >> 26) & 0x3f;
4675 vtm.sec = (int)(s >> 20) & 0x3f;
4677 vtm.yday = vtm.wday = 0;
4681 usec = (long)(s & 0xfffff);
4686 if (nano_num !=
Qnil) {
4687 VALUE nano = quov(num_exact(nano_num), num_exact(nano_den));
4690 else if (submicro !=
Qnil) {
4698 if (10 <= (digit = ptr[0] >> 4))
goto end_submicro;
4699 nsec += digit * 100;
4700 if (10 <= (digit = ptr[0] & 0xf))
goto end_submicro;
4704 if (10 <= (digit = ptr[1] >> 4))
goto end_submicro;
4710 timew = timegmw(&vtm);
4716 tobj->timew = timew;
4720 else if (!
NIL_P(offset)) {
4721 time_set_utc_offset(time, offset);
4736 time_load(VALUE klass, VALUE str)
4738 VALUE time = time_s_alloc(klass);
4740 time_mload(time, str);
4836 #define rb_intern(str) rb_intern_const(str) 4846 id_nanosecond =
rb_intern(
"nanosecond");
4847 id_microsecond =
rb_intern(
"microsecond");
4848 id_millisecond =
rb_intern(
"millisecond");
4937 #ifdef DEBUG_FIND_TIME_NUMGUESS #define STRNCASECMP(s1, s2, n)
VALUE rb_big_modulo(VALUE x, VALUE y)
VALUE rb_external_str_with_enc(VALUE str, rb_encoding *eenc)
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
void rb_warn(const char *fmt,...)
VALUE rb_ary_entry(VALUE ary, long offset)
int gettimeofday(struct timeval *, struct timezone *)
#define RUBY_TYPED_FREE_IMMEDIATELY
void rb_define_virtual_variable(const char *, VALUE(*)(ANYARGS), void(*)(ANYARGS))
VALUE rb_check_to_int(VALUE)
Tries to convert val into Integer.
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp)
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
void rb_timespec_now(struct timespec *ts)
#define GetTimeval(obj, tobj)
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_time_timespec_new(const struct timespec *ts, int offset)
Returns a time object with UTC/localtime/fixed offset.
#define OBJ_INIT_COPY(obj, orig)
#define TypedData_Get_Struct(obj, type, data_type, sval)
VALUE rb_big_plus(VALUE x, VALUE y)
struct timeval rb_time_interval(VALUE num)
void rb_define_private_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
void rb_check_trusted(VALUE obj)
VALUE rb_strftime_timespec(const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, struct timespec *ts, int gmt)
#define DEBUG_REPORT_GUESSRANGE
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
#define INTEGER_PACK_NATIVE_BYTE_ORDER
VALUE rb_time_succ(VALUE time)
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
VALUE rb_strftime(const char *format, size_t format_len, rb_encoding *enc, const struct vtm *vtm, VALUE timev, int gmt)
VALUE rb_rescue(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*r_proc)(ANYARGS), VALUE data2)
An equivalent of rescue clause.
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
void rb_include_module(VALUE klass, VALUE module)
void rb_gc_mark(VALUE ptr)
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg)
#define TIME_LOCALTIME_P(tobj)
#define VTM_ISDST_INITVAL
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
VALUE rb_singleton_class(VALUE obj)
Returns the singleton class of obj.
VALUE rb_obj_class(VALUE)
call-seq: obj.class -> class
#define RB_TYPE_P(obj, type)
unsigned long long uint64_t
#define validate_vtm_range(mem, b, e)
#define GetNewTimeval(obj, tobj)
VALUE rb_equal(VALUE, VALUE)
call-seq: obj === other -> true or false
RUBY_EXTERN VALUE rb_cObject
#define get_attr(attr, iffound)
VALUE rb_time_new(time_t sec, long usec)
#define wmulquoll(x, y, z)
VALUE rb_str_to_inum(VALUE str, int base, int badcheck)
#define TIME_SET_UTC(tobj)
#define LOCALTIME(tm, result)
#define TIME_FIXOFF_P(tobj)
VALUE rb_big_cmp(VALUE x, VALUE y)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
struct tm * localtime_r(const time_t *, struct tm *)
#define GMTIME(tm, result)
PACKED_STRUCT_UNALIGNED(struct time_object { wideval_t timew;struct vtm vtm;uint8_t gmt:3;uint8_t tm_got:1;})
#define TIME_INIT_P(tobj)
#define MEMCPY(p1, p2, type, n)
void rb_num_zerodiv(void)
void rb_sys_fail(const char *mesg)
VALUE rb_big_minus(VALUE x, VALUE y)
VALUE rb_big_div(VALUE x, VALUE y)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
VALUE rb_ivar_set(VALUE, ID, VALUE)
#define TIME_COPY_GMT(tobj1, tobj2)
unsigned char buf[MIME_BUF_SIZE]
rb_encoding * rb_usascii_encoding(void)
VALUE rb_big_mul(VALUE x, VALUE y)
rb_encoding * rb_locale_encoding(void)
#define rb_enc_str_asciicompat_p(str)
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
int clock_gettime(clockid_t, struct timespec *)
VALUE rb_time_nano_new(time_t sec, long nsec)
#define rb_cmpint(cmp, a, b)
VALUE rb_str_new_cstr(const char *)
size_t rb_absint_size(VALUE val, int *nlz_bits_ret)
#define MUL_OVERFLOW_FIXWV_P(a, b)
#define RB_FLOAT_TYPE_P(obj)
#define TYPEOF_TIMEVAL_TV_USEC
int rb_respond_to(VALUE, ID)
register unsigned int len
#define StringValueCStr(v)
rb_encoding * rb_enc_get(VALUE obj)
#define TIME_SET_LOCALTIME(tobj)
VALUE rb_Float(VALUE)
Equivalent to Kernel#Float in Ruby.
VALUE rb_check_array_type(VALUE ary)
#define TIME_SET_FIXOFF(tobj, off)
#define MAKE_TM(time, tobj)
VALUE rb_check_string_type(VALUE)
struct timespec rb_time_timespec(VALUE time)
void rb_warning(const char *fmt,...)
VALUE rb_class_new_instance(int, const VALUE *, VALUE)
Allocates and initializes an instance of klass.
SIGNED_VALUE SIGNED_WIDEVALUE
#define TypedData_Make_Struct(klass, type, data_type, sval)
struct tm * gmtime_r(const time_t *, struct tm *)
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
#define StringValuePtr(v)
VALUE rb_numeric_quo(VALUE x, VALUE y)
#define rb_check_frozen(obj)
VALUE rb_str_tmp_frozen_acquire(VALUE str)
#define RUBY_TYPED_DEFAULT_FREE
void rb_copy_generic_ivar(VALUE, VALUE)
int rb_enc_str_asciionly_p(VALUE)
#define RB_INTEGER_TYPE_P(obj)
VALUE rb_invcmp(VALUE x, VALUE y)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
#define strftimev(fmt, time, enc)
struct timeval rb_time_timeval(VALUE time)
VALUE rb_to_int(VALUE)
Converts val into Integer.
VALUE rb_attr_get(VALUE, ID)
VALUE rb_usascii_str_new_cstr(const char *)
#define TYPEOF_TIMEVAL_TV_SEC
VALUE rb_str_new(const char *, long)
VALUE rb_time_num_new(VALUE timev, VALUE off)