12 #define _DEFAULT_SOURCE
16 #include <sys/types.h>
31 #if defined(HAVE_SYS_TIME_H)
38 static ID 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;
40 static ID id_local_to_utc, id_utc_to_local, id_find_timezone;
41 static ID id_year, id_mon, id_mday, id_hour, id_min, id_sec, id_isdst;
44 #define id_divmod idDivmod
45 #define id_name idName
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)
240 #ifdef STRUCT_WIDEVAL
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)));
557 rb_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)
646 static VALUE rb_cTimeTM;
652 static VALUE validate_utc_offset(
VALUE utc_offset);
653 static VALUE validate_zone_name(
VALUE zone_name);
654 static void validate_vtm(
struct vtm *vtm);
662 static time_t timegm_noleapsecond(
struct tm *
tm);
663 static int tmcmp(
struct tm *a,
struct tm *b);
664 static int vtmcmp(
struct vtm *a,
struct vtm *b);
665 static const char *find_time_t(
struct tm *tptr,
int utc_p,
time_t *tp);
667 static struct vtm *localtimew(
wideval_t timew,
struct vtm *result);
669 static int leap_year_p(
long y);
670 #define leap_year_v_p(y) leap_year_p(NUM2LONG(modv((y), INT2FIX(400))))
685 rb_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
720 rb_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))
738 static 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
753 static 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
769 static const int common_year_days_in_month[] = {
770 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
772 static 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)
793 static const uint8_t common_year_mon_of_yday[] = {
797 static 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
824 static const uint8_t common_year_mday_of_yday[] = {
826 D31,
D28,
D31,
D30,
D31,
D30,
D31,
D31,
D30,
D31,
D30,
D31
828 static 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))
852 timegmw_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));
893 zone_str(
const char *
zone)
904 for (p =
zone; *p; p++)
920 gmtimew_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];
1022 gmtime_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);
1145 static long this_year = 0;
1146 static time_t known_leap_seconds_limit;
1147 static int number_of_leap_seconds_known;
1150 init_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))));
1199 timegmw(
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));
1241 gmtimew(
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"))
1295 static struct tm *localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *
zone);
1330 static 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 },
1371 static const int compat_leap_month_table[7] = {
1373 2032, 2016, 2028, 2012, 2024, 2036, 2020,
1377 calc_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;
1391 guess_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;
1483 small_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;
1501 timelocalw(
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;
1583 localtime_with_gmtoff_zone(
const time_t *t,
struct tm *result,
long *gmtoff,
VALUE *
zone)
1588 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1599 off = l->tm_year < u->
tm_year ? -1 : 1;
1600 else if (l->tm_mon != u->
tm_mon)
1601 off = l->tm_mon < u->
tm_mon ? -1 : 1;
1602 else if (l->tm_mday != u->
tm_mday)
1603 off = l->tm_mday < u->
tm_mday ? -1 : 1;
1606 off = off * 24 + l->tm_hour - u->
tm_hour;
1607 off = off * 60 + l->tm_min - u->
tm_min;
1608 off = off * 60 + l->tm_sec - u->
tm_sec;
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
1638 timew_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);
1671 localtimew(
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)
1753 static 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)); \
1762 time_mark(
void *
ptr)
1764 struct time_object *tobj =
ptr;
1774 time_memsize(
const void *tobj)
1776 return sizeof(
struct time_object);
1789 struct time_object *tobj;
1795 tobj->vtm.zone =
Qnil;
1800 static struct time_object *
1803 struct time_object *tobj;
1811 static struct time_object *
1814 struct time_object *tobj;
1829 timespec2timew(
struct timespec *ts)
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;
1925 vtm_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;
2058 NORETURN(
static void invalid_utc_offset(
void));
2060 invalid_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;
2103 goto invalid_utc_offset;
2105 if (s[6] !=
':')
goto invalid_utc_offset;
2107 n += (s[7] * 10 + s[8] -
'0' * 11);
2110 if (s[0] !=
'+' && s[0] !=
'-')
goto invalid_utc_offset;
2112 if (s[3] !=
':')
goto invalid_utc_offset;
2114 if (s[4] >
'5')
goto invalid_utc_offset;
2117 goto invalid_utc_offset;
2119 n += (s[1] * 10 + s[2] -
'0' * 11) * 3600;
2120 n += (s[4] * 10 + s[5] -
'0' * 11) * 60;
2126 return num_exact(
arg);
2131 zone_set_offset(
VALUE zone,
struct time_object *tobj,
2137 validate_utc_offset(off);
2138 tobj->vtm.utc_offset = off;
2139 tobj->vtm.zone =
zone;
2149 #define EXTRACT_TIME() do { \
2150 t = v2w(rb_Integer(AREF(to_i))); \
2157 t = rb_time_unmagnify(tobj->timew);
2160 #define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2165 #define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2180 #define EXTRACT_VTM() do { \
2182 vtm->year = obj2vint(AREF(year)); \
2183 vtm->mon = month_arg(AREF(mon)); \
2184 vtm->mday = obj2ubits(AREF(mday), 5); \
2185 vtm->hour = obj2ubits(AREF(hour), 5); \
2186 vtm->min = obj2ubits(AREF(min), 6); \
2187 vtm->sec = obj2subsecx(AREF(sec), &subsecx); \
2188 vtm->isdst = RTEST(AREF(isdst)); \
2189 vtm->utc_offset = Qnil; \
2190 t = v2w(rb_Integer(AREF(to_i))); \
2196 time_get_tm(
time, tobj);
2198 t = rb_time_unmagnify(tobj->timew);
2200 t = wadd(t, v2w(vtm->utc_offset));
2203 #define AREF(x) rb_struct_aref(time, ID2SYM(id_##x))
2207 else if (rb_integer_type_p(
time)) {
2209 GMTIMEW(rb_time_magnify(t), vtm);
2212 #define AREF(x) rb_funcallv(time, id_##x, 0, 0)
2217 vtm->subsecx = subsecx;
2239 t = rb_time_unmagnify(tobj->timew);
2240 tm = tm_from_time(rb_cTimeTM,
time);
2242 if (utc ==
Qundef)
return 0;
2244 s = extract_time(utc);
2245 zone_set_offset(
zone, tobj, t, s);
2246 s = rb_time_magnify(s);
2247 if (tobj->vtm.subsecx !=
INT2FIX(0)) {
2248 s = wadd(s, v2w(tobj->vtm.subsecx));
2251 zone_set_dst(
zone, tobj,
tm);
2262 split_second(tobj->timew, &t, &subsecx);
2263 tm = tm_from_time(rb_cTimeTM,
time);
2266 if (local ==
Qundef)
return 0;
2268 s = extract_vtm(local, &tobj->vtm, subsecx);
2270 zone_set_offset(
zone, tobj, s, t);
2271 zone_set_dst(
zone, tobj,
tm);
2290 struct time_object *tobj;
2299 vtm.year = obj2vint(
v[0]);
2301 vtm.mon =
NIL_P(
v[1]) ? 1 : month_arg(
v[1]);
2303 vtm.mday =
NIL_P(
v[2]) ? 1 : obj2ubits(
v[2], 5);
2305 vtm.hour =
NIL_P(
v[3]) ? 0 : obj2ubits(
v[3], 5);
2307 vtm.min =
NIL_P(
v[4]) ? 0 : obj2ubits(
v[4], 6);
2315 vtm.sec = obj2subsecx(
v[5], &subsecx);
2316 vtm.subsecx = subsecx;
2320 vtm.utc_offset =
Qnil;
2327 else if (maybe_tzobj_p(
arg))
2329 else if (!
NIL_P(utc = utc_offset_arg(
arg)))
2332 invalid_utc_offset();
2341 tobj->timew = timegmw(&vtm);
2348 else if (
NIL_P(vtm.utc_offset = utc_offset_arg(
zone))) {
2350 invalid_utc_offset();
2355 tobj->timew = timegmw(&vtm);
2366 if (!
NIL_P(vtm.utc_offset)) {
2367 VALUE off = vtm.utc_offset;
2368 vtm_add_offset(&vtm, off, -1);
2369 vtm.utc_offset =
Qnil;
2370 tobj->timew = timegmw(&vtm);
2371 return time_set_utc_offset(
time, off);
2374 tobj->timew = timelocalw(&vtm);
2375 return time_localtime(
time);
2432 return time_init_0(
time);
2438 time_overflow_p(
time_t *secp,
long *nsecp)
2444 if (nsec >= 1000000000) {
2445 sec2 = nsec / 1000000000;
2449 nsec -= sec2 * 1000000000;
2452 else if (nsec < 0) {
2453 sec2 =
NDIV(nsec,1000000000);
2457 nsec -= sec2 * 1000000000;
2460 #ifndef NEGATIVE_TIME_T
2469 nsec2timew(
time_t sec,
long nsec)
2472 time_overflow_p(&sec, &nsec);
2475 return timespec2timew(&ts);
2482 struct time_object *tobj;
2486 tobj->timew = timew;
2496 if (usec >= 1000000) {
2497 long sec2 = usec / 1000000;
2501 usec -= sec2 * 1000000;
2504 else if (usec < 0) {
2505 long sec2 =
NDIV(usec,1000000);
2509 usec -= sec2 * 1000000;
2513 timew = nsec2timew(sec, usec * 1000);
2514 return time_new_timew(
rb_cTime, timew);
2521 return time_new_timew(
rb_cTime, nsec2timew(sec, nsec));
2532 struct time_object *tobj;
2535 if (-86400 < offset && offset < 86400) {
2541 else if (offset ==
INT_MAX-1) {
2560 if (maybe_tzobj_p(
zone)) {
2564 if (
NIL_P(off = utc_offset_arg(off))) {
2567 if (!zone_timelocal(
zone,
time)) invalid_utc_offset();
2571 return time_gmtime(
time);
2574 validate_utc_offset(off);
2575 time_set_utc_offset(
time, off);
2583 time_timespec(
VALUE num,
int interval)
2586 const char *
const tstr = interval ?
"time interval" :
"time";
2589 #ifndef NEGATIVE_TIME_T
2590 # define arg_range_check(v) \
2592 rb_raise(rb_eArgError, "%s must not be negative", tstr) : \
2595 # define arg_range_check(v) \
2596 ((interval && (v) < 0) ? \
2597 rb_raise(rb_eArgError, "time interval must not be negative") : \
2614 t.tv_nsec = (
int)(d*1e9+0.5);
2615 if (t.tv_nsec >= 1000000000) {
2616 t.tv_nsec -= 1000000000;
2620 else if ((t.tv_nsec = (
int)(-d*1e9+0.5)) > 0) {
2621 t.tv_nsec = 1000000000 - t.tv_nsec;
2625 if (
f != t.tv_sec) {
2652 #undef arg_range_check
2656 time_timeval(
VALUE num,
int interval)
2661 ts = time_timespec(num, interval);
2671 return time_timeval(num,
TRUE);
2677 struct time_object *tobj;
2683 ts = timew2timespec(tobj->timew);
2694 struct time_object *tobj;
2699 t = timew2timespec(tobj->timew);
2708 return time_timespec(num,
TRUE);
2721 if (
NIL_P(opts))
return false;
2745 time_zonelocal(t,
zone);
2751 get_scale(
VALUE unit)
2753 if (unit ==
ID2SYM(id_nanosecond) || unit ==
ID2SYM(id_nsec)) {
2756 else if (unit ==
ID2SYM(id_microsecond) || unit ==
ID2SYM(id_usec)) {
2759 else if (unit ==
ID2SYM(id_millisecond)) {
2813 if (get_tmopt(opts, vals)) {
2817 int scale =
argc == 3 ? get_scale(unit) : 1000000;
2821 t = time_new_timew(
klass, timew);
2824 struct time_object *tobj, *tobj2;
2826 t = time_new_timew(
klass, tobj->timew);
2831 timew = rb_time_magnify(v2w(num_exact(
time)));
2832 t = time_new_timew(
klass, timew);
2835 time_zonelocal(t,
zone);
2841 static const char months[][4] = {
2842 "jan",
"feb",
"mar",
"apr",
"may",
"jun",
2843 "jul",
"aug",
"sep",
"oct",
"nov",
"dec",
2860 const uint32_t usable_mask = ~(u32max << bits);
2862 int tmp = obj2int(
obj);
2867 if ((rv & usable_mask) != rv)
2896 *subsecx = w2v(rb_time_magnify(v2w(subsec)));
2898 return obj2ubits(
obj, 6);
2919 for (
i=0;
i<12;
i++) {
2929 if (
'0' <= c && c <=
'9') {
2930 mon = obj2ubits(s, 4);
2935 mon = obj2ubits(
arg, 4);
2941 validate_utc_offset(
VALUE utc_offset)
2949 validate_zone_name(
VALUE zone_name)
2956 validate_vtm(
struct vtm *vtm)
2958 #define validate_vtm_range(mem, b, e) \
2959 ((vtm->mem < b || vtm->mem > e) ? \
2960 rb_raise(rb_eArgError, #mem" out of range") : (void)0)
2968 if (!
NIL_P(vtm->utc_offset)) validate_utc_offset(vtm->utc_offset);
2969 #undef validate_vtm_range
2985 vtm->utc_offset =
Qnil;
3002 rb_scan_args(
argc,
argv,
"17", &
v[0],&
v[1],&
v[2],&
v[3],&
v[4],&
v[5],&
v[6],&
v[7]);
3009 vtm->year = obj2vint(
v[0]);
3015 vtm->mon = month_arg(
v[1]);
3022 vtm->mday = obj2ubits(
v[2], 5);
3031 if (vtm->mday > mday2) {
3041 if (vtm->mday == 31) {
3048 vtm->hour =
NIL_P(
v[3])?0:obj2ubits(
v[3], 5);
3050 vtm->min =
NIL_P(
v[4])?0:obj2ubits(
v[4], 6);
3053 vtm->sec =
NIL_P(
v[5])?0:obj2ubits(
v[5],6);
3054 subsecx = usec2subsecx(
v[6]);
3062 vtm->sec = obj2subsecx(
v[5], &subsecx);
3065 vtm->subsecx = subsecx;
3077 unsigned long uy = (
unsigned long)(
LIKELY(y >= 0) ? y : -y);
3079 if (
LIKELY(uy % 4 != 0))
return 0;
3081 unsigned long century = uy / 100;
3082 if (
LIKELY(uy != century * 100))
return 1;
3083 return century % 4 == 0;
3087 timegm_noleapsecond(
struct tm *
tm)
3102 DIV(tm_year-1,100) +
3103 DIV(tm_year+299,400))*86400;
3107 #define DEBUG_FIND_TIME_NUMGUESS
3108 #define DEBUG_GUESSRANGE
3111 #ifdef DEBUG_GUESSRANGE
3112 #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))
3114 #define DEBUG_REPORT_GUESSRANGE
3117 #ifdef DEBUG_FIND_TIME_NUMGUESS
3118 #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
3119 static unsigned long long find_time_numguess;
3121 static VALUE find_time_numguess_getter(
void)
3123 return ULL2NUM(find_time_numguess);
3126 #define DEBUG_FIND_TIME_NUMGUESS_INC
3130 find_time_t(
struct tm *tptr,
int utc_p,
time_t *tp)
3132 time_t guess, guess0, guess_lo, guess_hi;
3133 struct tm *
tm, tm0, tm_lo, tm_hi;
3140 #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
3158 else if (11 < tm0.
tm_mon) {
3171 else if ((d = (leap_year_p(1900 + tm0.
tm_year) ?
3172 leap_year_days_in_month :
3189 else if (tm0.
tm_min < 0) {
3193 else if (59 < tm0.
tm_min) {
3197 else if (tm0.
tm_sec < 0) {
3200 else if (60 < tm0.
tm_sec) {
3205 guess0 = guess = timegm_noleapsecond(&tm0);
3208 d = tmcmp(tptr,
tm);
3209 if (d == 0) {
goto found; }
3212 guess -= 24 * 60 * 60;
3216 guess += 24 * 60 * 60;
3219 if (guess_lo < guess && guess < guess_hi && (
tm =
GUESS(&guess)) !=
NULL) {
3220 d = tmcmp(tptr,
tm);
3221 if (d == 0) {
goto found; }
3232 d = tmcmp(tptr,
tm);
3233 if (d < 0)
goto out_of_range;
3234 if (d == 0) { guess = guess_lo;
goto found; }
3239 d = tmcmp(tptr,
tm);
3240 if (d > 0)
goto out_of_range;
3241 if (d == 0) { guess = guess_hi;
goto found; }
3248 while (guess_lo + 1 < guess_hi) {
3251 guess = guess_lo / 2 + guess_hi / 2;
3252 if (guess <= guess_lo)
3253 guess = guess_lo + 1;
3254 else if (guess >= guess_hi)
3255 guess = guess_hi - 1;
3260 time_t guess0_hi = timegm_noleapsecond(&tm_hi);
3261 guess = guess_hi - (guess0_hi - guess0);
3262 if (guess == guess_hi)
3266 else if (status == 2) {
3267 time_t guess0_lo = timegm_noleapsecond(&tm_lo);
3268 guess = guess_lo + (guess0 - guess0_lo);
3269 if (guess == guess_lo)
3273 if (guess <= guess_lo || guess_hi <= guess) {
3275 #ifdef DEBUG_GUESSRANGE
3276 if (guess <= guess_lo)
fprintf(
stderr,
"too small guess: %ld <= %ld\n", guess, guess_lo);
3277 if (guess_hi <= guess)
fprintf(
stderr,
"too big guess: %ld <= %ld\n", guess_hi, guess);
3286 d = tmcmp(tptr,
tm);
3304 guess2 = guess - 2 * 60 * 60;
3314 guess2 += 24 * 60 * 60;
3315 if (guess != guess2) {
3317 if (
tm && tmcmp(tptr,
tm) == 0) {
3329 guess2 = guess + 2 * 60 * 60;
3339 guess2 -= 24 * 60 * 60;
3340 if (guess != guess2) {
3342 if (
tm && tmcmp(tptr,
tm) == 0) {
3386 return "time out of range";
3389 return "gmtime/localtime error";
3393 vtmcmp(
struct vtm *a,
struct vtm *b)
3395 if (
ne(a->year, b->year))
3396 return lt(a->year, b->year) ? -1 : 1;
3397 else if (a->mon != b->mon)
3398 return a->mon < b->mon ? -1 : 1;
3399 else if (a->mday != b->mday)
3400 return a->mday < b->mday ? -1 : 1;
3401 else if (a->hour != b->hour)
3402 return a->hour < b->hour ? -1 : 1;
3403 else if (a->min != b->min)
3404 return a->min < b->min ? -1 : 1;
3405 else if (a->sec != b->sec)
3406 return a->sec < b->sec ? -1 : 1;
3407 else if (
ne(a->subsecx, b->subsecx))
3408 return lt(a->subsecx, b->subsecx) ? -1 : 1;
3414 tmcmp(
struct tm *a,
struct tm *b)
3470 return time_gmtime(time_new_timew(
klass, timegmw(&vtm)));
3504 return time_localtime(time_new_timew(
klass, timelocalw(&vtm)));
3523 struct time_object *tobj;
3547 struct time_object *tobj;
3550 return rb_Float(rb_time_unmagnify_to_float(tobj->timew));
3571 struct time_object *tobj;
3575 v = rb_time_unmagnify_to_rational(tobj->timew);
3597 struct time_object *tobj;
3628 struct time_object *tobj;
3656 struct time_object *tobj;
3690 struct time_object *tobj1, *tobj2;
3696 n = wcmp(tobj1->timew, tobj2->timew);
3717 struct time_object *tobj1, *tobj2;
3722 return rb_equal(w2v(tobj1->timew), w2v(tobj2->timew));
3748 struct time_object *tobj;
3767 struct time_object *tobj;
3770 return rb_hash(w2v(tobj->timew));
3777 struct time_object *tobj, *tcopy;
3782 MEMCPY(tcopy, tobj,
struct time_object, 1);
3798 struct time_object *tobj;
3811 zone = tobj->vtm.zone;
3812 if (maybe_tzobj_p(
zone) && zone_localtime(
zone,
time)) {
3816 if (!localtimew(tobj->timew, &vtm))
3831 if (
NIL_P(off = utc_offset_arg(off))) {
3833 if (!zone_localtime(
zone,
time)) invalid_utc_offset();
3837 return time_gmtime(
time);
3839 validate_utc_offset(off);
3841 time_set_utc_offset(
time, off);
3842 return time_fixoff(
time);
3874 return time_zonelocal(
time, off);
3877 return time_localtime(
time);
3901 struct time_object *tobj;
3925 struct time_object *tobj;
3939 off = tobj->vtm.utc_offset;
3945 zone = tobj->vtm.zone;
3947 tobj->vtm.zone =
zone;
3948 vtm_add_offset(&tobj->vtm, off, +1);
3991 if (maybe_tzobj_p(
zone)) {
3993 if (zone_localtime(off, t))
return t;
3996 if (
NIL_P(off = utc_offset_arg(off))) {
3999 if (!zone_localtime(
zone,
time)) invalid_utc_offset();
4003 return time_gmtime(time_dup(
time));
4005 validate_utc_offset(off);
4008 time_set_utc_offset(
time, off);
4009 return time_fixoff(
time);
4012 return time_localtime(time_dup(
time));
4032 return time_gmtime(time_dup(
time));
4036 time_get_tm(
VALUE time,
struct time_object *tobj)
4040 return time_localtime(
time);
4044 #define strftimev(fmt, time, enc) strftime_cstr((fmt), rb_strlen_lit(fmt), (time), (enc))
4081 struct time_object *tobj;
4108 struct time_object *tobj;
4141 struct time_object *result_tobj;
4143 offset = num_exact(offset);
4145 result = time_new_timew(
klass, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
4147 result = time_new_timew(
klass, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
4155 time_add(
const struct time_object *tobj,
VALUE torig,
VALUE offset,
int sign)
4157 return time_add0(
rb_cTime, tobj, torig, offset, sign);
4174 struct time_object *tobj;
4180 return time_add(tobj, time1, time2, 1);
4201 struct time_object *tobj;
4205 struct time_object *tobj2;
4208 return rb_Float(rb_time_unmagnify_to_float(wsub(tobj->timew, tobj2->timew)));
4210 return time_add(tobj, time1, time2, -1);
4231 struct time_object *tobj;
4232 struct time_object *tobj2;
4234 rb_warn(
"Time#succ is obsolete; use time + 1");
4240 zone_localtime(tobj2->vtm.zone,
time);
4245 #define time_succ rb_time_succ
4248 ndigits_denominator(
VALUE ndigits)
4297 struct time_object *tobj;
4302 den = ndigits_denominator(ndigits);
4305 v = w2v(rb_time_unmagnify(tobj->timew));
4309 return time_add(tobj,
time,
v, -1);
4311 return time_add(tobj,
time, subv(den,
v), 1);
4347 struct time_object *tobj;
4352 den = ndigits_denominator(ndigits);
4355 v = w2v(rb_time_unmagnify(tobj->timew));
4358 return time_add(tobj,
time,
v, -1);
4394 struct time_object *tobj;
4399 den = ndigits_denominator(ndigits);
4402 v = w2v(rb_time_unmagnify(tobj->timew));
4405 return time_add(tobj,
time, subv(den,
v), 1);
4425 struct time_object *tobj;
4429 return INT2FIX(tobj->vtm.sec);
4445 struct time_object *tobj;
4449 return INT2FIX(tobj->vtm.min);
4465 struct time_object *tobj;
4469 return INT2FIX(tobj->vtm.hour);
4487 struct time_object *tobj;
4491 return INT2FIX(tobj->vtm.mday);
4509 struct time_object *tobj;
4513 return INT2FIX(tobj->vtm.mon);
4529 struct time_object *tobj;
4533 return tobj->vtm.year;
4557 struct time_object *tobj;
4561 return INT2FIX((
int)tobj->vtm.wday);
4564 #define wday_p(n) {\
4565 struct time_object *tobj;\
4566 GetTimeval(time, tobj);\
4567 MAKE_TM(time, tobj);\
4568 return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\
4696 struct time_object *tobj;
4700 return INT2FIX(tobj->vtm.yday);
4731 struct time_object *tobj;
4757 struct time_object *tobj;
4766 zone = tobj->vtm.zone;
4793 struct time_object *tobj;
4802 return tobj->vtm.utc_offset;
4826 struct time_object *tobj;
4844 rb_strftime_alloc(
const char *format,
size_t format_len,
rb_encoding *enc,
4850 if (!timew2timespec_exact(timew, &ts))
4851 timev = w2v(rb_time_unmagnify(timew));
4864 struct time_object *tobj;
5064 struct time_object *tobj;
5081 rb_warning(
"strftime called with empty format string");
5101 struct time_object *tobj;
5113 const int max_year = 1900+0xffff;
5117 gmtimew(tobj->timew, &vtm);
5121 if (year > max_year) {
5122 year_extend =
INT2FIX(year - max_year);
5125 else if (year < 1900) {
5126 year_extend =
LONG2NUM(1900 - year);
5141 subsecx = vtm.subsecx;
5144 divmodv(nano,
INT2FIX(1), &
v, &subnano);
5149 nano = addv(
LONG2FIX(nsec), subnano);
5157 s = (
unsigned long)vtm.min << 26 |
5161 for (
i=0;
i<4;
i++) {
5165 for (
i=4;
i<8;
i++) {
5170 if (!
NIL_P(year_extend)) {
5182 (year == 1900 ?
"small" :
"big"), vtm.year);
5215 buf[1] = (
char)((nsec % 10) << 4);
5219 buf[0] |= (
char)((nsec % 10) << 4);
5231 zone = tobj->vtm.zone;
5232 if (maybe_tzobj_p(
zone)) {
5277 struct time_object *tobj;
5285 VALUE submicro, nano_num, nano_den, offset,
zone, year;
5290 #define get_attr(attr, iffound) \
5291 attr = rb_attr_delete(str, id_##attr); \
5292 if (!NIL_P(attr)) { \
5315 for (
i=0;
i<4;
i++) {
5318 for (
i=4;
i<8;
i++) {
5322 if ((p & (1UL<<31)) == 0) {
5332 gmt = (
int)((p >> 30) & 0x1);
5335 year =
INT2FIX(((
int)(p >> 14) & 0xffff) + 1900);
5343 len -= ybuf - (
const char *)
buf;
5344 if (ysize < 0 || ysize >
len)
goto invalid_format;
5354 vtm.mon = ((
int)(p >> 10) & 0xf) + 1;
5355 vtm.mday = (
int)(p >> 5) & 0x1f;
5356 vtm.hour = (
int) p & 0x1f;
5357 vtm.min = (
int)(s >> 26) & 0x3f;
5358 vtm.sec = (
int)(s >> 20) & 0x3f;
5360 vtm.yday = vtm.wday = 0;
5364 usec = (
long)(s & 0xfffff);
5369 if (nano_num !=
Qnil) {
5370 VALUE nano = quov(num_exact(nano_num), num_exact(nano_den));
5373 else if (submicro !=
Qnil) {
5381 if (10 <= (
digit =
ptr[0] >> 4))
goto end_submicro;
5382 nsec +=
digit * 100;
5383 if (10 <= (
digit =
ptr[0] & 0xf))
goto end_submicro;
5387 if (10 <= (
digit =
ptr[1] >> 4))
goto end_submicro;
5393 timew = timegmw(&vtm);
5399 tobj->timew = timew;
5403 else if (!
NIL_P(offset)) {
5404 time_set_utc_offset(
time, offset);
5409 tobj->vtm.zone =
zone;
5443 struct time_object *tobj;
5447 struct time_object *ttm;
5453 GMTIMEW(ttm->timew = tobj->timew,
v);
5469 args[
i++] =
v->year;
5476 case 0: args[
i++] =
Qfalse;
break;
5477 case 1: args[
i++] =
Qtrue;
break;
5478 default: args[
i++] =
Qnil;
break;
5480 args[
i++] = w2v(rb_time_unmagnify(tobj->timew));
5533 struct time_object *torig = get_timeval(
tm);
5557 #define tm_subsec tm_zero
5558 #define tm_utc_offset tm_zero
5574 p[5], p[4], p[3], p[2], p[1], p[0]);
5630 "sec",
"min",
"hour",
5631 "mday",
"mon",
"year",
5652 VALUE tm, abbr, strftime_args[2];
5655 if (!
NIL_P(abbr))
return abbr;
5657 tm = tm_from_time(rb_cTimeTM,
time);
5662 #ifdef SUPPORT_TZINFO_ZONE_ABBREVIATION
5670 strftime_args[1] =
tm;
5813 #define rb_intern(str) rb_intern_const(str)
5820 id_nanosecond =
rb_intern(
"nanosecond");
5821 id_microsecond =
rb_intern(
"microsecond");
5822 id_millisecond =
rb_intern(
"millisecond");
5825 id_local_to_utc =
rb_intern(
"local_to_utc");
5826 id_utc_to_local =
rb_intern(
"utc_to_local");
5834 id_find_timezone =
rb_intern(
"find_timezone");
5923 #ifdef DEBUG_FIND_TIME_NUMGUESS
5927 rb_cTimeTM = Init_tm(
rb_cTime,
"tm");