PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/time.c

https://github.com/fizx/ruby
C | 3965 lines | 2645 code | 467 blank | 853 comment | 567 complexity | e699b10f1c61e49000523452dfbf68b2 MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-3.0, GPL-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /**********************************************************************
  2. time.c -
  3. $Author$
  4. created at: Tue Dec 28 14:31:59 JST 1993
  5. Copyright (C) 1993-2007 Yukihiro Matsumoto
  6. **********************************************************************/
  7. #include "ruby/ruby.h"
  8. #include <sys/types.h>
  9. #include <time.h>
  10. #include <errno.h>
  11. #include "ruby/encoding.h"
  12. #ifdef HAVE_UNISTD_H
  13. #include <unistd.h>
  14. #endif
  15. #include <float.h>
  16. #include <math.h>
  17. #include "timev.h"
  18. #ifndef TYPEOF_TIMEVAL_TV_SEC
  19. # define TYPEOF_TIMEVAL_TV_SEC time_t
  20. #endif
  21. #ifndef TYPEOF_TIMEVAL_TV_USEC
  22. # if INT_MAX >= 1000000
  23. # define TYPEOF_TIMEVAL_TV_USEC int
  24. # else
  25. # define TYPEOF_TIMEVAL_TV_USEC long
  26. # endif
  27. #endif
  28. #if SIZEOF_TIME_T == SIZEOF_LONG
  29. typedef unsigned long unsigned_time_t;
  30. #elif SIZEOF_TIME_T == SIZEOF_INT
  31. typedef unsigned int unsigned_time_t;
  32. #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
  33. typedef unsigned LONG_LONG unsigned_time_t;
  34. #else
  35. # error cannot find integer type which size is same as time_t.
  36. #endif
  37. #define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (~(unsigned_time_t)0))
  38. #define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
  39. VALUE rb_cTime;
  40. static VALUE time_utc_offset _((VALUE));
  41. static int obj2int(VALUE obj);
  42. static VALUE obj2vint(VALUE obj);
  43. static int month_arg(VALUE arg);
  44. static void validate_utc_offset(VALUE utc_offset);
  45. static void validate_vtm(struct vtm *vtm);
  46. static VALUE time_gmtime(VALUE);
  47. static VALUE time_localtime(VALUE);
  48. static VALUE time_fixoff(VALUE);
  49. static time_t timegm_noleapsecond(struct tm *tm);
  50. static int tmcmp(struct tm *a, struct tm *b);
  51. static int vtmcmp(struct vtm *a, struct vtm *b);
  52. static const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
  53. static struct vtm *localtimexv(VALUE timexv, struct vtm *result);
  54. static int leap_year_p(long y);
  55. #define leap_year_v_p(y) leap_year_p(NUM2LONG(mod(v, INT2FIX(400))))
  56. #define NDIV(x,y) (-(-((x)+1)/(y))-1)
  57. #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
  58. #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
  59. #ifdef HAVE_GMTIME_R
  60. #define IF_HAVE_GMTIME_R(x) x
  61. #define ASCTIME(tm, buf) asctime_r((tm), (buf))
  62. #define GMTIME(tm, result) gmtime_r((tm), &(result))
  63. #define LOCALTIME(tm, result) (tzset(),localtime_r((tm), &(result)))
  64. #else
  65. #define IF_HAVE_GMTIME_R(x) /* nothing */
  66. #define ASCTIME(tm, buf) asctime(tm)
  67. #define GMTIME(tm, result) rb_gmtime((tm), &(result))
  68. #define LOCALTIME(tm, result) rb_localtime((tm), &(result))
  69. static inline struct tm *
  70. rb_gmtime(const time_t *tm, struct tm *result)
  71. {
  72. struct tm *t = gmtime(tm);
  73. if (t) *result = *t;
  74. return t;
  75. }
  76. static inline struct tm *
  77. rb_localtime(const time_t *tm, struct tm *result)
  78. {
  79. struct tm *t = localtime(tm);
  80. if (t) *result = *t;
  81. return t;
  82. }
  83. #endif
  84. static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset;
  85. static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;
  86. #define eq(x,y) (RTEST(rb_funcall((x), id_eq, 1, (y))))
  87. #define ne(x,y) (RTEST(rb_funcall((x), id_ne, 1, (y))))
  88. #define lt(x,y) (RTEST(rb_funcall((x), '<', 1, (y))))
  89. #define gt(x,y) (RTEST(rb_funcall((x), '>', 1, (y))))
  90. #define le(x,y) (!gt(x,y))
  91. #define ge(x,y) (!lt(x,y))
  92. static VALUE
  93. add(VALUE x, VALUE y)
  94. {
  95. if (FIXNUM_P(x) && FIXNUM_P(y)) {
  96. long l = FIX2LONG(x) + FIX2LONG(y);
  97. if (FIXABLE(l)) return LONG2FIX(l);
  98. return LONG2NUM(l);
  99. }
  100. if (TYPE(x) == T_BIGNUM) return rb_big_plus(x, y);
  101. return rb_funcall(x, '+', 1, y);
  102. }
  103. static VALUE
  104. sub(VALUE x, VALUE y)
  105. {
  106. if (FIXNUM_P(x) && FIXNUM_P(y)) {
  107. long l = FIX2LONG(x) - FIX2LONG(y);
  108. if (FIXABLE(l)) return LONG2FIX(l);
  109. return LONG2NUM(l);
  110. }
  111. if (TYPE(x) == T_BIGNUM) return rb_big_minus(x, y);
  112. return rb_funcall(x, '-', 1, y);
  113. }
  114. static VALUE
  115. mul(VALUE x, VALUE y)
  116. {
  117. if (FIXNUM_P(x) && FIXNUM_P(y)) {
  118. #if HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG
  119. LONG_LONG ll = (LONG_LONG)FIX2LONG(x) * FIX2LONG(y);
  120. if (FIXABLE(ll)) return LONG2FIX(ll);
  121. return LL2NUM(ll);
  122. #else
  123. long a, b, c;
  124. a = FIX2LONG(x);
  125. if (a == 0) return x;
  126. b = FIX2LONG(y);
  127. c = a * b;
  128. if (c / a == b && FIXABLE(c)) return LONG2FIX(c);
  129. #endif
  130. }
  131. if (TYPE(x) == T_BIGNUM) return rb_big_mul(x, y);
  132. return rb_funcall(x, '*', 1, y);
  133. }
  134. #define div(x,y) (rb_funcall((x), id_div, 1, (y)))
  135. static VALUE
  136. mod(VALUE x, VALUE y)
  137. {
  138. switch (TYPE(x)) {
  139. case T_BIGNUM: return rb_big_modulo(x, y);
  140. default: return rb_funcall(x, '%', 1, y);
  141. }
  142. }
  143. #define neg(x) (sub(INT2FIX(0), (x)))
  144. #define cmp(x,y) (rb_funcall((x), id_cmp, 1, (y)))
  145. #define lshift(x,y) (rb_funcall((x), id_lshift, 1, (y)))
  146. static VALUE
  147. quo(VALUE x, VALUE y)
  148. {
  149. VALUE ret;
  150. ret = rb_funcall((x), id_quo, 1, (y));
  151. if (TYPE(ret) == T_RATIONAL &&
  152. RRATIONAL(ret)->den == INT2FIX(1)) {
  153. ret = RRATIONAL(ret)->num;
  154. }
  155. return ret;
  156. }
  157. #define mulquo(x,y,z) ((y == z) ? x : quo(mul(x,y),z))
  158. static void
  159. divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
  160. {
  161. VALUE tmp, ary;
  162. tmp = rb_funcall(n, id_divmod, 1, d);
  163. ary = rb_check_array_type(tmp);
  164. if (NIL_P(ary)) {
  165. rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
  166. rb_obj_classname(tmp));
  167. }
  168. *q = rb_ary_entry(ary, 0);
  169. *r = rb_ary_entry(ary, 1);
  170. }
  171. static VALUE
  172. num_exact(VALUE v)
  173. {
  174. switch (TYPE(v)) {
  175. case T_FIXNUM:
  176. case T_BIGNUM:
  177. case T_RATIONAL:
  178. break;
  179. case T_FLOAT:
  180. v = rb_convert_type(v, T_RATIONAL, "Rational", "to_r");
  181. break;
  182. case T_STRING:
  183. case T_NIL:
  184. goto typeerror;
  185. default: {
  186. VALUE tmp;
  187. if (!NIL_P(tmp = rb_check_convert_type(v, T_RATIONAL, "Rational", "to_r"))) {
  188. if (rb_respond_to(v, rb_intern("to_str"))) goto typeerror;
  189. v = tmp;
  190. }
  191. else if (!NIL_P(tmp = rb_check_to_integer(v, "to_int")))
  192. v = tmp;
  193. else {
  194. typeerror:
  195. rb_raise(rb_eTypeError, "can't convert %s into an exact number",
  196. NIL_P(v) ? "nil" : rb_obj_classname(v));
  197. }
  198. break;
  199. }
  200. }
  201. return v;
  202. }
  203. static VALUE
  204. rb_time_magnify(VALUE v)
  205. {
  206. return mul(v, INT2FIX(TIME_SCALE));
  207. }
  208. static VALUE
  209. rb_time_unmagnify(VALUE v)
  210. {
  211. return quo(v, INT2FIX(TIME_SCALE));
  212. }
  213. static const int common_year_yday_offset[] = {
  214. -1,
  215. -1 + 31,
  216. -1 + 31 + 28,
  217. -1 + 31 + 28 + 31,
  218. -1 + 31 + 28 + 31 + 30,
  219. -1 + 31 + 28 + 31 + 30 + 31,
  220. -1 + 31 + 28 + 31 + 30 + 31 + 30,
  221. -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
  222. -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  223. -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  224. -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  225. -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
  226. /* 1 2 3 4 5 6 7 8 9 10 11 */
  227. };
  228. static const int leap_year_yday_offset[] = {
  229. -1,
  230. -1 + 31,
  231. -1 + 31 + 29,
  232. -1 + 31 + 29 + 31,
  233. -1 + 31 + 29 + 31 + 30,
  234. -1 + 31 + 29 + 31 + 30 + 31,
  235. -1 + 31 + 29 + 31 + 30 + 31 + 30,
  236. -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
  237. -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
  238. -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  239. -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  240. -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
  241. /* 1 2 3 4 5 6 7 8 9 10 11 */
  242. };
  243. static const int common_year_days_in_month[] = {
  244. 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  245. };
  246. static const int leap_year_days_in_month[] = {
  247. 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  248. };
  249. static VALUE
  250. timegmxv_noleapsecond(struct vtm *vtm)
  251. {
  252. VALUE year1900;
  253. VALUE q400, r400;
  254. int year_mod400;
  255. int yday = vtm->mday;
  256. long days_in400;
  257. VALUE ret;
  258. year1900 = sub(vtm->year, INT2FIX(1900));
  259. divmodv(year1900, INT2FIX(400), &q400, &r400);
  260. year_mod400 = NUM2INT(r400);
  261. if (leap_year_p(year_mod400 + 1900))
  262. yday += leap_year_yday_offset[vtm->mon-1];
  263. else
  264. yday += common_year_yday_offset[vtm->mon-1];
  265. /*
  266. * `Seconds Since the Epoch' in SUSv3:
  267. * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
  268. * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
  269. * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
  270. */
  271. ret = LONG2NUM(vtm->sec
  272. + vtm->min*60
  273. + vtm->hour*3600);
  274. days_in400 = yday
  275. - 70*365
  276. + DIV(year_mod400 - 69, 4)
  277. - DIV(year_mod400 - 1, 100)
  278. + (year_mod400 + 299) / 400;
  279. ret = add(ret, mul(LONG2NUM(days_in400), INT2FIX(86400)));
  280. ret = add(ret, mul(q400, INT2FIX(97*86400)));
  281. ret = add(ret, mul(year1900, INT2FIX(365*86400)));
  282. ret = add(rb_time_magnify(ret), vtm->subsecx);
  283. return ret;
  284. }
  285. static st_table *zone_table;
  286. static const char *
  287. zone_str(const char *s)
  288. {
  289. st_data_t k, v;
  290. if (!zone_table)
  291. zone_table = st_init_strtable();
  292. k = (st_data_t)s;
  293. if (st_lookup(zone_table, k, &v)) {
  294. return (const char *)v;
  295. }
  296. s = strdup(s);
  297. k = (st_data_t)s;
  298. st_add_direct(zone_table, k, k);
  299. return s;
  300. }
  301. static void
  302. gmtimexv_noleapsecond(VALUE timexv, struct vtm *vtm)
  303. {
  304. VALUE v;
  305. int i, n, x, y;
  306. const int *yday_offset;
  307. int wday;
  308. VALUE timev;
  309. vtm->isdst = 0;
  310. divmodv(timexv, INT2FIX(TIME_SCALE), &timev, &vtm->subsecx);
  311. divmodv(timev, INT2FIX(86400), &timev, &v);
  312. wday = NUM2INT(mod(timev, INT2FIX(7)));
  313. vtm->wday = (wday + 4) % 7;
  314. n = NUM2INT(v);
  315. vtm->sec = n % 60; n = n / 60;
  316. vtm->min = n % 60; n = n / 60;
  317. vtm->hour = n;
  318. /* 97 leap days in the 400 year cycle */
  319. divmodv(timev, INT2FIX(400*365 + 97), &timev, &v);
  320. vtm->year = mul(timev, INT2FIX(400));
  321. /* n is the days in the 400 year cycle.
  322. * the start of the cycle is 1970-01-01. */
  323. n = NUM2INT(v);
  324. y = 1970;
  325. /* 30 years including 7 leap days (1972, 1976, ... 1996),
  326. * 31 days in January 2000 and
  327. * 29 days in February 2000
  328. * from 1970-01-01 to 2000-02-29 */
  329. if (30*365+7+31+29-1 <= n) {
  330. /* 2000-02-29 or after */
  331. if (n < 31*365+8) {
  332. /* 2000-02-29 to 2000-12-31 */
  333. y += 30;
  334. n -= 30*365+7;
  335. goto found;
  336. }
  337. else {
  338. /* 2001-01-01 or after */
  339. n -= 1;
  340. }
  341. }
  342. x = n / (365*100 + 24);
  343. n = n % (365*100 + 24);
  344. y += x * 100;
  345. if (30*365+7+31+29-1 <= n) {
  346. if (n < 31*365+7) {
  347. y += 30;
  348. n -= 30*365+7;
  349. goto found;
  350. }
  351. else
  352. n += 1;
  353. }
  354. x = n / (365*4 + 1);
  355. n = n % (365*4 + 1);
  356. y += x * 4;
  357. if (365*2+31+29-1 <= n) {
  358. if (n < 365*2+366) {
  359. y += 2;
  360. n -= 365*2;
  361. goto found;
  362. }
  363. else
  364. n -= 1;
  365. }
  366. x = n / 365;
  367. n = n % 365;
  368. y += x;
  369. found:
  370. vtm->yday = n+1;
  371. vtm->year = add(vtm->year, INT2NUM(y));
  372. if (leap_year_p(y))
  373. yday_offset = leap_year_yday_offset;
  374. else
  375. yday_offset = common_year_yday_offset;
  376. for (i = 0; i < 12; i++) {
  377. if (yday_offset[i] < n) {
  378. vtm->mon = i+1;
  379. vtm->mday = n - yday_offset[i];
  380. }
  381. else
  382. break;
  383. }
  384. vtm->utc_offset = INT2FIX(0);
  385. vtm->zone = "UTC";
  386. }
  387. static struct tm *
  388. gmtime_with_leapsecond(const time_t *timep, struct tm *result)
  389. {
  390. #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
  391. /* 4.4BSD counts leap seconds only with localtime, not with gmtime. */
  392. struct tm *t;
  393. int sign;
  394. int gmtoff_sec, gmtoff_min, gmtoff_hour, gmtoff_day;
  395. long gmtoff;
  396. t = localtime_r(timep, result);
  397. if (t == NULL)
  398. return NULL;
  399. /* subtract gmtoff */
  400. if (t->tm_gmtoff < 0) {
  401. sign = 1;
  402. gmtoff = -t->tm_gmtoff;
  403. }
  404. else {
  405. sign = -1;
  406. gmtoff = t->tm_gmtoff;
  407. }
  408. gmtoff_sec = (int)(gmtoff % 60);
  409. gmtoff = gmtoff / 60;
  410. gmtoff_min = (int)(gmtoff % 60);
  411. gmtoff = gmtoff / 60;
  412. gmtoff_hour = (int)gmtoff; /* <= 12 */
  413. gmtoff_sec *= sign;
  414. gmtoff_min *= sign;
  415. gmtoff_hour *= sign;
  416. gmtoff_day = 0;
  417. if (gmtoff_sec) {
  418. /* If gmtoff_sec == 0, don't change result->tm_sec.
  419. * It may be 60 which is a leap second. */
  420. result->tm_sec += gmtoff_sec;
  421. if (result->tm_sec < 0) {
  422. result->tm_sec += 60;
  423. gmtoff_min -= 1;
  424. }
  425. if (60 <= result->tm_sec) {
  426. result->tm_sec -= 60;
  427. gmtoff_min += 1;
  428. }
  429. }
  430. if (gmtoff_min) {
  431. result->tm_min += gmtoff_min;
  432. if (result->tm_min < 0) {
  433. result->tm_min += 60;
  434. gmtoff_hour -= 1;
  435. }
  436. if (60 <= result->tm_min) {
  437. result->tm_min -= 60;
  438. gmtoff_hour += 1;
  439. }
  440. }
  441. if (gmtoff_hour) {
  442. result->tm_hour += gmtoff_hour;
  443. if (result->tm_hour < 0) {
  444. result->tm_hour += 24;
  445. gmtoff_day = -1;
  446. }
  447. if (24 <= result->tm_hour) {
  448. result->tm_hour -= 24;
  449. gmtoff_day = 1;
  450. }
  451. }
  452. if (gmtoff_day) {
  453. if (gmtoff_day < 0) {
  454. if (result->tm_yday == 0) {
  455. result->tm_mday = 31;
  456. result->tm_mon = 11; /* December */
  457. result->tm_year--;
  458. result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
  459. }
  460. else if (result->tm_mday == 1) {
  461. const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
  462. leap_year_days_in_month :
  463. common_year_days_in_month;
  464. result->tm_mon--;
  465. result->tm_mday = days_in_month[result->tm_mon];
  466. result->tm_yday--;
  467. }
  468. else {
  469. result->tm_mday--;
  470. result->tm_yday--;
  471. }
  472. result->tm_wday = (result->tm_wday + 6) % 7;
  473. }
  474. else {
  475. int leap = leap_year_p(result->tm_year + 1900);
  476. if (result->tm_yday == (leap ? 365 : 364)) {
  477. result->tm_year++;
  478. result->tm_mon = 0; /* January */
  479. result->tm_mday = 1;
  480. result->tm_yday = 0;
  481. }
  482. else if (result->tm_mday == (leap ? leap_year_days_in_month :
  483. common_year_days_in_month)[result->tm_mon]) {
  484. result->tm_mon++;
  485. result->tm_mday = 1;
  486. result->tm_yday++;
  487. }
  488. else {
  489. result->tm_mday++;
  490. result->tm_yday++;
  491. }
  492. result->tm_wday = (result->tm_wday + 1) % 7;
  493. }
  494. }
  495. result->tm_isdst = 0;
  496. result->tm_gmtoff = 0;
  497. #if defined(HAVE_TM_ZONE)
  498. result->tm_zone = (char *)"UTC";
  499. #endif
  500. return result;
  501. #else
  502. return GMTIME(timep, *result);
  503. #endif
  504. }
  505. static long this_year = 0;
  506. static time_t known_leap_seconds_limit;
  507. static int number_of_leap_seconds_known;
  508. static void
  509. init_leap_second_info()
  510. {
  511. /*
  512. * leap seconds are determined by IERS.
  513. * It is announced 6 months before the leap second.
  514. * So no one knows leap seconds in the future after the next year.
  515. */
  516. if (this_year == 0) {
  517. time_t now;
  518. struct tm *tm, result;
  519. struct vtm vtm;
  520. VALUE timexv;
  521. now = time(NULL);
  522. gmtime(&now);
  523. tm = gmtime_with_leapsecond(&now, &result);
  524. if (!tm) return;
  525. this_year = tm->tm_year;
  526. if (TIMET_MAX - now < (time_t)(366*86400))
  527. known_leap_seconds_limit = TIMET_MAX;
  528. else
  529. known_leap_seconds_limit = now + (time_t)(366*86400);
  530. gmtime_with_leapsecond(&known_leap_seconds_limit, &result);
  531. vtm.year = LONG2NUM(result.tm_year + 1900);
  532. vtm.mon = result.tm_mon + 1;
  533. vtm.mday = result.tm_mday;
  534. vtm.hour = result.tm_hour;
  535. vtm.min = result.tm_min;
  536. vtm.sec = result.tm_sec;
  537. vtm.subsecx = INT2FIX(0);
  538. vtm.utc_offset = INT2FIX(0);
  539. timexv = timegmxv_noleapsecond(&vtm);
  540. number_of_leap_seconds_known = NUM2INT(sub(TIMET2NUM(known_leap_seconds_limit), rb_time_unmagnify(timexv)));
  541. }
  542. }
  543. static VALUE
  544. timegmxv(struct vtm *vtm)
  545. {
  546. VALUE timexv;
  547. struct tm tm;
  548. time_t t;
  549. const char *errmsg;
  550. /* The first leap second is 1972-06-30 23:59:60 UTC.
  551. * No leap seconds before. */
  552. if (RTEST(gt(INT2FIX(1972), vtm->year)))
  553. return timegmxv_noleapsecond(vtm);
  554. init_leap_second_info();
  555. timexv = timegmxv_noleapsecond(vtm);
  556. if (RTEST(lt(rb_time_magnify(TIMET2NUM(known_leap_seconds_limit)), timexv))) {
  557. return add(timexv, rb_time_magnify(INT2NUM(number_of_leap_seconds_known)));
  558. }
  559. tm.tm_year = rb_long2int(NUM2LONG(vtm->year) - 1900);
  560. tm.tm_mon = vtm->mon - 1;
  561. tm.tm_mday = vtm->mday;
  562. tm.tm_hour = vtm->hour;
  563. tm.tm_min = vtm->min;
  564. tm.tm_sec = vtm->sec;
  565. tm.tm_isdst = 0;
  566. errmsg = find_time_t(&tm, 1, &t);
  567. if (errmsg)
  568. rb_raise(rb_eArgError, "%s", errmsg);
  569. return add(rb_time_magnify(TIMET2NUM(t)), vtm->subsecx);
  570. }
  571. static struct vtm *
  572. gmtimexv(VALUE timexv, struct vtm *result)
  573. {
  574. time_t t;
  575. struct tm tm;
  576. VALUE subsecx;
  577. VALUE timev;
  578. if (RTEST(lt(timexv, INT2FIX(0)))) {
  579. gmtimexv_noleapsecond(timexv, result);
  580. return result;
  581. }
  582. init_leap_second_info();
  583. if (RTEST(lt(rb_time_magnify(LONG2NUM(known_leap_seconds_limit)), timexv))) {
  584. timexv = sub(timexv, rb_time_magnify(INT2NUM(number_of_leap_seconds_known)));
  585. gmtimexv_noleapsecond(timexv, result);
  586. return result;
  587. }
  588. divmodv(timexv, INT2FIX(TIME_SCALE), &timev, &subsecx);
  589. t = NUM2TIMET(timev);
  590. if (!gmtime_with_leapsecond(&t, &tm))
  591. return NULL;
  592. result->year = LONG2NUM((long)tm.tm_year + 1900);
  593. result->mon = tm.tm_mon + 1;
  594. result->mday = tm.tm_mday;
  595. result->hour = tm.tm_hour;
  596. result->min = tm.tm_min;
  597. result->sec = tm.tm_sec;
  598. result->subsecx = subsecx;
  599. result->utc_offset = INT2FIX(0);
  600. result->wday = tm.tm_wday;
  601. result->yday = tm.tm_yday+1;
  602. result->isdst = tm.tm_isdst;
  603. result->zone = "UTC";
  604. return result;
  605. }
  606. static struct tm *localtime_with_gmtoff(const time_t *t, struct tm *result, long *gmtoff);
  607. /*
  608. * The idea is come from Perl:
  609. * http://use.perl.org/articles/08/02/07/197204.shtml
  610. *
  611. * compat_common_month_table is generated by following program.
  612. * This table finds the last month which start the same day of a week.
  613. * The year 2037 is not used because
  614. * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522949
  615. *
  616. * #!/usr/bin/ruby
  617. *
  618. * require 'date'
  619. *
  620. * h = {}
  621. * 2036.downto(2010) {|y|
  622. * 1.upto(12) {|m|
  623. * next if m == 2 && y % 4 == 0
  624. * d = Date.new(y,m,1)
  625. * h[m] ||= {}
  626. * h[m][d.wday] ||= y
  627. * }
  628. * }
  629. *
  630. * 1.upto(12) {|m|
  631. * print "{"
  632. * 0.upto(6) {|w|
  633. * y = h[m][w]
  634. * print " #{y},"
  635. * }
  636. * puts "},"
  637. * }
  638. *
  639. */
  640. static int compat_common_month_table[12][7] = {
  641. /* Sun Mon Tue Wed Thu Fri Sat */
  642. { 2034, 2035, 2036, 2031, 2032, 2027, 2033 }, /* January */
  643. { 2026, 2027, 2033, 2034, 2035, 2030, 2031 }, /* February */
  644. { 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* March */
  645. { 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* April */
  646. { 2033, 2034, 2035, 2030, 2036, 2026, 2032 }, /* May */
  647. { 2036, 2026, 2032, 2033, 2034, 2035, 2030 }, /* June */
  648. { 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* July */
  649. { 2032, 2033, 2034, 2035, 2030, 2036, 2026 }, /* August */
  650. { 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* September */
  651. { 2034, 2035, 2030, 2036, 2026, 2032, 2033 }, /* October */
  652. { 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* November */
  653. { 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* December */
  654. };
  655. /*
  656. * compat_leap_month_table is generated by following program.
  657. *
  658. * #!/usr/bin/ruby
  659. *
  660. * require 'date'
  661. *
  662. * h = {}
  663. * 2037.downto(2010) {|y|
  664. * 1.upto(12) {|m|
  665. * next unless m == 2 && y % 4 == 0
  666. * d = Date.new(y,m,1)
  667. * h[m] ||= {}
  668. * h[m][d.wday] ||= y
  669. * }
  670. * }
  671. *
  672. * 2.upto(2) {|m|
  673. * 0.upto(6) {|w|
  674. * y = h[m][w]
  675. * print " #{y},"
  676. * }
  677. * puts
  678. * }
  679. */
  680. static int compat_leap_month_table[7] = {
  681. /* Sun Mon Tue Wed Thu Fri Sat */
  682. 2032, 2016, 2028, 2012, 2024, 2036, 2020, /* February */
  683. };
  684. static int
  685. calc_wday(int year, int month, int day)
  686. {
  687. int a, y, m;
  688. int wday;
  689. a = (14 - month) / 12;
  690. y = year + 4800 - a;
  691. m = month + 12 * a - 3;
  692. wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
  693. wday = wday % 7;
  694. return wday;
  695. }
  696. static VALUE
  697. guess_local_offset(struct vtm *vtm_utc)
  698. {
  699. VALUE off = INT2FIX(0);
  700. struct tm tm;
  701. long gmtoff;
  702. time_t t;
  703. struct vtm vtm2;
  704. VALUE timev;
  705. int y, wday;
  706. # if defined(NEGATIVE_TIME_T)
  707. /* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t. */
  708. if (localtime_with_gmtoff((t = (time_t)0x80000000, &t), &tm, &gmtoff))
  709. off = LONG2FIX(gmtoff);
  710. else
  711. # endif
  712. /* 1970-01-01 00:00:00 UTC : The Unix epoch - the oldest time in portable time_t. */
  713. if (localtime_with_gmtoff((t = 0, &t), &tm, &gmtoff))
  714. off = LONG2FIX(gmtoff);
  715. /* The first DST is at 1916 in German.
  716. * So we don't need to care DST before that. */
  717. if (lt(vtm_utc->year, INT2FIX(1916)))
  718. return off;
  719. /* It is difficult to guess future. */
  720. vtm2 = *vtm_utc;
  721. /* guess using a year before 2038. */
  722. y = NUM2INT(mod(vtm_utc->year, INT2FIX(400)));
  723. wday = calc_wday(y, vtm_utc->mon, 1);
  724. if (vtm_utc->mon == 2 && leap_year_p(y))
  725. vtm2.year = INT2FIX(compat_leap_month_table[wday]);
  726. else
  727. vtm2.year = INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
  728. timev = rb_time_unmagnify(timegmxv(&vtm2));
  729. t = NUM2TIMET(timev);
  730. if (localtime_with_gmtoff(&t, &tm, &gmtoff))
  731. return LONG2FIX(gmtoff);
  732. {
  733. /* Use the current time offset as a last resort. */
  734. static time_t now = 0;
  735. static long now_gmtoff = 0;
  736. if (now == 0) {
  737. now = time(NULL);
  738. localtime_with_gmtoff(&now, &tm, &now_gmtoff);
  739. }
  740. return LONG2FIX(now_gmtoff);
  741. }
  742. }
  743. static VALUE
  744. small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
  745. {
  746. int off;
  747. off = vtm1->sec - vtm2->sec;
  748. off += (vtm1->min - vtm2->min) * 60;
  749. off += (vtm1->hour - vtm2->hour) * 3600;
  750. if (ne(vtm1->year, vtm2->year))
  751. off += lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
  752. else if (vtm1->mon != vtm2->mon)
  753. off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
  754. else if (vtm1->mday != vtm2->mday)
  755. off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
  756. return INT2FIX(off);
  757. }
  758. static VALUE
  759. timelocalxv(struct vtm *vtm)
  760. {
  761. time_t t;
  762. struct tm tm;
  763. VALUE v;
  764. VALUE timexv1, timexv2;
  765. struct vtm vtm1, vtm2;
  766. int n;
  767. if (FIXNUM_P(vtm->year)) {
  768. long l = FIX2LONG(vtm->year) - 1900;
  769. if (l < INT_MIN || INT_MAX < l)
  770. goto no_localtime;
  771. tm.tm_year = (int)l;
  772. }
  773. else {
  774. v = sub(vtm->year, INT2FIX(1900));
  775. if (lt(v, INT2NUM(INT_MIN)) || lt(INT2NUM(INT_MAX), v))
  776. goto no_localtime;
  777. tm.tm_year = NUM2INT(v);
  778. }
  779. tm.tm_mon = vtm->mon-1;
  780. tm.tm_mday = vtm->mday;
  781. tm.tm_hour = vtm->hour;
  782. tm.tm_min = vtm->min;
  783. tm.tm_sec = vtm->sec;
  784. tm.tm_isdst = vtm->isdst;
  785. if (find_time_t(&tm, 0, &t))
  786. goto no_localtime;
  787. return add(rb_time_magnify(TIMET2NUM(t)), vtm->subsecx);
  788. no_localtime:
  789. timexv1 = timegmxv(vtm);
  790. if (!localtimexv(timexv1, &vtm1))
  791. rb_raise(rb_eArgError, "localtimexv error");
  792. n = vtmcmp(vtm, &vtm1);
  793. if (n == 0) {
  794. timexv1 = sub(timexv1, rb_time_magnify(INT2FIX(12*3600)));
  795. if (!localtimexv(timexv1, &vtm1))
  796. rb_raise(rb_eArgError, "localtimexv error");
  797. n = 1;
  798. }
  799. if (n < 0) {
  800. timexv2 = timexv1;
  801. vtm2 = vtm1;
  802. timexv1 = sub(timexv1, rb_time_magnify(INT2FIX(24*3600)));
  803. if (!localtimexv(timexv1, &vtm1))
  804. rb_raise(rb_eArgError, "localtimexv error");
  805. }
  806. else {
  807. timexv2 = add(timexv1, rb_time_magnify(INT2FIX(24*3600)));
  808. if (!localtimexv(timexv2, &vtm2))
  809. rb_raise(rb_eArgError, "localtimexv error");
  810. }
  811. timexv1 = add(timexv1, rb_time_magnify(small_vtm_sub(vtm, &vtm1)));
  812. timexv2 = add(timexv2, rb_time_magnify(small_vtm_sub(vtm, &vtm2)));
  813. if (eq(timexv1, timexv2))
  814. return timexv1;
  815. if (!localtimexv(timexv1, &vtm1))
  816. rb_raise(rb_eArgError, "localtimexv error");
  817. if (vtm->hour != vtm1.hour || vtm->min != vtm1.min || vtm->sec != vtm1.sec)
  818. return timexv2;
  819. if (!localtimexv(timexv2, &vtm2))
  820. rb_raise(rb_eArgError, "localtimexv error");
  821. if (vtm->hour != vtm2.hour || vtm->min != vtm2.min || vtm->sec != vtm2.sec)
  822. return timexv1;
  823. if (vtm->isdst)
  824. return lt(vtm1.utc_offset, vtm2.utc_offset) ? timexv2 : timexv1;
  825. else
  826. return lt(vtm1.utc_offset, vtm2.utc_offset) ? timexv1 : timexv2;
  827. }
  828. static struct tm *
  829. localtime_with_gmtoff(const time_t *t, struct tm *result, long *gmtoff)
  830. {
  831. struct tm tm;
  832. if (LOCALTIME(t, tm)) {
  833. #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
  834. *gmtoff = tm.tm_gmtoff;
  835. #else
  836. struct tm *u, *l;
  837. long off;
  838. struct tm tmbuf;
  839. l = &tm;
  840. u = GMTIME(t, tmbuf);
  841. if (!u)
  842. return NULL;
  843. if (l->tm_year != u->tm_year)
  844. off = l->tm_year < u->tm_year ? -1 : 1;
  845. else if (l->tm_mon != u->tm_mon)
  846. off = l->tm_mon < u->tm_mon ? -1 : 1;
  847. else if (l->tm_mday != u->tm_mday)
  848. off = l->tm_mday < u->tm_mday ? -1 : 1;
  849. else
  850. off = 0;
  851. off = off * 24 + l->tm_hour - u->tm_hour;
  852. off = off * 60 + l->tm_min - u->tm_min;
  853. off = off * 60 + l->tm_sec - u->tm_sec;
  854. *gmtoff = off;
  855. #endif
  856. *result = tm;
  857. return result;
  858. }
  859. return NULL;
  860. }
  861. static struct vtm *
  862. localtimexv(VALUE timexv, struct vtm *result)
  863. {
  864. VALUE timev, subsecx, offset;
  865. divmodv(timexv, INT2FIX(TIME_SCALE), &timev, &subsecx);
  866. if (le(TIMET2NUM(TIMET_MIN), timev) &&
  867. le(timev, TIMET2NUM(TIMET_MAX))) {
  868. time_t t;
  869. struct tm tm;
  870. long gmtoff;
  871. t = NUM2TIMET(timev);
  872. if (localtime_with_gmtoff(&t, &tm, &gmtoff)) {
  873. result->year = LONG2NUM((long)tm.tm_year + 1900);
  874. result->mon = tm.tm_mon + 1;
  875. result->mday = tm.tm_mday;
  876. result->hour = tm.tm_hour;
  877. result->min = tm.tm_min;
  878. result->sec = tm.tm_sec;
  879. result->subsecx = subsecx;
  880. result->wday = tm.tm_wday;
  881. result->yday = tm.tm_yday+1;
  882. result->isdst = tm.tm_isdst;
  883. result->utc_offset = LONG2NUM(gmtoff);
  884. #if defined(HAVE_TM_ZONE)
  885. result->zone = zone_str(tm.tm_zone);
  886. #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
  887. /* this needs tzset or localtime, instead of localtime_r */
  888. result->zone = zone_str(tzname[daylight && tm.tm_isdst]);
  889. #else
  890. {
  891. char buf[64];
  892. strftime(buf, sizeof(buf), "%Z", &tm);
  893. result->zone = zone_str(buf);
  894. }
  895. #endif
  896. return result;
  897. }
  898. }
  899. if (!gmtimexv(timexv, result))
  900. return NULL;
  901. offset = guess_local_offset(result);
  902. if (!gmtimexv(add(timexv, rb_time_magnify(offset)), result))
  903. return NULL;
  904. result->utc_offset = offset;
  905. return result;
  906. }
  907. struct time_object {
  908. VALUE timexv; /* time_t value * TIME_SCALE. possibly Rational. */
  909. struct vtm vtm;
  910. int gmt;
  911. int tm_got;
  912. };
  913. #define GetTimeval(obj, tobj) \
  914. TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj)
  915. #define IsTimeval(obj) rb_typeddata_is_kind_of(obj, &time_data_type)
  916. #define TIME_UTC_P(tobj) ((tobj)->gmt == 1)
  917. #define TIME_SET_UTC(tobj) ((tobj)->gmt = 1)
  918. #define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0)
  919. #define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0)
  920. #define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2)
  921. #define TIME_SET_FIXOFF(tobj, off) \
  922. ((tobj)->gmt = 2, \
  923. (tobj)->vtm.utc_offset = (off), \
  924. (tobj)->vtm.zone = NULL)
  925. #define TIME_COPY_GMT(tobj1, tobj2) ((tobj1)->gmt = (tobj2)->gmt)
  926. static VALUE time_get_tm(VALUE, struct time_object *);
  927. #define MAKE_TM(time, tobj) \
  928. do { \
  929. if ((tobj)->tm_got == 0) { \
  930. time_get_tm((time), (tobj)); \
  931. } \
  932. } while (0)
  933. static void
  934. time_mark(void *ptr)
  935. {
  936. struct time_object *tobj = ptr;
  937. if (!tobj) return;
  938. rb_gc_mark(tobj->timexv);
  939. rb_gc_mark(tobj->vtm.year);
  940. rb_gc_mark(tobj->vtm.subsecx);
  941. rb_gc_mark(tobj->vtm.utc_offset);
  942. }
  943. static void
  944. time_free(void *tobj)
  945. {
  946. if (tobj) xfree(tobj);
  947. }
  948. static size_t
  949. time_memsize(const void *tobj)
  950. {
  951. return tobj ? sizeof(struct time_object) : 0;
  952. }
  953. static const rb_data_type_t time_data_type = {
  954. "time",
  955. time_mark, time_free, time_memsize,
  956. };
  957. static VALUE
  958. time_s_alloc(VALUE klass)
  959. {
  960. VALUE obj;
  961. struct time_object *tobj;
  962. obj = TypedData_Make_Struct(klass, struct time_object, &time_data_type, tobj);
  963. tobj->tm_got=0;
  964. tobj->timexv = INT2FIX(0);
  965. return obj;
  966. }
  967. static void
  968. time_modify(VALUE time)
  969. {
  970. rb_check_frozen(time);
  971. if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
  972. rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
  973. }
  974. static VALUE
  975. timespec2timexv(struct timespec *ts)
  976. {
  977. VALUE timexv;
  978. timexv = rb_time_magnify(TIMET2NUM(ts->tv_sec));
  979. if (ts->tv_nsec)
  980. timexv = add(timexv, mulquo(LONG2NUM(ts->tv_nsec), INT2FIX(TIME_SCALE), INT2FIX(1000000000)));
  981. return timexv;
  982. }
  983. static struct timespec
  984. timexv2timespec(VALUE timexv)
  985. {
  986. VALUE timev, subsecx;
  987. struct timespec ts;
  988. divmodv(timexv, INT2FIX(TIME_SCALE), &timev, &subsecx);
  989. if (lt(timev, TIMET2NUM(TIMET_MIN)) || lt(TIMET2NUM(TIMET_MAX), timev))
  990. rb_raise(rb_eArgError, "time out of system range");
  991. ts.tv_sec = NUM2TIMET(timev);
  992. ts.tv_nsec = NUM2LONG(mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE)));
  993. return ts;
  994. }
  995. /*
  996. * Document-method: now
  997. *
  998. * Synonym for <code>Time.new</code>. Returns a +Time+ object
  999. * initialized to the current system time.
  1000. */
  1001. static VALUE
  1002. time_init_0(VALUE time)
  1003. {
  1004. struct time_object *tobj;
  1005. struct timespec ts;
  1006. time_modify(time);
  1007. GetTimeval(time, tobj);
  1008. tobj->tm_got=0;
  1009. tobj->timexv = INT2FIX(0);
  1010. #ifdef HAVE_CLOCK_GETTIME
  1011. if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
  1012. rb_sys_fail("clock_gettime");
  1013. }
  1014. #else
  1015. {
  1016. struct timeval tv;
  1017. if (gettimeofday(&tv, 0) < 0) {
  1018. rb_sys_fail("gettimeofday");
  1019. }
  1020. ts.tv_sec = tv.tv_sec;
  1021. ts.tv_nsec = tv.tv_usec * 1000;
  1022. }
  1023. #endif
  1024. tobj->timexv = timespec2timexv(&ts);
  1025. return time;
  1026. }
  1027. static VALUE
  1028. time_set_utc_offset(VALUE time, VALUE off)
  1029. {
  1030. struct time_object *tobj;
  1031. off = num_exact(off);
  1032. time_modify(time);
  1033. GetTimeval(time, tobj);
  1034. tobj->tm_got = 0;
  1035. TIME_SET_FIXOFF(tobj, off);
  1036. return time;
  1037. }
  1038. static void
  1039. vtm_add_offset(struct vtm *vtm, VALUE off)
  1040. {
  1041. int sign;
  1042. VALUE subsec, v;
  1043. int sec, min, hour;
  1044. int day;
  1045. vtm->utc_offset = sub(vtm->utc_offset, off);
  1046. if (RTEST(lt(off, INT2FIX(0)))) {
  1047. sign = -1;
  1048. off = neg(off);
  1049. }
  1050. else {
  1051. sign = 1;
  1052. }
  1053. divmodv(off, INT2FIX(1), &off, &subsec);
  1054. divmodv(off, INT2FIX(60), &off, &v);
  1055. sec = NUM2INT(v);
  1056. divmodv(off, INT2FIX(60), &off, &v);
  1057. min = NUM2INT(v);
  1058. divmodv(off, INT2FIX(24), &off, &v);
  1059. hour = NUM2INT(v);
  1060. if (sign < 0) {
  1061. subsec = neg(subsec);
  1062. sec = -sec;
  1063. min = -min;
  1064. hour = -hour;
  1065. }
  1066. day = 0;
  1067. if (!rb_equal(subsec, INT2FIX(0))) {
  1068. vtm->subsecx = add(vtm->subsecx, rb_time_magnify(subsec));
  1069. if (lt(vtm->subsecx, INT2FIX(0))) {
  1070. vtm->subsecx = add(vtm->subsecx, INT2FIX(TIME_SCALE));
  1071. sec -= 1;
  1072. }
  1073. if (le(INT2FIX(TIME_SCALE), vtm->subsecx)) {
  1074. vtm->subsecx = sub(vtm->subsecx, INT2FIX(TIME_SCALE));
  1075. sec += 1;
  1076. }
  1077. goto not_zero_sec;
  1078. }
  1079. if (sec) {
  1080. not_zero_sec:
  1081. /* If sec + subsec == 0, don't change vtm->sec.
  1082. * It may be 60 which is a leap second. */
  1083. vtm->sec += sec;
  1084. if (vtm->sec < 0) {
  1085. vtm->sec += 60;
  1086. min -= 1;
  1087. }
  1088. if (60 <= vtm->sec) {
  1089. vtm->sec -= 60;
  1090. min += 1;
  1091. }
  1092. }
  1093. if (min) {
  1094. vtm->min += min;
  1095. if (vtm->min < 0) {
  1096. vtm->min += 60;
  1097. hour -= 1;
  1098. }
  1099. if (60 <= vtm->min) {
  1100. vtm->min -= 60;
  1101. hour += 1;
  1102. }
  1103. }
  1104. if (hour) {
  1105. vtm->hour += hour;
  1106. if (vtm->hour < 0) {
  1107. vtm->hour += 24;
  1108. day = -1;
  1109. }
  1110. if (24 <= vtm->hour) {
  1111. vtm->hour -= 24;
  1112. day = 1;
  1113. }
  1114. }
  1115. if (day) {
  1116. if (day < 0) {
  1117. if (vtm->mon == 1 && vtm->mday == 1) {
  1118. vtm->mday = 31;
  1119. vtm->mon = 12; /* December */
  1120. vtm->year = sub(vtm->year, INT2FIX(1));
  1121. vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
  1122. }
  1123. else if (vtm->mday == 1) {
  1124. const int *days_in_month = leap_year_v_p(vtm->year) ?
  1125. leap_year_days_in_month :
  1126. common_year_days_in_month;
  1127. vtm->mon--;
  1128. vtm->mday = days_in_month[vtm->mon-1];
  1129. vtm->yday--;
  1130. }
  1131. else {
  1132. vtm->mday--;
  1133. vtm->yday--;
  1134. }
  1135. vtm->wday = (vtm->wday + 6) % 7;
  1136. }
  1137. else {
  1138. int leap = leap_year_v_p(vtm->year);
  1139. if (vtm->mon == 12 && vtm->mday == 31) {
  1140. vtm->year = add(vtm->year, INT2FIX(1));
  1141. vtm->mon = 1; /* January */
  1142. vtm->mday = 1;
  1143. vtm->yday = 1;
  1144. }
  1145. else if (vtm->mday == (leap ? leap_year_days_in_month :
  1146. common_year_days_in_month)[vtm->mon-1]) {
  1147. vtm->mon++;
  1148. vtm->mday = 1;
  1149. vtm->yday++;
  1150. }
  1151. else {
  1152. vtm->mday++;
  1153. vtm->yday++;
  1154. }
  1155. vtm->wday = (vtm->wday + 1) % 7;
  1156. }
  1157. }
  1158. }
  1159. static VALUE
  1160. utc_offset_arg(VALUE arg)
  1161. {
  1162. VALUE tmp;
  1163. if (!NIL_P(tmp = rb_check_string_type(arg))) {
  1164. int n;
  1165. char *s = RSTRING_PTR(tmp);
  1166. if (!rb_enc_str_asciicompat_p(tmp) ||
  1167. RSTRING_LEN(tmp) != 6 ||
  1168. (s[0] != '+' && s[0] != '-') ||
  1169. !ISDIGIT(s[1]) ||
  1170. !ISDIGIT(s[2]) ||
  1171. s[3] != ':' ||
  1172. !ISDIGIT(s[4]) ||
  1173. !ISDIGIT(s[5]))
  1174. rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
  1175. n = (s[1] * 10 + s[2] - '0' * 11) * 3600;
  1176. n += (s[4] * 10 + s[5] - '0' * 11) * 60;
  1177. if (s[0] == '-')
  1178. n = -n;
  1179. return INT2FIX(n);
  1180. }
  1181. else {
  1182. return num_exact(arg);
  1183. }
  1184. }
  1185. static VALUE
  1186. time_init_1(int argc, VALUE *argv, VALUE time)
  1187. {
  1188. struct vtm vtm;
  1189. VALUE v[7];
  1190. struct time_object *tobj;
  1191. vtm.wday = -1;
  1192. vtm.yday = 0;
  1193. vtm.zone = "";
  1194. /* year mon mday hour min sec off */
  1195. rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
  1196. vtm.year = obj2vint(v[0]);
  1197. vtm.mon = NIL_P(v[1]) ? 1 : month_arg(v[1]);
  1198. vtm.mday = NIL_P(v[2]) ? 1 : obj2int(v[2]);
  1199. vtm.hour = NIL_P(v[3]) ? 0 : obj2int(v[3]);
  1200. vtm.min = NIL_P(v[4]) ? 0 : obj2int(v[4]);
  1201. vtm.sec = 0;
  1202. vtm.subsecx = INT2FIX(0);
  1203. if (!NIL_P(v[5])) {
  1204. VALUE sec = num_exact(v[5]);
  1205. VALUE subsec;
  1206. divmodv(sec, INT2FIX(1), &sec, &subsec);
  1207. vtm.sec = NUM2INT(sec);
  1208. vtm.subsecx = rb_time_magnify(subsec);
  1209. }
  1210. vtm.isdst = -1;
  1211. vtm.utc_offset = Qnil;
  1212. if (!NIL_P(v[6])) {
  1213. VALUE arg = v[6];
  1214. if (arg == ID2SYM(rb_intern("dst")))
  1215. vtm.isdst = 1;
  1216. else if (arg == ID2SYM(rb_intern("std")))
  1217. vtm.isdst = 0;
  1218. else
  1219. vtm.utc_offset = utc_offset_arg(arg);
  1220. }
  1221. validate_vtm(&vtm);
  1222. time_modify(time);
  1223. GetTimeval(time, tobj);
  1224. tobj->tm_got=0;
  1225. tobj->timexv = INT2FIX(0);
  1226. if (!NIL_P(vtm.utc_offset)) {
  1227. VALUE off = vtm.utc_offset;
  1228. vtm_add_offset(&vtm, neg(off));
  1229. vtm.utc_offset = Qnil;
  1230. tobj->timexv = timegmxv(&vtm);
  1231. return time_set_utc_offset(time, off);
  1232. }
  1233. else {
  1234. tobj->timexv = timelocalxv(&vtm);
  1235. return time_localtime(time);
  1236. }
  1237. }
  1238. /*
  1239. * call-seq:
  1240. * Time.new -> time
  1241. * Time.new(year) -> time
  1242. * Time.new(year, month) -> time
  1243. * Time.new(year, month, day) -> time
  1244. * Time.new(year, month, day, hour) -> time
  1245. * Time.new(year, month, day, hour, min) -> time
  1246. * Time.new(year, month, day, hour, min, sec) -> time
  1247. * Time.new(year, month, day, hour, min, sec, utc_offset) -> time
  1248. *
  1249. * Returns a <code>Time</code> object.
  1250. *
  1251. * It is initialized to the current system time if no argument.
  1252. * <b>Note:</b> The object created will be created using the
  1253. * resolution available on your system clock, and so may include
  1254. * fractional seconds.
  1255. *
  1256. * If one or more arguments specified, the time is initialized
  1257. * to the specified time.
  1258. * _sec_ may have fraction if it is a rational.
  1259. *
  1260. * _utc_offset_ is the offset from UTC.
  1261. * It is a string such as "+09:00" or a number of seconds such as 32400.
  1262. *
  1263. * a = Time.new #=> 2007-11-19 07:50:02 -0600
  1264. * b = Time.new #=> 2007-11-19 07:50:02 -0600
  1265. * a == b #=> false
  1266. * "%.6f" % a.to_f #=> "1195480202.282373"
  1267. * "%.6f" % b.to_f #=> "1195480202.283415"
  1268. *
  1269. * Time.new(2008,6,21, 13,30,0, "+09:00") #=> 2008-06-21 13:30:00 +0900
  1270. *
  1271. * # A trip for RubyConf 2007
  1272. * t1 = Time.new(2007,11,1,15,25,0, "+09:00") # JST (Narita)
  1273. * t2 = Time.new(2007,11,1,12, 5,0, "-05:00") # CDT (Minneapolis)
  1274. * t3 = Time.new(2007,11,1,13,25,0, "-05:00") # CDT (Minneapolis)
  1275. * t4 = Time.new(2007,11,1,16,53,0, "-04:00") # EDT (Charlotte)
  1276. * t5 = Time.new(2007,11,5, 9,24,0, "-05:00") # EST (Charlotte)
  1277. * t6 = Time.new(2007,11,5,11,21,0, "-05:00") # EST (Detroit)
  1278. * t7 = Time.new(2007,11,5,13,45,0, "-05:00") # EST (Detroit)
  1279. * t8 = Time.new(2007,11,6,17,10,0, "+09:00") # JST (Narita)
  1280. * p((t2-t1)/3600.0) #=> 10.666666666666666
  1281. * p((t4-t3)/3600.0) #=> 2.466666666666667
  1282. * p((t6-t5)/3600.0) #=> 1.95
  1283. * p((t8-t7)/3600.0) #=> 13.416666666666666
  1284. *
  1285. */
  1286. static VALUE
  1287. time_init(int argc, VALUE *argv, VALUE time)
  1288. {
  1289. if (argc == 0)
  1290. return time_init_0(time);
  1291. else
  1292. return time_init_1(argc, argv, time);
  1293. }
  1294. static void
  1295. time_overflow_p(time_t *secp, long *nsecp)
  1296. {
  1297. time_t tmp, sec = *secp;
  1298. long nsec = *nsecp;
  1299. if (nsec >= 1000000000) { /* nsec positive overflow */
  1300. tmp = sec + nsec / 1000000000;
  1301. nsec %= 1000000000;
  1302. if (sec > 0 && tmp < 0) {
  1303. rb_raise(rb_eRangeError, "out of Time range");
  1304. }
  1305. sec = tmp;
  1306. }
  1307. if (nsec < 0) { /* nsec negative overflow */
  1308. tmp = sec + NDIV(nsec,1000000000); /* negative div */
  1309. nsec = NMOD(nsec,1000000000); /* negative mod */
  1310. if (sec < 0 && tmp > 0) {
  1311. rb_raise(rb_eRangeError, "out of Time range");
  1312. }
  1313. sec = tmp;
  1314. }
  1315. #ifndef NEGATIVE_TIME_T
  1316. if (sec < 0)
  1317. rb_raise(rb_eArgError, "time must be positive");
  1318. #endif
  1319. *secp = sec;
  1320. *nsecp = nsec;
  1321. }
  1322. static VALUE nsec2timexv(time_t sec, long nsec)
  1323. {
  1324. struct timespec ts;
  1325. time_overflow_p(&sec, &nsec);
  1326. ts.tv_sec = sec;
  1327. ts.tv_nsec = nsec;
  1328. return timespec2timexv(&ts);
  1329. }
  1330. static VALUE
  1331. time_new_internal(VALUE klass, VALUE timexv)
  1332. {
  1333. VALUE time = time_s_alloc(klass);
  1334. struct time_object *tobj;
  1335. GetTimeval(time, tobj);
  1336. tobj->timexv = num_exact(timexv);
  1337. return time;
  1338. }
  1339. VALUE
  1340. rb_time_new(time_t sec, long usec)
  1341. {
  1342. return time_new_internal(rb_cTime, nsec2timexv(sec, usec * 1000));
  1343. }
  1344. VALUE
  1345. rb_time_nano_new(time_t sec, long nsec)
  1346. {
  1347. return time_new_internal(rb_cTime, nsec2timexv(sec, nsec));
  1348. }
  1349. VALUE
  1350. rb_time_num_new(VALUE timev, VALUE off)
  1351. {
  1352. VALUE time = time_new_internal(rb_cTime, rb_time_magnify(timev));
  1353. if (!NIL_P(off)) {
  1354. off = utc_offset_arg(off);
  1355. validate_utc_offset(off);
  1356. time_set_utc_offset(time, off);
  1357. return time;
  1358. }
  1359. return time;
  1360. }
  1361. static VALUE
  1362. time_new_timexv(VALUE klass, VALUE timexv)
  1363. {
  1364. VALUE time = time_s_alloc(klass);
  1365. struct time_object *tobj;
  1366. GetTimeval(time, tobj);
  1367. tobj->timexv = timexv;
  1368. return time;
  1369. }
  1370. static struct timespec
  1371. time_timespec(VALUE num, int interval)
  1372. {
  1373. struct timespec t;
  1374. const char *tstr = interval ? "time interval" : "time";
  1375. VALUE i, f, ary;
  1376. #ifndef NEGATIVE_TIME_T
  1377. interval = 1;
  1378. #endif
  1379. switch (TYPE(num)) {
  1380. case T_FIXNUM:
  1381. t.tv_sec = NUM2TIMET(num);
  1382. if (interval && t.tv_sec < 0)
  1383. rb_raise(rb_eArgError, "%s must be positive", tstr);
  1384. t.tv_nsec = 0;
  1385. break;
  1386. case T_FLOAT:
  1387. if (interval && RFLOAT_VALUE(num) < 0.0)
  1388. rb_raise(rb_eArgError, "%s must be positive", tstr);
  1389. else {
  1390. double f, d;
  1391. d = modf(RFLOAT_VALUE(num), &f);
  1392. if (d >= 0) {
  1393. t.tv_nsec = (int)(d*1e9+0.5);
  1394. }
  1395. else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) {
  1396. t.tv_nsec = 1000000000 - t.tv_nsec;
  1397. f -= 1;
  1398. }
  1399. t.tv_sec = (time_t)f;
  1400. if (f != t.tv_sec) {
  1401. rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(num));
  1402. }
  1403. }
  1404. break;
  1405. case T_BIGNUM:
  1406. t.tv_sec = NUM2TIMET(num);
  1407. if (interval && t.tv_sec < 0)
  1408. rb_raise(rb_eArgError, "%s must be positive", tstr);
  1409. t.tv_nsec = 0;
  1410. break;
  1411. default:
  1412. if (rb_respond_to(num, id_divmod)) {
  1413. ary = rb_check_array_type(rb_funcall(num, id_divmod, 1, INT2FIX(1)));
  1414. if (NIL_P(ary)) {
  1415. goto typeerror;
  1416. }
  1417. i = rb_ary_entry(ary, 0);
  1418. f = rb_ary_entry(ary, 1);
  1419. t.tv_sec = NUM2TIMET(i);
  1420. if (interval && t.tv_sec < 0)
  1421. rb_raise(rb_eArgError, "%s must be positive", tstr);
  1422. f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
  1423. t.tv_nsec = NUM2LONG(f);
  1424. }
  1425. else {
  1426. typeerror:
  1427. rb_raise(rb_eTypeError, "can't convert %s into %s",
  1428. rb_obj_classname(num), tstr);
  1429. }
  1430. break;
  1431. }
  1432. return t;
  1433. }
  1434. static struct timeval
  1435. time_timeval(VALUE num, int interval)
  1436. {
  1437. struct timespec ts;
  1438. struct timeval tv;
  1439. ts = time_timespec(num, interval);
  1440. tv.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
  1441. tv.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
  1442. return tv;
  1443. }
  1444. struct timeval
  1445. rb_time_interval(VALUE num)
  1446. {
  1447. return time_timeval(num, TRUE);
  1448. }
  1449. struct timeval
  1450. rb_time_timeval(VALUE time)
  1451. {
  1452. struct time_object *tobj;
  1453. struct timeval t;
  1454. struct timespec ts;
  1455. if (IsTimeval(time)) {
  1456. GetTimeval(time, tobj);
  1457. ts = timexv2timespec(tobj->timexv);
  1458. t.tv_sec = (TYPEOF_TIMEVAL_TV_SEC)ts.tv_sec;
  1459. t.tv_usec = (TYPEOF_TIMEVAL_TV_USEC)(ts.tv_nsec / 1000);
  1460. return t;
  1461. }
  1462. return time_timeval(time, FALSE);
  1463. }
  1464. struct timespec
  1465. rb_time_timespec(VALUE time)
  1466. {
  1467. struct time_object *tobj;
  1468. struct timespec t;
  1469. if (IsTimeval(time)) {
  1470. GetTimeval(time, tobj);
  1471. t = timexv2timespec(tobj->timexv);
  1472. return t;
  1473. }
  1474. return time_timespec(time, FALSE);
  1475. }
  1476. /*
  1477. * call-seq:
  1478. * Time.now => time
  1479. *
  1480. * Creates a new time object for the current time.
  1481. *
  1482. * Time.now #=> 2009-06-24 12:39:54 +0900
  1483. */
  1484. static VALUE
  1485. time_s_now(VALUE klass)
  1486. {
  1487. return rb_class_new_instance(0, NULL, klass);
  1488. }
  1489. /*
  1490. * call-seq:
  1491. * Time.at(time) => time
  1492. * Time.at(seconds_with_frac) => time
  1493. * Time.at(seconds, microseconds_with_frac) => time
  1494. *
  1495. * Creates a new time object with the value given by <i>time</i>,
  1496. * the given number of <i>seconds_with_frac</i>, or
  1497. * <i>seconds</i> and <i>microseconds_with_frac</i> from the Epoch.
  1498. * <i>seconds_with_frac</i> and <i>microseconds_with_frac</i>
  1499. * can be Integer, Float, Rational, or other Numeric.
  1500. * non-portable feature allows the offset to be negative on some systems.
  1501. *
  1502. * Time.at(0) #=> 1969-12-31 18:00:00 -0600
  1503. * Time.at(Time.at(0)) #=> 1969-12-31 18:00:00 -0600
  1504. * Time.at(946702800) #=> 1999-12-31 23:00:00 -0600
  1505. * Time.at(-284061600) #=> 1960-12-31 00:00:00 -0600
  1506. * Time.at(946684800.2).usec #=> 200000
  1507. * Time.at(946684800, 123456.789).nsec #=> 123456789
  1508. */
  1509. static VALUE
  1510. time_s_at(int argc, VALUE *argv, VALUE klass)
  1511. {
  1512. VALUE time, t, timexv;
  1513. if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
  1514. time = num_exact(time);
  1515. t = num_exact(t);
  1516. timexv = add(rb_time_magnify(time), mulquo(t, INT2FIX(TIME_SCALE), INT2FIX(1000000)));
  1517. t = time_new_timexv(klass, timexv);
  1518. }
  1519. else if (IsTimeval(time)) {
  1520. struct time_object *tobj, *tobj2;
  1521. GetTimeval(time, tobj);
  1522. t = time_new_timexv(klass, tobj->timexv);
  1523. GetTimeval(t, tobj2);
  1524. TIME_COPY_GMT(tobj2, tobj);
  1525. }
  1526. else {
  1527. timexv = rb_time_magnify(num_exact(time));
  1528. t = time_new_timexv(klass, timexv);
  1529. }
  1530. return t;
  1531. }
  1532. static const char months[][4] = {
  1533. "jan", "feb", "mar", "apr", "may", "jun",
  1534. "jul", "aug", "sep", "oct", "nov", "dec",
  1535. };
  1536. static int
  1537. obj2int(VALUE obj)
  1538. {
  1539. if (TYPE(obj) == T_STRING) {
  1540. obj = rb_str_to_inum(obj, 10, FALSE);
  1541. }
  1542. return NUM2INT(obj);
  1543. }
  1544. static VALUE
  1545. obj2vint(VALUE obj)
  1546. {
  1547. if (TYPE(obj) == T_STRING) {
  1548. obj = rb_str_to_inum(obj, 10, FALSE);
  1549. }
  1550. else {
  1551. obj = rb_to_int(obj);
  1552. }
  1553. return obj;
  1554. }
  1555. static int
  1556. obj2subsecx(VALUE obj, VALUE *subsecx)
  1557. {
  1558. VALUE subsec;
  1559. if (TYPE(obj) == T_STRING) {
  1560. obj = rb_str_to_inum(obj, 10, FALSE);
  1561. *subsecx = INT2FIX(0);
  1562. return NUM2INT(obj);
  1563. }
  1564. divmodv(num_exact(obj), INT2FIX(1), &obj, &subsec);
  1565. *subsecx = rb_time_magnify(subsec);
  1566. return NUM2INT(obj);
  1567. }
  1568. static long
  1569. usec2subsecx(VALUE obj)
  1570. {
  1571. if (TYPE(obj) == T_STRING) {
  1572. obj = rb_str_to_inum(obj, 10, FALSE);
  1573. }
  1574. return mulquo(num_exact(obj), INT2FIX(TIME_SCALE), INT2FIX(1000000));
  1575. }
  1576. static int
  1577. month_arg(VALUE arg)
  1578. {
  1579. int i, mon;
  1580. VALUE s = rb_check_string_type(arg);
  1581. if (!NIL_P(s)) {
  1582. mon = 0;
  1583. for (i=0; i<12; i++) {
  1584. if (RSTRING_LEN(s) == 3 &&
  1585. STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
  1586. mon = i+1;
  1587. break;
  1588. }
  1589. }
  1590. if (mon == 0) {
  1591. char c = RSTRING_PTR(s)[0];
  1592. if ('0' <= c && c <= '9') {
  1593. mon = obj2int(s);
  1594. }
  1595. }
  1596. }
  1597. else {
  1598. mon = obj2int(arg);
  1599. }
  1600. return mon;
  1601. }
  1602. static void
  1603. validate_utc_offset(VALUE utc_offset)
  1604. {
  1605. if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400)))
  1606. rb_raise(rb_eArgError, "utc_offset out of range");
  1607. }
  1608. static void
  1609. validate_vtm(struct vtm *vtm)
  1610. {
  1611. if ( vtm->mon < 1 || vtm->mon > 12
  1612. || vtm->mday < 1 || vtm->mday > 31
  1613. || vtm->hour < 0 || vtm->hour > 24
  1614. || (vtm->hour == 24 && (vtm->min > 0 || vtm->sec > 0))
  1615. || vtm->min < 0 || vtm->min > 59
  1616. || vtm->sec < 0 || vtm->sec > 60
  1617. || lt(vtm->subsecx, INT2FIX(0)) || ge(vtm->subsecx, INT2FIX(TIME_SCALE))
  1618. || (!NIL_P(vtm->utc_offset) && (validate_utc_offset(vtm->utc_offset), 0)))
  1619. rb_raise(rb_eArgError, "argument out of range");
  1620. }
  1621. static void
  1622. time_arg(int argc, VALUE *argv, struct vtm *vtm)
  1623. {
  1624. VALUE v[8];
  1625. vtm->year = INT2FIX(0);
  1626. vtm->mon = 0;
  1627. vtm->mday = 0;
  1628. vtm->hour = 0;
  1629. vtm->min = 0;
  1630. vtm->sec = 0;
  1631. vtm->subsecx = INT2FIX(0);
  1632. vtm->utc_offset = Qnil;
  1633. vtm->wday = 0;
  1634. vtm->yday = 0;
  1635. vtm->isdst = 0;
  1636. vtm->zone = "";
  1637. if (argc == 10) {
  1638. v[0] = argv[5];
  1639. v[1] = argv[4];
  1640. v[2] = argv[3];
  1641. v[3] = argv[2];
  1642. v[4] = argv[1];
  1643. v[5] = argv[0];
  1644. v[6] = Qnil;
  1645. vtm->isdst = RTEST(argv[8]) ? 1 : 0;
  1646. }
  1647. else {
  1648. rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
  1649. /* v[6] may be usec or zone (parsedate) */
  1650. /* v[7] is wday (parsedate; ignored) */
  1651. vtm->wday = -1;
  1652. vtm->isdst = -1;
  1653. }
  1654. vtm->year = obj2vint(v[0]);
  1655. if (NIL_P(v[1])) {
  1656. vtm->mon = 1;
  1657. }
  1658. else {
  1659. vtm->mon = month_arg(v[1]);
  1660. }
  1661. if (NIL_P(v[2])) {
  1662. vtm->mday = 1;
  1663. }
  1664. else {
  1665. vtm->mday = obj2int(v[2]);
  1666. }
  1667. vtm->hour = NIL_P(v[3])?0:obj2int(v[3]);
  1668. vtm->min = NIL_P(v[4])?0:obj2int(v[4]);
  1669. if (!NIL_P(v[6]) && argc == 7) {
  1670. vtm->sec = NIL_P(v[5])?0:obj2int(v[5]);
  1671. vtm->subsecx = usec2subsecx(v[6]);
  1672. }
  1673. else {
  1674. /* when argc == 8, v[6] is timezone, but ignored */
  1675. vtm->sec = NIL_P(v[5])?0:obj2subsecx(v[5], &vtm->subsecx);
  1676. }
  1677. validate_vtm(vtm);
  1678. }
  1679. static int
  1680. leap_year_p(long y)
  1681. {
  1682. return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
  1683. }
  1684. static time_t
  1685. timegm_noleapsecond(struct tm *tm)
  1686. {
  1687. long tm_year = tm->tm_year;
  1688. int tm_yday = tm->tm_mday;
  1689. if (leap_year_p(tm_year + 1900))
  1690. tm_yday += leap_year_yday_offset[tm->tm_mon];
  1691. else
  1692. tm_yday += common_year_yday_offset[tm->tm_mon];
  1693. /*
  1694. * `Seconds Since the Epoch' in SUSv3:
  1695. * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
  1696. * (tm_year-70)*31536000 + ((tm_year-69…

Large files files are truncated, but you can click here to view the full file