PageRenderTime 42ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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)/4)*86400 -
  1697. * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
  1698. */
  1699. return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
  1700. (time_t)(tm_yday +
  1701. (tm_year-70)*365 +
  1702. DIV(tm_year-69,4) -
  1703. DIV(tm_year-1,100) +
  1704. DIV(tm_year+299,400))*86400;
  1705. }
  1706. #if 0
  1707. #define DEBUG_FIND_TIME_NUMGUESS
  1708. #define DEBUG_GUESSRANGE
  1709. #endif
  1710. #ifdef DEBUG_GUESSRANGE
  1711. #define DEBUG_REPORT_GUESSRANGE fprintf(stderr, "find time guess range: %ld - %ld : %lu\n", guess_lo, guess_hi, (unsigned_time_t)(guess_hi-guess_lo))
  1712. #else
  1713. #define DEBUG_REPORT_GUESSRANGE
  1714. #endif
  1715. #ifdef DEBUG_FIND_TIME_NUMGUESS
  1716. #define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
  1717. static unsigned long long find_time_numguess;
  1718. static VALUE find_time_numguess_getter(void)
  1719. {
  1720. return ULL2NUM(find_time_numguess);
  1721. }
  1722. #else
  1723. #define DEBUG_FIND_TIME_NUMGUESS_INC
  1724. #endif
  1725. static const char *
  1726. find_time_t(struct tm *tptr, int utc_p, time_t *tp)
  1727. {
  1728. time_t guess, guess0, guess_lo, guess_hi;
  1729. struct tm *tm, tm0, tm_lo, tm_hi;
  1730. int d;
  1731. int find_dst;
  1732. struct tm result;
  1733. int status;
  1734. #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond(p, &result) : LOCALTIME(p, result)))
  1735. guess_lo = TIMET_MIN;
  1736. guess_hi = TIMET_MAX;
  1737. find_dst = 0 < tptr->tm_isdst;
  1738. #if defined(HAVE_MKTIME)
  1739. tm0 = *tptr;
  1740. if (!utc_p && (guess = mktime(&tm0)) != -1) {
  1741. tm = GUESS(&guess);
  1742. if (tm && tmcmp(tptr, tm) == 0) {
  1743. goto found;
  1744. }
  1745. }
  1746. #endif
  1747. tm0 = *tptr;
  1748. if (tm0.tm_mon < 0) {
  1749. tm0.tm_mon = 0;
  1750. tm0.tm_mday = 1;
  1751. tm0.tm_hour = 0;
  1752. tm0.tm_min = 0;
  1753. tm0.tm_sec = 0;
  1754. }
  1755. else if (11 < tm0.tm_mon) {
  1756. tm0.tm_mon = 11;
  1757. tm0.tm_mday = 31;
  1758. tm0.tm_hour = 23;
  1759. tm0.tm_min = 59;
  1760. tm0.tm_sec = 60;
  1761. }
  1762. else if (tm0.tm_mday < 1) {
  1763. tm0.tm_mday = 1;
  1764. tm0.tm_hour = 0;
  1765. tm0.tm_min = 0;
  1766. tm0.tm_sec = 0;
  1767. }
  1768. else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
  1769. leap_year_days_in_month :
  1770. common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
  1771. tm0.tm_mday = d;
  1772. tm0.tm_hour = 23;
  1773. tm0.tm_min = 59;
  1774. tm0.tm_sec = 60;
  1775. }
  1776. else if (tm0.tm_hour < 0) {
  1777. tm0.tm_hour = 0;
  1778. tm0.tm_min = 0;
  1779. tm0.tm_sec = 0;
  1780. }
  1781. else if (23 < tm0.tm_hour) {
  1782. tm0.tm_hour = 23;
  1783. tm0.tm_min = 59;
  1784. tm0.tm_sec = 60;
  1785. }
  1786. else if (tm0.tm_min < 0) {
  1787. tm0.tm_min = 0;
  1788. tm0.tm_sec = 0;
  1789. }
  1790. else if (59 < tm0.tm_min) {
  1791. tm0.tm_min = 59;
  1792. tm0.tm_sec = 60;
  1793. }
  1794. else if (tm0.tm_sec < 0) {
  1795. tm0.tm_sec = 0;
  1796. }
  1797. else if (60 < tm0.tm_sec) {
  1798. tm0.tm_sec = 60;
  1799. }
  1800. DEBUG_REPORT_GUESSRANGE;
  1801. guess0 = guess = timegm_noleapsecond(&tm0);
  1802. tm = GUESS(&guess);
  1803. if (tm) {
  1804. d = tmcmp(tptr, tm);
  1805. if (d == 0) { goto found; }
  1806. if (d < 0) {
  1807. guess_hi = guess;
  1808. guess -= 24 * 60 * 60;
  1809. }
  1810. else {
  1811. guess_lo = guess;
  1812. guess += 24 * 60 * 60;
  1813. }
  1814. DEBUG_REPORT_GUESSRANGE;
  1815. if (guess_lo < guess && guess < guess_hi && (tm = GUESS(&guess)) != NULL) {
  1816. d = tmcmp(tptr, tm);
  1817. if (d == 0) { goto found; }
  1818. if (d < 0)
  1819. guess_hi = guess;
  1820. else
  1821. guess_lo = guess;
  1822. DEBUG_REPORT_GUESSRANGE;
  1823. }
  1824. }
  1825. tm = GUESS(&guess_lo);
  1826. if (!tm) goto error;
  1827. d = tmcmp(tptr, tm);
  1828. if (d < 0) goto out_of_range;
  1829. if (d == 0) { guess = guess_lo; goto found; }
  1830. tm_lo = *tm;
  1831. tm = GUESS(&guess_hi);
  1832. if (!tm) goto error;
  1833. d = tmcmp(tptr, tm);
  1834. if (d > 0) goto out_of_range;
  1835. if (d == 0) { guess = guess_hi; goto found; }
  1836. tm_hi = *tm;
  1837. DEBUG_REPORT_GUESSRANGE;
  1838. status = 1;
  1839. while (guess_lo + 1 < guess_hi) {
  1840. if (status == 0) {
  1841. binsearch:
  1842. guess = guess_lo / 2 + guess_hi / 2;
  1843. if (guess <= guess_lo)
  1844. guess = guess_lo + 1;
  1845. else if (guess >= guess_hi)
  1846. guess = guess_hi - 1;
  1847. status = 1;
  1848. }
  1849. else {
  1850. if (status == 1) {
  1851. time_t guess0_hi = timegm_noleapsecond(&tm_hi);
  1852. guess = guess_hi - (guess0_hi - guess0);
  1853. if (guess == guess_hi) /* hh:mm:60 tends to cause this condition. */
  1854. guess--;
  1855. status = 2;
  1856. }
  1857. else if (status == 2) {
  1858. time_t guess0_lo = timegm_noleapsecond(&tm_lo);
  1859. guess = guess_lo + (guess0 - guess0_lo);
  1860. if (guess == guess_lo)
  1861. guess++;
  1862. status = 0;
  1863. }
  1864. if (guess <= guess_lo || guess_hi <= guess) {
  1865. /* Precious guess is invalid. try binary search. */
  1866. #ifdef DEBUG_GUESSRANGE
  1867. if (guess <= guess_lo) fprintf(stderr, "too small guess: %ld <= %ld\n", guess, guess_lo);
  1868. if (guess_hi <= guess) fprintf(stderr, "too big guess: %ld <= %ld\n", guess_hi, guess);
  1869. #endif
  1870. goto binsearch;
  1871. }
  1872. }
  1873. tm = GUESS(&guess);
  1874. if (!tm) goto error;
  1875. d = tmcmp(tptr, tm);
  1876. if (d < 0) {
  1877. guess_hi = guess;
  1878. tm_hi = *tm;
  1879. DEBUG_REPORT_GUESSRANGE;
  1880. }
  1881. else if (d > 0) {
  1882. guess_lo = guess;
  1883. tm_lo = *tm;
  1884. DEBUG_REPORT_GUESSRANGE;
  1885. }
  1886. else {
  1887. found:
  1888. if (!utc_p) {
  1889. /* If localtime is nonmonotonic, another result may exist. */
  1890. time_t guess2;
  1891. if (find_dst) {
  1892. guess2 = guess - 2 * 60 * 60;
  1893. tm = LOCALTIME(&guess2, result);
  1894. if (tm) {
  1895. if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
  1896. tptr->tm_min != tm->tm_min ||
  1897. tptr->tm_sec != tm->tm_sec) {
  1898. guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
  1899. (tm->tm_min - tptr->tm_min) * 60 +
  1900. (tm->tm_sec - tptr->tm_sec);
  1901. if (tptr->tm_mday != tm->tm_mday)
  1902. guess2 += 24 * 60 * 60;
  1903. if (guess != guess2) {
  1904. tm = LOCALTIME(&guess2, result);
  1905. if (tmcmp(tptr, tm) == 0) {
  1906. if (guess < guess2)
  1907. *tp = guess;
  1908. else
  1909. *tp = guess2;
  1910. return NULL;
  1911. }
  1912. }
  1913. }
  1914. }
  1915. }
  1916. else {
  1917. guess2 = guess + 2 * 60 * 60;
  1918. tm = LOCALTIME(&guess2, result);
  1919. if (tm) {
  1920. if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
  1921. tptr->tm_min != tm->tm_min ||
  1922. tptr->tm_sec != tm->tm_sec) {
  1923. guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
  1924. (tm->tm_min - tptr->tm_min) * 60 +
  1925. (tm->tm_sec - tptr->tm_sec);
  1926. if (tptr->tm_mday != tm->tm_mday)
  1927. guess2 -= 24 * 60 * 60;
  1928. if (guess != guess2) {
  1929. tm = LOCALTIME(&guess2, result);
  1930. if (tmcmp(tptr, tm) == 0) {
  1931. if (guess < guess2)
  1932. *tp = guess2;
  1933. else
  1934. *tp = guess;
  1935. return NULL;
  1936. }
  1937. }
  1938. }
  1939. }
  1940. }
  1941. }
  1942. *tp = guess;
  1943. return NULL;
  1944. }
  1945. }
  1946. /* Given argument has no corresponding time_t. Let's outerpolation. */
  1947. if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) {
  1948. *tp = guess_lo +
  1949. (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 +
  1950. (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 +
  1951. (tptr->tm_min - tm_lo.tm_min) * 60 +
  1952. (tptr->tm_sec - tm_lo.tm_sec);
  1953. return NULL;
  1954. }
  1955. else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
  1956. *tp = guess_hi +
  1957. (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
  1958. (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
  1959. (tptr->tm_min - tm_hi.tm_min) * 60 +
  1960. (tptr->tm_sec - tm_hi.tm_sec);
  1961. return NULL;
  1962. }
  1963. out_of_range:
  1964. return "time out of range";
  1965. error:
  1966. return "gmtime/localtime error";
  1967. }
  1968. static int
  1969. vtmcmp(struct vtm *a, struct vtm *b)
  1970. {
  1971. if (ne(a->year, b->year))
  1972. return lt(a->year, b->year) ? -1 : 1;
  1973. else if (a->mon != b->mon)
  1974. return a->mon < b->mon ? -1 : 1;
  1975. else if (a->mday != b->mday)
  1976. return a->mday < b->mday ? -1 : 1;
  1977. else if (a->hour != b->hour)
  1978. return a->hour < b->hour ? -1 : 1;
  1979. else if (a->min != b->min)
  1980. return a->min < b->min ? -1 : 1;
  1981. else if (a->sec != b->sec)
  1982. return a->sec < b->sec ? -1 : 1;
  1983. else if (ne(a->subsecx, b->subsecx))
  1984. return lt(a->subsecx, b->subsecx) ? -1 : 1;
  1985. else
  1986. return 0;
  1987. }
  1988. static int
  1989. tmcmp(struct tm *a, struct tm *b)
  1990. {
  1991. if (a->tm_year != b->tm_year)
  1992. return a->tm_year < b->tm_year ? -1 : 1;
  1993. else if (a->tm_mon != b->tm_mon)
  1994. return a->tm_mon < b->tm_mon ? -1 : 1;
  1995. else if (a->tm_mday != b->tm_mday)
  1996. return a->tm_mday < b->tm_mday ? -1 : 1;
  1997. else if (a->tm_hour != b->tm_hour)
  1998. return a->tm_hour < b->tm_hour ? -1 : 1;
  1999. else if (a->tm_min != b->tm_min)
  2000. return a->tm_min < b->tm_min ? -1 : 1;
  2001. else if (a->tm_sec != b->tm_sec)
  2002. return a->tm_sec < b->tm_sec ? -1 : 1;
  2003. else
  2004. return 0;
  2005. }
  2006. static VALUE
  2007. time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
  2008. {
  2009. struct vtm vtm;
  2010. VALUE time;
  2011. time_arg(argc, argv, &vtm);
  2012. if (utc_p)
  2013. time = time_new_timexv(klass, timegmxv(&vtm));
  2014. else
  2015. time = time_new_timexv(klass, timelocalxv(&vtm));
  2016. if (utc_p) return time_gmtime(time);
  2017. return time_localtime(time);
  2018. }
  2019. /*
  2020. * call-seq:
  2021. * Time.utc(year) => time
  2022. * Time.utc(year, month) => time
  2023. * Time.utc(year, month, day) => time
  2024. * Time.utc(year, month, day, hour) => time
  2025. * Time.utc(year, month, day, hour, min) => time
  2026. * Time.utc(year, month, day, hour, min, sec_with_frac) => time
  2027. * Time.utc(year, month, day, hour, min, sec, usec_with_frac) => time
  2028. * Time.utc(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
  2029. * Time.gm(year) => time
  2030. * Time.gm(year, month) => time
  2031. * Time.gm(year, month, day) => time
  2032. * Time.gm(year, month, day, hour) => time
  2033. * Time.gm(year, month, day, hour, min) => time
  2034. * Time.gm(year, month, day, hour, min, sec_with_frac) => time
  2035. * Time.gm(year, month, day, hour, min, sec, usec_with_frac) => time
  2036. * Time.gm(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
  2037. *
  2038. * Creates a time based on given values, interpreted as UTC (GMT). The
  2039. * year must be specified. Other values default to the minimum value
  2040. * for that field (and may be <code>nil</code> or omitted). Months may
  2041. * be specified by numbers from 1 to 12, or by the three-letter English
  2042. * month names. Hours are specified on a 24-hour clock (0..23). Raises
  2043. * an <code>ArgumentError</code> if any values are out of range. Will
  2044. * also accept ten arguments in the order output by
  2045. * <code>Time#to_a</code>.
  2046. * <i>sec_with_frac</i> and <i>usec_with_frac</i> can have a fractional part.
  2047. *
  2048. * Time.utc(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2049. * Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2050. */
  2051. static VALUE
  2052. time_s_mkutc(int argc, VALUE *argv, VALUE klass)
  2053. {
  2054. return time_utc_or_local(argc, argv, TRUE, klass);
  2055. }
  2056. /*
  2057. * call-seq:
  2058. * Time.local(year) => time
  2059. * Time.local(year, month) => time
  2060. * Time.local(year, month, day) => time
  2061. * Time.local(year, month, day, hour) => time
  2062. * Time.local(year, month, day, hour, min) => time
  2063. * Time.local(year, month, day, hour, min, sec_with_frac) => time
  2064. * Time.local(year, month, day, hour, min, sec, usec_with_frac) => time
  2065. * Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
  2066. * Time.mktime(year) => time
  2067. * Time.mktime(year, month) => time
  2068. * Time.mktime(year, month, day) => time
  2069. * Time.mktime(year, month, day, hour) => time
  2070. * Time.mktime(year, month, day, hour, min) => time
  2071. * Time.mktime(year, month, day, hour, min, sec_with_frac) => time
  2072. * Time.mktime(year, month, day, hour, min, sec, usec_with_frac) => time
  2073. * Time.mktime(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
  2074. *
  2075. * Same as <code>Time::gm</code>, but interprets the values in the
  2076. * local time zone.
  2077. *
  2078. * Time.local(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 -0600
  2079. */
  2080. static VALUE
  2081. time_s_mktime(int argc, VALUE *argv, VALUE klass)
  2082. {
  2083. return time_utc_or_local(argc, argv, FALSE, klass);
  2084. }
  2085. /*
  2086. * call-seq:
  2087. * time.to_i => int
  2088. * time.tv_sec => int
  2089. *
  2090. * Returns the value of <i>time</i> as an integer number of seconds
  2091. * since the Epoch.
  2092. *
  2093. * t = Time.now
  2094. * "%10.5f" % t.to_f #=> "1049896564.17839"
  2095. * t.to_i #=> 1049896564
  2096. */
  2097. static VALUE
  2098. time_to_i(VALUE time)
  2099. {
  2100. struct time_object *tobj;
  2101. GetTimeval(time, tobj);
  2102. return div(tobj->timexv, INT2FIX(TIME_SCALE));
  2103. }
  2104. /*
  2105. * call-seq:
  2106. * time.to_f => float
  2107. *
  2108. * Returns the value of <i>time</i> as a floating point number of
  2109. * seconds since the Epoch.
  2110. *
  2111. * t = Time.now
  2112. * "%10.5f" % t.to_f #=> "1049896564.13654"
  2113. * t.to_i #=> 1049896564
  2114. *
  2115. * Note that IEEE 754 double is not accurate enough to represent
  2116. * nanoseconds from the Epoch.
  2117. */
  2118. static VALUE
  2119. time_to_f(VALUE time)
  2120. {
  2121. struct time_object *tobj;
  2122. GetTimeval(time, tobj);
  2123. return rb_Float(rb_time_unmagnify(tobj->timexv));
  2124. }
  2125. /*
  2126. * call-seq:
  2127. * time.to_r => Rational
  2128. *
  2129. * Returns the value of <i>time</i> as a rational number of seconds
  2130. * since the Epoch.
  2131. *
  2132. * t = Time.now
  2133. * p t.to_r #=> (8807170717088293/8388608)
  2134. *
  2135. * This methods is intended to be used to get an accurate value
  2136. * representing nanoseconds from the Epoch. You can use this
  2137. * to convert time to another Epoch.
  2138. */
  2139. static VALUE
  2140. time_to_r(VALUE time)
  2141. {
  2142. struct time_object *tobj;
  2143. VALUE v;
  2144. GetTimeval(time, tobj);
  2145. v = rb_time_unmagnify(tobj->timexv);
  2146. if (TYPE(v) != T_RATIONAL) {
  2147. v = rb_convert_type(v, T_RATIONAL, "Rational", "to_r");
  2148. }
  2149. return v;
  2150. }
  2151. /*
  2152. * call-seq:
  2153. * time.usec => int
  2154. * time.tv_usec => int
  2155. *
  2156. * Returns just the number of microseconds for <i>time</i>.
  2157. *
  2158. * t = Time.now #=> 2007-11-19 08:03:26 -0600
  2159. * "%10.6f" % t.to_f #=> "1195481006.775195"
  2160. * t.usec #=> 775195
  2161. */
  2162. static VALUE
  2163. time_usec(VALUE time)
  2164. {
  2165. struct time_object *tobj;
  2166. GetTimeval(time, tobj);
  2167. return rb_to_int(mulquo(mod(tobj->timexv, INT2FIX(TIME_SCALE)), INT2FIX(1000000), INT2FIX(TIME_SCALE)));
  2168. }
  2169. /*
  2170. * call-seq:
  2171. * time.nsec => int
  2172. * time.tv_nsec => int
  2173. *
  2174. * Returns just the number of nanoseconds for <i>time</i>.
  2175. *
  2176. * t = Time.now #=> 2007-11-17 15:18:03 +0900
  2177. * "%10.9f" % t.to_f #=> "1195280283.536151409"
  2178. * t.nsec #=> 536151406
  2179. *
  2180. * The lowest digit of to_f and nsec is different because
  2181. * IEEE 754 double is not accurate enough to represent
  2182. * nanoseconds from the Epoch.
  2183. * The accurate value is returned by nsec.
  2184. */
  2185. static VALUE
  2186. time_nsec(VALUE time)
  2187. {
  2188. struct time_object *tobj;
  2189. GetTimeval(time, tobj);
  2190. return rb_to_int(mulquo(mod(tobj->timexv, INT2FIX(TIME_SCALE)), INT2FIX(1000000000), INT2FIX(TIME_SCALE)));
  2191. }
  2192. /*
  2193. * call-seq:
  2194. * time.subsec => number
  2195. *
  2196. * Returns just the fraction for <i>time</i>.
  2197. *
  2198. * The result is possibly rational.
  2199. *
  2200. * t = Time.now #=> 2009-03-26 22:33:12 +0900
  2201. * "%10.9f" % t.to_f #=> "1238074392.940563917"
  2202. * t.subsec #=> (94056401/100000000)
  2203. *
  2204. * The lowest digit of to_f and subsec is different because
  2205. * IEEE 754 double is not accurate enough to represent
  2206. * the rational.
  2207. * The accurate value is returned by subsec.
  2208. */
  2209. static VALUE
  2210. time_subsec(VALUE time)
  2211. {
  2212. struct time_object *tobj;
  2213. GetTimeval(time, tobj);
  2214. return quo(mod(tobj->timexv, INT2FIX(TIME_SCALE)), INT2FIX(TIME_SCALE));
  2215. }
  2216. /*
  2217. * call-seq:
  2218. * time <=> other_time => -1, 0, +1 or nil
  2219. *
  2220. * Comparison---Compares <i>time</i> with <i>other_time</i>.
  2221. *
  2222. * t = Time.now #=> 2007-11-19 08:12:12 -0600
  2223. * t2 = t + 2592000 #=> 2007-12-19 08:12:12 -0600
  2224. * t <=> t2 #=> -1
  2225. * t2 <=> t #=> 1
  2226. *
  2227. * t = Time.now #=> 2007-11-19 08:13:38 -0600
  2228. * t2 = t + 0.1 #=> 2007-11-19 08:13:38 -0600
  2229. * t.nsec #=> 98222999
  2230. * t2.nsec #=> 198222999
  2231. * t <=> t2 #=> -1
  2232. * t2 <=> t #=> 1
  2233. * t <=> t #=> 0
  2234. */
  2235. static VALUE
  2236. time_cmp(VALUE time1, VALUE time2)
  2237. {
  2238. struct time_object *tobj1, *tobj2;
  2239. int n;
  2240. GetTimeval(time1, tobj1);
  2241. if (IsTimeval(time2)) {
  2242. GetTimeval(time2, tobj2);
  2243. n = rb_cmpint(cmp(tobj1->timexv, tobj2->timexv), tobj1->timexv, tobj2->timexv);
  2244. }
  2245. else {
  2246. VALUE cmp;
  2247. cmp = rb_funcall(time2, rb_intern("<=>"), 1, time1);
  2248. if (NIL_P(cmp)) return Qnil;
  2249. n = -rb_cmpint(cmp, time1, time2);
  2250. }
  2251. if (n == 0) return INT2FIX(0);
  2252. if (n > 0) return INT2FIX(1);
  2253. return INT2FIX(-1);
  2254. }
  2255. /*
  2256. * call-seq:
  2257. * time.eql?(other_time)
  2258. *
  2259. * Return <code>true</code> if <i>time</i> and <i>other_time</i> are
  2260. * both <code>Time</code> objects with the same seconds and fractional
  2261. * seconds.
  2262. */
  2263. static VALUE
  2264. time_eql(VALUE time1, VALUE time2)
  2265. {
  2266. struct time_object *tobj1, *tobj2;
  2267. GetTimeval(time1, tobj1);
  2268. if (IsTimeval(time2)) {
  2269. GetTimeval(time2, tobj2);
  2270. return rb_equal(tobj1->timexv, tobj2->timexv);
  2271. }
  2272. return Qfalse;
  2273. }
  2274. /*
  2275. * call-seq:
  2276. * time.utc? => true or false
  2277. * time.gmt? => true or false
  2278. *
  2279. * Returns <code>true</code> if <i>time</i> represents a time in UTC
  2280. * (GMT).
  2281. *
  2282. * t = Time.now #=> 2007-11-19 08:15:23 -0600
  2283. * t.utc? #=> false
  2284. * t = Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2285. * t.utc? #=> true
  2286. *
  2287. * t = Time.now #=> 2007-11-19 08:16:03 -0600
  2288. * t.gmt? #=> false
  2289. * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2290. * t.gmt? #=> true
  2291. */
  2292. static VALUE
  2293. time_utc_p(VALUE time)
  2294. {
  2295. struct time_object *tobj;
  2296. GetTimeval(time, tobj);
  2297. if (TIME_UTC_P(tobj)) return Qtrue;
  2298. return Qfalse;
  2299. }
  2300. /*
  2301. * call-seq:
  2302. * time.hash => fixnum
  2303. *
  2304. * Return a hash code for this time object.
  2305. */
  2306. static VALUE
  2307. time_hash(VALUE time)
  2308. {
  2309. struct time_object *tobj;
  2310. GetTimeval(time, tobj);
  2311. return rb_hash(tobj->timexv);
  2312. }
  2313. /* :nodoc: */
  2314. static VALUE
  2315. time_init_copy(VALUE copy, VALUE time)
  2316. {
  2317. struct time_object *tobj, *tcopy;
  2318. if (copy == time) return copy;
  2319. time_modify(copy);
  2320. GetTimeval(time, tobj);
  2321. GetTimeval(copy, tcopy);
  2322. MEMCPY(tcopy, tobj, struct time_object, 1);
  2323. return copy;
  2324. }
  2325. static VALUE
  2326. time_dup(VALUE time)
  2327. {
  2328. VALUE dup = time_s_alloc(CLASS_OF(time));
  2329. time_init_copy(dup, time);
  2330. return dup;
  2331. }
  2332. static VALUE
  2333. time_localtime(VALUE time)
  2334. {
  2335. struct time_object *tobj;
  2336. struct vtm vtm;
  2337. GetTimeval(time, tobj);
  2338. if (TIME_LOCALTIME_P(tobj)) {
  2339. if (tobj->tm_got)
  2340. return time;
  2341. }
  2342. else {
  2343. time_modify(time);
  2344. }
  2345. if (!localtimexv(tobj->timexv, &vtm))
  2346. rb_raise(rb_eArgError, "localtime error");
  2347. tobj->vtm = vtm;
  2348. tobj->tm_got = 1;
  2349. TIME_SET_LOCALTIME(tobj);
  2350. return time;
  2351. }
  2352. /*
  2353. * call-seq:
  2354. * time.localtime => time
  2355. * time.localtime(utc_offset) => time
  2356. *
  2357. * Converts <i>time</i> to local time (using the local time zone in
  2358. * effect for this process) modifying the receiver.
  2359. *
  2360. * If _utc_offset_ is given, it is used instead of the local time.
  2361. *
  2362. * t = Time.utc(2000, "jan", 1, 20, 15, 1) #=> 2000-01-01 20:15:01 UTC
  2363. * t.utc? #=> true
  2364. *
  2365. * t.localtime #=> 2000-01-01 14:15:01 -0600
  2366. * t.utc? #=> false
  2367. *
  2368. * t.localtime("+09:00") #=> 2000-01-02 05:15:01 +0900
  2369. * t.utc? #=> false
  2370. */
  2371. static VALUE
  2372. time_localtime_m(int argc, VALUE *argv, VALUE time)
  2373. {
  2374. VALUE off;
  2375. rb_scan_args(argc, argv, "01", &off);
  2376. if (!NIL_P(off)) {
  2377. off = utc_offset_arg(off);
  2378. validate_utc_offset(off);
  2379. time_set_utc_offset(time, off);
  2380. return time_fixoff(time);
  2381. }
  2382. return time_localtime(time);
  2383. }
  2384. /*
  2385. * call-seq:
  2386. * time.gmtime => time
  2387. * time.utc => time
  2388. *
  2389. * Converts <i>time</i> to UTC (GMT), modifying the receiver.
  2390. *
  2391. * t = Time.now #=> 2007-11-19 08:18:31 -0600
  2392. * t.gmt? #=> false
  2393. * t.gmtime #=> 2007-11-19 14:18:31 UTC
  2394. * t.gmt? #=> true
  2395. *
  2396. * t = Time.now #=> 2007-11-19 08:18:51 -0600
  2397. * t.utc? #=> false
  2398. * t.utc #=> 2007-11-19 14:18:51 UTC
  2399. * t.utc? #=> true
  2400. */
  2401. static VALUE
  2402. time_gmtime(VALUE time)
  2403. {
  2404. struct time_object *tobj;
  2405. struct vtm vtm;
  2406. GetTimeval(time, tobj);
  2407. if (TIME_UTC_P(tobj)) {
  2408. if (tobj->tm_got)
  2409. return time;
  2410. }
  2411. else {
  2412. time_modify(time);
  2413. }
  2414. if (!gmtimexv(tobj->timexv, &vtm))
  2415. rb_raise(rb_eArgError, "gmtime error");
  2416. tobj->vtm = vtm;
  2417. tobj->tm_got = 1;
  2418. TIME_SET_UTC(tobj);
  2419. return time;
  2420. }
  2421. static VALUE
  2422. time_fixoff(VALUE time)
  2423. {
  2424. struct time_object *tobj;
  2425. struct vtm vtm;
  2426. VALUE off;
  2427. GetTimeval(time, tobj);
  2428. if (TIME_FIXOFF_P(tobj)) {
  2429. if (tobj->tm_got)
  2430. return time;
  2431. }
  2432. else {
  2433. time_modify(time);
  2434. }
  2435. if (TIME_FIXOFF_P(tobj))
  2436. off = tobj->vtm.utc_offset;
  2437. else
  2438. off = INT2FIX(0);
  2439. if (!gmtimexv(tobj->timexv, &vtm))
  2440. rb_raise(rb_eArgError, "gmtime error");
  2441. tobj->vtm = vtm;
  2442. vtm_add_offset(&tobj->vtm, off);
  2443. tobj->tm_got = 1;
  2444. TIME_SET_FIXOFF(tobj, off);
  2445. return time;
  2446. }
  2447. /*
  2448. * call-seq:
  2449. * time.getlocal => new_time
  2450. * time.getlocal(utc_offset) => new_time
  2451. *
  2452. * Returns a new <code>new_time</code> object representing <i>time</i> in
  2453. * local time (using the local time zone in effect for this process).
  2454. *
  2455. * If _utc_offset_ is given, it is used instead of the local time.
  2456. *
  2457. * t = Time.utc(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2458. * t.utc? #=> true
  2459. *
  2460. * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
  2461. * l.utc? #=> false
  2462. * t == l #=> true
  2463. *
  2464. * j = t.getlocal("+09:00") #=> 2000-01-02 05:15:01 +0900
  2465. * j.utc? #=> false
  2466. * t == j #=> true
  2467. */
  2468. static VALUE
  2469. time_getlocaltime(int argc, VALUE *argv, VALUE time)
  2470. {
  2471. VALUE off;
  2472. rb_scan_args(argc, argv, "01", &off);
  2473. if (!NIL_P(off)) {
  2474. off = utc_offset_arg(off);
  2475. validate_utc_offset(off);
  2476. time = time_dup(time);
  2477. time_set_utc_offset(time, off);
  2478. return time_fixoff(time);
  2479. }
  2480. return time_localtime(time_dup(time));
  2481. }
  2482. /*
  2483. * call-seq:
  2484. * time.getgm => new_time
  2485. * time.getutc => new_time
  2486. *
  2487. * Returns a new <code>new_time</code> object representing <i>time</i> in
  2488. * UTC.
  2489. *
  2490. * t = Time.local(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 -0600
  2491. * t.gmt? #=> false
  2492. * y = t.getgm #=> 2000-01-02 02:15:01 UTC
  2493. * y.gmt? #=> true
  2494. * t == y #=> true
  2495. */
  2496. static VALUE
  2497. time_getgmtime(VALUE time)
  2498. {
  2499. return time_gmtime(time_dup(time));
  2500. }
  2501. static VALUE
  2502. time_get_tm(VALUE time, struct time_object *tobj)
  2503. {
  2504. if (TIME_UTC_P(tobj)) return time_gmtime(time);
  2505. if (TIME_FIXOFF_P(tobj)) return time_fixoff(time);
  2506. return time_localtime(time);
  2507. }
  2508. static VALUE strftimev(const char *fmt, VALUE time);
  2509. /*
  2510. * call-seq:
  2511. * time.asctime => string
  2512. * time.ctime => string
  2513. *
  2514. * Returns a canonical string representation of <i>time</i>.
  2515. *
  2516. * Time.now.asctime #=> "Wed Apr 9 08:56:03 2003"
  2517. */
  2518. static VALUE
  2519. time_asctime(VALUE time)
  2520. {
  2521. struct time_object *tobj;
  2522. GetTimeval(time, tobj);
  2523. return strftimev("%a %b %e %T %Y", time);
  2524. }
  2525. /*
  2526. * call-seq:
  2527. * time.inspect => string
  2528. * time.to_s => string
  2529. *
  2530. * Returns a string representing <i>time</i>. Equivalent to calling
  2531. * <code>Time#strftime</code> with a format string of
  2532. * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>%z</code>''
  2533. * for a local time and
  2534. * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>UTC</code>''
  2535. * for a UTC time.
  2536. *
  2537. * Time.now.to_s #=> "2007-10-05 16:09:51 +0900"
  2538. * Time.now.utc.to_s #=> "2007-10-05 07:09:51 UTC"
  2539. */
  2540. static VALUE
  2541. time_to_s(VALUE time)
  2542. {
  2543. struct time_object *tobj;
  2544. GetTimeval(time, tobj);
  2545. if (TIME_UTC_P(tobj))
  2546. return strftimev("%Y-%m-%d %H:%M:%S UTC", time);
  2547. else
  2548. return strftimev("%Y-%m-%d %H:%M:%S %z", time);
  2549. }
  2550. static VALUE
  2551. time_add(struct time_object *tobj, VALUE offset, int sign)
  2552. {
  2553. VALUE result;
  2554. offset = num_exact(offset);
  2555. if (sign < 0)
  2556. result = time_new_timexv(rb_cTime, sub(tobj->timexv, rb_time_magnify(offset)));
  2557. else
  2558. result = time_new_timexv(rb_cTime, add(tobj->timexv, rb_time_magnify(offset)));
  2559. if (TIME_UTC_P(tobj)) {
  2560. GetTimeval(result, tobj);
  2561. TIME_SET_UTC(tobj);
  2562. }
  2563. return result;
  2564. }
  2565. /*
  2566. * call-seq:
  2567. * time + numeric => time
  2568. *
  2569. * Addition---Adds some number of seconds (possibly fractional) to
  2570. * <i>time</i> and returns that value as a new time.
  2571. *
  2572. * t = Time.now #=> 2007-11-19 08:22:21 -0600
  2573. * t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
  2574. */
  2575. static VALUE
  2576. time_plus(VALUE time1, VALUE time2)
  2577. {
  2578. struct time_object *tobj;
  2579. GetTimeval(time1, tobj);
  2580. if (IsTimeval(time2)) {
  2581. rb_raise(rb_eTypeError, "time + time?");
  2582. }
  2583. return time_add(tobj, time2, 1);
  2584. }
  2585. /*
  2586. * call-seq:
  2587. * time - other_time => float
  2588. * time - numeric => time
  2589. *
  2590. * Difference---Returns a new time that represents the difference
  2591. * between two times, or subtracts the given number of seconds in
  2592. * <i>numeric</i> from <i>time</i>.
  2593. *
  2594. * t = Time.now #=> 2007-11-19 08:23:10 -0600
  2595. * t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
  2596. * t2 - t #=> 2592000.0
  2597. * t2 - 2592000 #=> 2007-11-19 08:23:10 -0600
  2598. */
  2599. static VALUE
  2600. time_minus(VALUE time1, VALUE time2)
  2601. {
  2602. struct time_object *tobj;
  2603. GetTimeval(time1, tobj);
  2604. if (IsTimeval(time2)) {
  2605. struct time_object *tobj2;
  2606. GetTimeval(time2, tobj2);
  2607. return rb_Float(rb_time_unmagnify(sub(tobj->timexv, tobj2->timexv)));
  2608. }
  2609. return time_add(tobj, time2, -1);
  2610. }
  2611. /*
  2612. * call-seq:
  2613. * time.succ => new_time
  2614. *
  2615. * Return a new time object, one second later than <code>time</code>.
  2616. * Time#succ is obsolete since 1.9.2 for time is not a discrete value.
  2617. *
  2618. * t = Time.now #=> 2007-11-19 08:23:57 -0600
  2619. * t.succ #=> 2007-11-19 08:23:58 -0600
  2620. */
  2621. VALUE
  2622. rb_time_succ(VALUE time)
  2623. {
  2624. struct time_object *tobj;
  2625. struct time_object *tobj2;
  2626. rb_warn("Time#succ is obsolete; use time + 1");
  2627. GetTimeval(time, tobj);
  2628. time = time_new_timexv(rb_cTime, add(tobj->timexv, INT2FIX(TIME_SCALE)));
  2629. GetTimeval(time, tobj2);
  2630. TIME_COPY_GMT(tobj2, tobj);
  2631. return time;
  2632. }
  2633. #define time_succ rb_time_succ
  2634. /*
  2635. * call-seq:
  2636. * time.sec => fixnum
  2637. *
  2638. * Returns the second of the minute (0..60)<em>[Yes, seconds really can
  2639. * range from zero to 60. This allows the system to inject leap seconds
  2640. * every now and then to correct for the fact that years are not really
  2641. * a convenient number of hours long.]</em> for <i>time</i>.
  2642. *
  2643. * t = Time.now #=> 2007-11-19 08:25:02 -0600
  2644. * t.sec #=> 2
  2645. */
  2646. static VALUE
  2647. time_sec(VALUE time)
  2648. {
  2649. struct time_object *tobj;
  2650. GetTimeval(time, tobj);
  2651. MAKE_TM(time, tobj);
  2652. return INT2FIX(tobj->vtm.sec);
  2653. }
  2654. /*
  2655. * call-seq:
  2656. * time.min => fixnum
  2657. *
  2658. * Returns the minute of the hour (0..59) for <i>time</i>.
  2659. *
  2660. * t = Time.now #=> 2007-11-19 08:25:51 -0600
  2661. * t.min #=> 25
  2662. */
  2663. static VALUE
  2664. time_min(VALUE time)
  2665. {
  2666. struct time_object *tobj;
  2667. GetTimeval(time, tobj);
  2668. MAKE_TM(time, tobj);
  2669. return INT2FIX(tobj->vtm.min);
  2670. }
  2671. /*
  2672. * call-seq:
  2673. * time.hour => fixnum
  2674. *
  2675. * Returns the hour of the day (0..23) for <i>time</i>.
  2676. *
  2677. * t = Time.now #=> 2007-11-19 08:26:20 -0600
  2678. * t.hour #=> 8
  2679. */
  2680. static VALUE
  2681. time_hour(VALUE time)
  2682. {
  2683. struct time_object *tobj;
  2684. GetTimeval(time, tobj);
  2685. MAKE_TM(time, tobj);
  2686. return INT2FIX(tobj->vtm.hour);
  2687. }
  2688. /*
  2689. * call-seq:
  2690. * time.day => fixnum
  2691. * time.mday => fixnum
  2692. *
  2693. * Returns the day of the month (1..n) for <i>time</i>.
  2694. *
  2695. * t = Time.now #=> 2007-11-19 08:27:03 -0600
  2696. * t.day #=> 19
  2697. * t.mday #=> 19
  2698. */
  2699. static VALUE
  2700. time_mday(VALUE time)
  2701. {
  2702. struct time_object *tobj;
  2703. GetTimeval(time, tobj);
  2704. MAKE_TM(time, tobj);
  2705. return INT2FIX(tobj->vtm.mday);
  2706. }
  2707. /*
  2708. * call-seq:
  2709. * time.mon => fixnum
  2710. * time.month => fixnum
  2711. *
  2712. * Returns the month of the year (1..12) for <i>time</i>.
  2713. *
  2714. * t = Time.now #=> 2007-11-19 08:27:30 -0600
  2715. * t.mon #=> 11
  2716. * t.month #=> 11
  2717. */
  2718. static VALUE
  2719. time_mon(VALUE time)
  2720. {
  2721. struct time_object *tobj;
  2722. GetTimeval(time, tobj);
  2723. MAKE_TM(time, tobj);
  2724. return INT2FIX(tobj->vtm.mon);
  2725. }
  2726. /*
  2727. * call-seq:
  2728. * time.year => fixnum
  2729. *
  2730. * Returns the year for <i>time</i> (including the century).
  2731. *
  2732. * t = Time.now #=> 2007-11-19 08:27:51 -0600
  2733. * t.year #=> 2007
  2734. */
  2735. static VALUE
  2736. time_year(VALUE time)
  2737. {
  2738. struct time_object *tobj;
  2739. GetTimeval(time, tobj);
  2740. MAKE_TM(time, tobj);
  2741. return tobj->vtm.year;
  2742. }
  2743. /*
  2744. * call-seq:
  2745. * time.wday => fixnum
  2746. *
  2747. * Returns an integer representing the day of the week, 0..6, with
  2748. * Sunday == 0.
  2749. *
  2750. * t = Time.now #=> 2007-11-20 02:35:35 -0600
  2751. * t.wday #=> 2
  2752. * t.sunday? #=> false
  2753. * t.monday? #=> false
  2754. * t.tuesday? #=> true
  2755. * t.wednesday? #=> false
  2756. * t.thursday? #=> false
  2757. * t.friday? #=> false
  2758. * t.saturday? #=> false
  2759. */
  2760. static VALUE
  2761. time_wday(VALUE time)
  2762. {
  2763. struct time_object *tobj;
  2764. GetTimeval(time, tobj);
  2765. MAKE_TM(time, tobj);
  2766. return INT2FIX(tobj->vtm.wday);
  2767. }
  2768. #define wday_p(n) {\
  2769. struct time_object *tobj;\
  2770. GetTimeval(time, tobj);\
  2771. MAKE_TM(time, tobj);\
  2772. return (tobj->vtm.wday == (n)) ? Qtrue : Qfalse;\
  2773. }
  2774. /*
  2775. * call-seq:
  2776. * time.sunday? => true or false
  2777. *
  2778. * Returns <code>true</code> if <i>time</i> represents Sunday.
  2779. *
  2780. * t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
  2781. * t.sunday? #=> true
  2782. */
  2783. static VALUE
  2784. time_sunday(VALUE time)
  2785. {
  2786. wday_p(0);
  2787. }
  2788. /*
  2789. * call-seq:
  2790. * time.monday? => true or false
  2791. *
  2792. * Returns <code>true</code> if <i>time</i> represents Monday.
  2793. *
  2794. * t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
  2795. * p t.monday? #=> true
  2796. */
  2797. static VALUE
  2798. time_monday(VALUE time)
  2799. {
  2800. wday_p(1);
  2801. }
  2802. /*
  2803. * call-seq:
  2804. * time.tuesday? => true or false
  2805. *
  2806. * Returns <code>true</code> if <i>time</i> represents Tuesday.
  2807. *
  2808. * t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
  2809. * p t.tuesday? #=> true
  2810. */
  2811. static VALUE
  2812. time_tuesday(VALUE time)
  2813. {
  2814. wday_p(2);
  2815. }
  2816. /*
  2817. * call-seq:
  2818. * time.wednesday? => true or false
  2819. *
  2820. * Returns <code>true</code> if <i>time</i> represents Wednesday.
  2821. *
  2822. * t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
  2823. * p t.wednesday? #=> true
  2824. */
  2825. static VALUE
  2826. time_wednesday(VALUE time)
  2827. {
  2828. wday_p(3);
  2829. }
  2830. /*
  2831. * call-seq:
  2832. * time.thursday? => true or false
  2833. *
  2834. * Returns <code>true</code> if <i>time</i> represents Thursday.
  2835. *
  2836. * t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
  2837. * p t.thursday? #=> true
  2838. */
  2839. static VALUE
  2840. time_thursday(VALUE time)
  2841. {
  2842. wday_p(4);
  2843. }
  2844. /*
  2845. * call-seq:
  2846. * time.friday? => true or false
  2847. *
  2848. * Returns <code>true</code> if <i>time</i> represents Friday.
  2849. *
  2850. * t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
  2851. * t.friday? #=> true
  2852. */
  2853. static VALUE
  2854. time_friday(VALUE time)
  2855. {
  2856. wday_p(5);
  2857. }
  2858. /*
  2859. * call-seq:
  2860. * time.saturday? => true or false
  2861. *
  2862. * Returns <code>true</code> if <i>time</i> represents Saturday.
  2863. *
  2864. * t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
  2865. * t.saturday? #=> true
  2866. */
  2867. static VALUE
  2868. time_saturday(VALUE time)
  2869. {
  2870. wday_p(6);
  2871. }
  2872. /*
  2873. * call-seq:
  2874. * time.yday => fixnum
  2875. *
  2876. * Returns an integer representing the day of the year, 1..366.
  2877. *
  2878. * t = Time.now #=> 2007-11-19 08:32:31 -0600
  2879. * t.yday #=> 323
  2880. */
  2881. static VALUE
  2882. time_yday(VALUE time)
  2883. {
  2884. struct time_object *tobj;
  2885. GetTimeval(time, tobj);
  2886. MAKE_TM(time, tobj);
  2887. return INT2FIX(tobj->vtm.yday);
  2888. }
  2889. /*
  2890. * call-seq:
  2891. * time.isdst => true or false
  2892. * time.dst? => true or false
  2893. *
  2894. * Returns <code>true</code> if <i>time</i> occurs during Daylight
  2895. * Saving Time in its time zone.
  2896. *
  2897. * # CST6CDT:
  2898. * Time.local(2000, 1, 1).zone #=> "CST"
  2899. * Time.local(2000, 1, 1).isdst #=> false
  2900. * Time.local(2000, 1, 1).dst? #=> false
  2901. * Time.local(2000, 7, 1).zone #=> "CDT"
  2902. * Time.local(2000, 7, 1).isdst #=> true
  2903. * Time.local(2000, 7, 1).dst? #=> true
  2904. *
  2905. * # Asia/Tokyo:
  2906. * Time.local(2000, 1, 1).zone #=> "JST"
  2907. * Time.local(2000, 1, 1).isdst #=> false
  2908. * Time.local(2000, 1, 1).dst? #=> false
  2909. * Time.local(2000, 7, 1).zone #=> "JST"
  2910. * Time.local(2000, 7, 1).isdst #=> false
  2911. * Time.local(2000, 7, 1).dst? #=> false
  2912. */
  2913. static VALUE
  2914. time_isdst(VALUE time)
  2915. {
  2916. struct time_object *tobj;
  2917. GetTimeval(time, tobj);
  2918. MAKE_TM(time, tobj);
  2919. return tobj->vtm.isdst ? Qtrue : Qfalse;
  2920. }
  2921. /*
  2922. * call-seq:
  2923. * time.zone => string
  2924. *
  2925. * Returns the name of the time zone used for <i>time</i>. As of Ruby
  2926. * 1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
  2927. *
  2928. * t = Time.gm(2000, "jan", 1, 20, 15, 1)
  2929. * t.zone #=> "UTC"
  2930. * t = Time.local(2000, "jan", 1, 20, 15, 1)
  2931. * t.zone #=> "CST"
  2932. */
  2933. static VALUE
  2934. time_zone(VALUE time)
  2935. {
  2936. struct time_object *tobj;
  2937. GetTimeval(time, tobj);
  2938. MAKE_TM(time, tobj);
  2939. if (TIME_UTC_P(tobj)) {
  2940. return rb_str_new2("UTC");
  2941. }
  2942. if (tobj->vtm.zone == NULL)
  2943. return Qnil;
  2944. return rb_str_new2(tobj->vtm.zone);
  2945. }
  2946. /*
  2947. * call-seq:
  2948. * time.gmt_offset => fixnum
  2949. * time.gmtoff => fixnum
  2950. * time.utc_offset => fixnum
  2951. *
  2952. * Returns the offset in seconds between the timezone of <i>time</i>
  2953. * and UTC.
  2954. *
  2955. * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
  2956. * t.gmt_offset #=> 0
  2957. * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
  2958. * l.gmt_offset #=> -21600
  2959. */
  2960. static VALUE
  2961. time_utc_offset(VALUE time)
  2962. {
  2963. struct time_object *tobj;
  2964. GetTimeval(time, tobj);
  2965. MAKE_TM(time, tobj);
  2966. if (TIME_UTC_P(tobj)) {
  2967. return INT2FIX(0);
  2968. }
  2969. else {
  2970. return tobj->vtm.utc_offset;
  2971. }
  2972. }
  2973. /*
  2974. * call-seq:
  2975. * time.to_a => array
  2976. *
  2977. * Returns a ten-element <i>array</i> of values for <i>time</i>:
  2978. * {<code>[ sec, min, hour, day, month, year, wday, yday, isdst, zone
  2979. * ]</code>}. See the individual methods for an explanation of the
  2980. * valid ranges of each value. The ten elements can be passed directly
  2981. * to <code>Time::utc</code> or <code>Time::local</code> to create a
  2982. * new <code>Time</code>.
  2983. *
  2984. * t = Time.now #=> 2007-11-19 08:36:01 -0600
  2985. * now = t.to_a #=> [1, 36, 8, 19, 11, 2007, 1, 323, false, "CST"]
  2986. */
  2987. static VALUE
  2988. time_to_a(VALUE time)
  2989. {
  2990. struct time_object *tobj;
  2991. GetTimeval(time, tobj);
  2992. MAKE_TM(time, tobj);
  2993. return rb_ary_new3(10,
  2994. INT2FIX(tobj->vtm.sec),
  2995. INT2FIX(tobj->vtm.min),
  2996. INT2FIX(tobj->vtm.hour),
  2997. INT2FIX(tobj->vtm.mday),
  2998. INT2FIX(tobj->vtm.mon),
  2999. tobj->vtm.year,
  3000. INT2FIX(tobj->vtm.wday),
  3001. INT2FIX(tobj->vtm.yday),
  3002. tobj->vtm.isdst?Qtrue:Qfalse,
  3003. time_zone(time));
  3004. }
  3005. size_t
  3006. rb_strftime(char *s, size_t maxsize, const char *format,
  3007. const struct vtm *vtm, VALUE timev,
  3008. int gmt);
  3009. #define SMALLBUF 100
  3010. static size_t
  3011. rb_strftime_alloc(char **buf, const char *format,
  3012. struct vtm *vtm, VALUE timev, int gmt)
  3013. {
  3014. size_t size, len, flen;
  3015. (*buf)[0] = '\0';
  3016. flen = strlen(format);
  3017. if (flen == 0) {
  3018. return 0;
  3019. }
  3020. errno = 0;
  3021. len = rb_strftime(*buf, SMALLBUF, format, vtm, timev, gmt);
  3022. if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
  3023. for (size=1024; ; size*=2) {
  3024. *buf = xmalloc(size);
  3025. (*buf)[0] = '\0';
  3026. len = rb_strftime(*buf, size, format, vtm, timev, gmt);
  3027. /*
  3028. * buflen can be zero EITHER because there's not enough
  3029. * room in the string, or because the control command
  3030. * goes to the empty string. Make a reasonable guess that
  3031. * if the buffer is 1024 times bigger than the length of the
  3032. * format string, it's not failing for lack of room.
  3033. */
  3034. if (len > 0 || size >= 1024 * flen) break;
  3035. xfree(*buf);
  3036. }
  3037. return len;
  3038. }
  3039. static VALUE
  3040. strftimev(const char *fmt, VALUE time)
  3041. {
  3042. struct time_object *tobj;
  3043. char buffer[SMALLBUF], *buf = buffer;
  3044. long len;
  3045. VALUE str;
  3046. GetTimeval(time, tobj);
  3047. MAKE_TM(time, tobj);
  3048. len = rb_strftime_alloc(&buf, fmt, &tobj->vtm, rb_time_unmagnify(tobj->timexv), TIME_UTC_P(tobj));
  3049. str = rb_str_new(buf, len);
  3050. if (buf != buffer) xfree(buf);
  3051. return str;
  3052. }
  3053. /*
  3054. * call-seq:
  3055. * time.strftime( string ) => string
  3056. *
  3057. * Formats <i>time</i> according to the directives in the given format
  3058. * string. Any text not listed as a directive will be passed through
  3059. * to the output string.
  3060. *
  3061. * Format meaning:
  3062. * %a - The abbreviated weekday name (``Sun'')
  3063. * %A - The full weekday name (``Sunday'')
  3064. * %b - The abbreviated month name (``Jan'')
  3065. * %B - The full month name (``January'')
  3066. * %c - The preferred local date and time representation
  3067. * %C - Century (20 in 2009)
  3068. * %d - Day of the month (01..31)
  3069. * %D - Date (%m/%d/%y)
  3070. * %e - Day of the month, blank-padded ( 1..31)
  3071. * %F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
  3072. * %h - Equivalent to %b
  3073. * %H - Hour of the day, 24-hour clock (00..23)
  3074. * %I - Hour of the day, 12-hour clock (01..12)
  3075. * %j - Day of the year (001..366)
  3076. * %k - hour, 24-hour clock, blank-padded ( 0..23)
  3077. * %l - hour, 12-hour clock, blank-padded ( 0..12)
  3078. * %L - Millisecond of the second (000..999)
  3079. * %m - Month of the year (01..12)
  3080. * %M - Minute of the hour (00..59)
  3081. * %n - Newline (\n)
  3082. * %N - Fractional seconds digits, default is 9 digits (nanosecond)
  3083. * %3N millisecond (3 digits)
  3084. * %6N microsecond (6 digits)
  3085. * %9N nanosecond (9 digits)
  3086. * %p - Meridian indicator (``AM'' or ``PM'')
  3087. * %P - Meridian indicator (``am'' or ``pm'')
  3088. * %r - time, 12-hour (same as %I:%M:%S %p)
  3089. * %R - time, 24-hour (%H:%M)
  3090. * %s - Number of seconds since 1970-01-01 00:00:00 UTC.
  3091. * %S - Second of the minute (00..60)
  3092. * %t - Tab character (\t)
  3093. * %T - time, 24-hour (%H:%M:%S)
  3094. * %u - Day of the week as a decimal, Monday being 1. (1..7)
  3095. * %U - Week number of the current year,
  3096. * starting with the first Sunday as the first
  3097. * day of the first week (00..53)
  3098. * %v - VMS date (%e-%b-%Y)
  3099. * %V - Week number of year according to ISO 8601 (01..53)
  3100. * %W - Week number of the current year,
  3101. * starting with the first Monday as the first
  3102. * day of the first week (00..53)
  3103. * %w - Day of the week (Sunday is 0, 0..6)
  3104. * %x - Preferred representation for the date alone, no time
  3105. * %X - Preferred representation for the time alone, no date
  3106. * %y - Year without a century (00..99)
  3107. * %Y - Year with century
  3108. * %z - Time zone as hour offset from UTC (e.g. +0900)
  3109. * %Z - Time zone name
  3110. * %% - Literal ``%'' character
  3111. *
  3112. * t = Time.now #=> 2007-11-19 08:37:48 -0600
  3113. * t.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007"
  3114. * t.strftime("at %I:%M%p") #=> "at 08:37AM"
  3115. */
  3116. static VALUE
  3117. time_strftime(VALUE time, VALUE format)
  3118. {
  3119. void rb_enc_copy(VALUE, VALUE);
  3120. struct time_object *tobj;
  3121. char buffer[SMALLBUF], *buf = buffer;
  3122. const char *fmt;
  3123. long len;
  3124. VALUE str;
  3125. GetTimeval(time, tobj);
  3126. MAKE_TM(time, tobj);
  3127. StringValue(format);
  3128. if (!rb_enc_str_asciicompat_p(format)) {
  3129. rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
  3130. }
  3131. format = rb_str_new4(format);
  3132. fmt = RSTRING_PTR(format);
  3133. len = RSTRING_LEN(format);
  3134. if (len == 0) {
  3135. rb_warning("strftime called with empty format string");
  3136. }
  3137. else if (memchr(fmt, '\0', len)) {
  3138. /* Ruby string may contain \0's. */
  3139. const char *p = fmt, *pe = fmt + len;
  3140. str = rb_str_new(0, 0);
  3141. while (p < pe) {
  3142. len = rb_strftime_alloc(&buf, p, &tobj->vtm, rb_time_unmagnify(tobj->timexv), TIME_UTC_P(tobj));
  3143. rb_str_cat(str, buf, len);
  3144. p += strlen(p);
  3145. if (buf != buffer) {
  3146. xfree(buf);
  3147. buf = buffer;
  3148. }
  3149. for (fmt = p; p < pe && !*p; ++p);
  3150. if (p > fmt) rb_str_cat(str, fmt, p - fmt);
  3151. }
  3152. return str;
  3153. }
  3154. else {
  3155. len = rb_strftime_alloc(&buf, RSTRING_PTR(format),
  3156. &tobj->vtm, rb_time_unmagnify(tobj->timexv), TIME_UTC_P(tobj));
  3157. }
  3158. str = rb_str_new(buf, len);
  3159. if (buf != buffer) xfree(buf);
  3160. rb_enc_copy(str, format);
  3161. return str;
  3162. }
  3163. /*
  3164. * undocumented
  3165. */
  3166. static VALUE
  3167. time_mdump(VALUE time)
  3168. {
  3169. struct time_object *tobj;
  3170. unsigned long p, s;
  3171. char buf[8];
  3172. int i;
  3173. VALUE str;
  3174. struct vtm vtm;
  3175. long year;
  3176. long usec, nsec;
  3177. VALUE subsecx, nano, subnano, v;
  3178. GetTimeval(time, tobj);
  3179. gmtimexv(tobj->timexv, &vtm);
  3180. if (FIXNUM_P(vtm.year)) {
  3181. year = FIX2LONG(vtm.year);
  3182. if (year < 1900 || 1900+0xffff < year)
  3183. rb_raise(rb_eArgError, "year too big to marshal: %ld UTC", year);
  3184. }
  3185. else {
  3186. rb_raise(rb_eArgError, "year too big to marshal");
  3187. }
  3188. subsecx = vtm.subsecx;
  3189. nano = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
  3190. divmodv(nano, INT2FIX(1), &v, &subnano);
  3191. nsec = FIX2LONG(v);
  3192. usec = nsec / 1000;
  3193. nsec = nsec % 1000;
  3194. nano = add(LONG2FIX(nsec), subnano);
  3195. p = 0x1UL << 31 | /* 1 */
  3196. TIME_UTC_P(tobj) << 30 | /* 1 */
  3197. (year-1900) << 14 | /* 16 */
  3198. (vtm.mon-1) << 10 | /* 4 */
  3199. vtm.mday << 5 | /* 5 */
  3200. vtm.hour; /* 5 */
  3201. s = vtm.min << 26 | /* 6 */
  3202. vtm.sec << 20 | /* 6 */
  3203. usec; /* 20 */
  3204. for (i=0; i<4; i++) {
  3205. buf[i] = (unsigned char)p;
  3206. p = RSHIFT(p, 8);
  3207. }
  3208. for (i=4; i<8; i++) {
  3209. buf[i] = (unsigned char)s;
  3210. s = RSHIFT(s, 8);
  3211. }
  3212. str = rb_str_new(buf, 8);
  3213. rb_copy_generic_ivar(str, time);
  3214. if (!rb_equal(nano, INT2FIX(0))) {
  3215. if (TYPE(nano) == T_RATIONAL) {
  3216. rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
  3217. rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
  3218. }
  3219. else {
  3220. rb_ivar_set(str, id_nano_num, nano);
  3221. rb_ivar_set(str, id_nano_den, INT2FIX(1));
  3222. }
  3223. }
  3224. if (nsec) { /* submicro is only for Ruby 1.9.1 compatibility */
  3225. /*
  3226. * submicro is formatted in fixed-point packed BCD (without sign).
  3227. * It represent digits under microsecond.
  3228. * For nanosecond resolution, 3 digits (2 bytes) are used.
  3229. * However it can be longer.
  3230. * Extra digits are ignored for loading.
  3231. */
  3232. char buf[2];
  3233. int len = (int)sizeof(buf);
  3234. buf[1] = (char)((nsec % 10) << 4);
  3235. nsec /= 10;
  3236. buf[0] = (char)(nsec % 10);
  3237. nsec /= 10;
  3238. buf[0] |= (char)((nsec % 10) << 4);
  3239. if (buf[1] == 0)
  3240. len = 1;
  3241. rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
  3242. }
  3243. if (!TIME_UTC_P(tobj)) {
  3244. VALUE off = time_utc_offset(time), div, mod;
  3245. divmodv(off, INT2FIX(1), &div, &mod);
  3246. if (rb_equal(mod, INT2FIX(0)))
  3247. off = rb_Integer(div);
  3248. rb_ivar_set(str, id_offset, off);
  3249. }
  3250. return str;
  3251. }
  3252. /*
  3253. * call-seq:
  3254. * time._dump => string
  3255. *
  3256. * Dump _time_ for marshaling.
  3257. */
  3258. static VALUE
  3259. time_dump(int argc, VALUE *argv, VALUE time)
  3260. {
  3261. VALUE str;
  3262. rb_scan_args(argc, argv, "01", 0);
  3263. str = time_mdump(time);
  3264. return str;
  3265. }
  3266. /*
  3267. * undocumented
  3268. */
  3269. static VALUE
  3270. time_mload(VALUE time, VALUE str)
  3271. {
  3272. struct time_object *tobj;
  3273. unsigned long p, s;
  3274. time_t sec;
  3275. long usec;
  3276. unsigned char *buf;
  3277. struct vtm vtm;
  3278. int i, gmt;
  3279. long nsec;
  3280. VALUE timexv, submicro, nano_num, nano_den, offset;
  3281. time_modify(time);
  3282. nano_num = rb_attr_get(str, id_nano_num);
  3283. if (nano_num != Qnil) {
  3284. st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_nano_num, 0);
  3285. }
  3286. nano_den = rb_attr_get(str, id_nano_den);
  3287. if (nano_den != Qnil) {
  3288. st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_nano_den, 0);
  3289. }
  3290. submicro = rb_attr_get(str, id_submicro);
  3291. if (submicro != Qnil) {
  3292. st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_submicro, 0);
  3293. }
  3294. offset = rb_attr_get(str, id_offset);
  3295. if (offset != Qnil) {
  3296. validate_utc_offset(offset);
  3297. st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_offset, 0);
  3298. }
  3299. rb_copy_generic_ivar(time, str);
  3300. StringValue(str);
  3301. buf = (unsigned char *)RSTRING_PTR(str);
  3302. if (RSTRING_LEN(str) != 8) {
  3303. rb_raise(rb_eTypeError, "marshaled time format differ");
  3304. }
  3305. p = s = 0;
  3306. for (i=0; i<4; i++) {
  3307. p |= buf[i]<<(8*i);
  3308. }
  3309. for (i=4; i<8; i++) {
  3310. s |= buf[i]<<(8*(i-4));
  3311. }
  3312. if ((p & (1UL<<31)) == 0) {
  3313. gmt = 0;
  3314. offset = Qnil;
  3315. sec = p;
  3316. usec = s;
  3317. nsec = usec * 1000;
  3318. timexv = add(rb_time_magnify(TIMET2NUM(sec)), mulquo(LONG2FIX(usec), INT2FIX(TIME_SCALE), LONG2FIX(1000000)));
  3319. }
  3320. else {
  3321. p &= ~(1UL<<31);
  3322. gmt = (int)((p >> 30) & 0x1);
  3323. vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
  3324. vtm.mon = ((int)(p >> 10) & 0xf) + 1;
  3325. vtm.mday = (int)(p >> 5) & 0x1f;
  3326. vtm.hour = (int) p & 0x1f;
  3327. vtm.min = (int)(s >> 26) & 0x3f;
  3328. vtm.sec = (int)(s >> 20) & 0x3f;
  3329. vtm.utc_offset = INT2FIX(0);
  3330. vtm.yday = vtm.wday = 0;
  3331. vtm.isdst = 0;
  3332. vtm.zone = "";
  3333. usec = (long)(s & 0xfffff);
  3334. nsec = usec * 1000;
  3335. vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
  3336. if (nano_num != Qnil) {
  3337. VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
  3338. vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
  3339. }
  3340. else if (submicro != Qnil) { /* for Ruby 1.9.1 compatibility */
  3341. unsigned char *ptr;
  3342. long len;
  3343. int digit;
  3344. ptr = (unsigned char*)StringValuePtr(submicro);
  3345. len = RSTRING_LEN(submicro);
  3346. nsec = 0;
  3347. if (0 < len) {
  3348. if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
  3349. nsec += digit * 100;
  3350. if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
  3351. nsec += digit * 10;
  3352. }
  3353. if (1 < len) {
  3354. if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
  3355. nsec += digit;
  3356. }
  3357. vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
  3358. end_submicro: ;
  3359. }
  3360. timexv = timegmxv(&vtm);
  3361. }
  3362. GetTimeval(time, tobj);
  3363. tobj->tm_got = 0;
  3364. tobj->timexv = timexv;
  3365. if (gmt) {
  3366. TIME_SET_UTC(tobj);
  3367. }
  3368. else if (!NIL_P(offset)) {
  3369. time_set_utc_offset(time, offset);
  3370. time_fixoff(time);
  3371. }
  3372. return time;
  3373. }
  3374. /*
  3375. * call-seq:
  3376. * Time._load(string) => time
  3377. *
  3378. * Unmarshal a dumped +Time+ object.
  3379. */
  3380. static VALUE
  3381. time_load(VALUE klass, VALUE str)
  3382. {
  3383. VALUE time = time_s_alloc(klass);
  3384. time_mload(time, str);
  3385. return time;
  3386. }
  3387. /*
  3388. * <code>Time</code> is an abstraction of dates and times. Time is
  3389. * stored internally as the number of seconds with fraction since
  3390. * the <em>Epoch</em>, January 1, 1970 00:00 UTC.
  3391. * Also see the library modules <code>Date</code>.
  3392. * The <code>Time</code> class treats GMT (Greenwich Mean Time) and
  3393. * UTC (Coordinated Universal Time)<em>[Yes, UTC really does stand for
  3394. * Coordinated Universal Time. There was a committee involved.]</em>
  3395. * as equivalent. GMT is the older way of referring to these
  3396. * baseline times but persists in the names of calls on POSIX
  3397. * systems.
  3398. *
  3399. * All times may have fraction. Be aware of
  3400. * this fact when comparing times with each other---times that are
  3401. * apparently equal when displayed may be different when compared.
  3402. */
  3403. void
  3404. Init_Time(void)
  3405. {
  3406. #undef rb_intern
  3407. #define rb_intern(str) rb_intern_const(str)
  3408. id_eq = rb_intern("==");
  3409. id_ne = rb_intern("!=");
  3410. id_quo = rb_intern("quo");
  3411. id_div = rb_intern("div");
  3412. id_cmp = rb_intern("<=>");
  3413. id_lshift = rb_intern("<<");
  3414. id_divmod = rb_intern("divmod");
  3415. id_mul = rb_intern("*");
  3416. id_submicro = rb_intern("submicro");
  3417. id_nano_num = rb_intern("nano_num");
  3418. id_nano_den = rb_intern("nano_den");
  3419. id_offset = rb_intern("offset");
  3420. rb_cTime = rb_define_class("Time", rb_cObject);
  3421. rb_include_module(rb_cTime, rb_mComparable);
  3422. rb_define_alloc_func(rb_cTime, time_s_alloc);
  3423. rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
  3424. rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
  3425. rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
  3426. rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
  3427. rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
  3428. rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
  3429. rb_define_method(rb_cTime, "to_i", time_to_i, 0);
  3430. rb_define_method(rb_cTime, "to_f", time_to_f, 0);
  3431. rb_define_method(rb_cTime, "to_r", time_to_r, 0);
  3432. rb_define_method(rb_cTime, "<=>", time_cmp, 1);
  3433. rb_define_method(rb_cTime, "eql?", time_eql, 1);
  3434. rb_define_method(rb_cTime, "hash", time_hash, 0);
  3435. rb_define_method(rb_cTime, "initialize", time_init, -1);
  3436. rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1);
  3437. rb_define_method(rb_cTime, "localtime", time_localtime_m, -1);
  3438. rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
  3439. rb_define_method(rb_cTime, "utc", time_gmtime, 0);
  3440. rb_define_method(rb_cTime, "getlocal", time_getlocaltime, -1);
  3441. rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
  3442. rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
  3443. rb_define_method(rb_cTime, "ctime", time_asctime, 0);
  3444. rb_define_method(rb_cTime, "asctime", time_asctime, 0);
  3445. rb_define_method(rb_cTime, "to_s", time_to_s, 0);
  3446. rb_define_method(rb_cTime, "inspect", time_to_s, 0);
  3447. rb_define_method(rb_cTime, "to_a", time_to_a, 0);
  3448. rb_define_method(rb_cTime, "+", time_plus, 1);
  3449. rb_define_method(rb_cTime, "-", time_minus, 1);
  3450. rb_define_method(rb_cTime, "succ", time_succ, 0);
  3451. rb_define_method(rb_cTime, "sec", time_sec, 0);
  3452. rb_define_method(rb_cTime, "min", time_min, 0);
  3453. rb_define_method(rb_cTime, "hour", time_hour, 0);
  3454. rb_define_method(rb_cTime, "mday", time_mday, 0);
  3455. rb_define_method(rb_cTime, "day", time_mday, 0);
  3456. rb_define_method(rb_cTime, "mon", time_mon, 0);
  3457. rb_define_method(rb_cTime, "month", time_mon, 0);
  3458. rb_define_method(rb_cTime, "year", time_year, 0);
  3459. rb_define_method(rb_cTime, "wday", time_wday, 0);
  3460. rb_define_method(rb_cTime, "yday", time_yday, 0);
  3461. rb_define_method(rb_cTime, "isdst", time_isdst, 0);
  3462. rb_define_method(rb_cTime, "dst?", time_isdst, 0);
  3463. rb_define_method(rb_cTime, "zone", time_zone, 0);
  3464. rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
  3465. rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
  3466. rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
  3467. rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
  3468. rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
  3469. rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
  3470. rb_define_method(rb_cTime, "monday?", time_monday, 0);
  3471. rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
  3472. rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
  3473. rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
  3474. rb_define_method(rb_cTime, "friday?", time_friday, 0);
  3475. rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
  3476. rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
  3477. rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
  3478. rb_define_method(rb_cTime, "usec", time_usec, 0);
  3479. rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
  3480. rb_define_method(rb_cTime, "nsec", time_nsec, 0);
  3481. rb_define_method(rb_cTime, "subsec", time_subsec, 0);
  3482. rb_define_method(rb_cTime, "strftime", time_strftime, 1);
  3483. /* methods for marshaling */
  3484. rb_define_method(rb_cTime, "_dump", time_dump, -1);
  3485. rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
  3486. #if 0
  3487. /* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
  3488. rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0);
  3489. rb_define_method(rb_cTime, "marshal_load", time_mload, 1);
  3490. #endif
  3491. #ifdef DEBUG_FIND_TIME_NUMGUESS
  3492. rb_define_virtual_variable("$find_time_numguess", find_time_numguess_getter, NULL);
  3493. #endif
  3494. }