* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / time.c
blobcf7ca2217518d2051a86aa2c6d90cf2be406dcfc
1 /**********************************************************************
3 time.c -
5 $Author$
6 created at: Tue Dec 28 14:31:59 JST 1993
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include <sys/types.h>
14 #include <time.h>
15 #include <errno.h>
16 #include "ruby/encoding.h"
18 #ifdef HAVE_UNISTD_H
19 #include <unistd.h>
20 #endif
22 #include <math.h>
24 VALUE rb_cTime;
25 static VALUE time_utc_offset _((VALUE));
27 static ID id_divmod, id_mul, id_submicro;
29 struct time_object {
30 struct timespec ts;
31 struct tm tm;
32 int gmt;
33 int tm_got;
36 #define GetTimeval(obj, tobj) \
37 Data_Get_Struct(obj, struct time_object, tobj)
39 static void
40 time_free(void *tobj)
42 if (tobj) xfree(tobj);
45 static VALUE
46 time_s_alloc(VALUE klass)
48 VALUE obj;
49 struct time_object *tobj;
51 obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
52 tobj->tm_got=0;
53 tobj->ts.tv_sec = 0;
54 tobj->ts.tv_nsec = 0;
56 return obj;
59 static void
60 time_modify(VALUE time)
62 rb_check_frozen(time);
63 if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
64 rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
68 * Document-method: now
70 * Synonym for <code>Time.new</code>. Returns a +Time+ object
71 * initialized to the current system time.
75 * call-seq:
76 * Time.new -> time
78 * Returns a <code>Time</code> object initialized to the current system
79 * time. <b>Note:</b> The object created will be created using the
80 * resolution available on your system clock, and so may include
81 * fractional seconds.
83 * a = Time.new #=> 2007-11-19 07:50:02 -0600
84 * b = Time.new #=> 2007-11-19 07:50:02 -0600
85 * a == b #=> false
86 * "%.6f" % a.to_f #=> "1195480202.282373"
87 * "%.6f" % b.to_f #=> "1195480202.283415"
91 static VALUE
92 time_init(VALUE time)
94 struct time_object *tobj;
96 time_modify(time);
97 GetTimeval(time, tobj);
98 tobj->tm_got=0;
99 tobj->ts.tv_sec = 0;
100 tobj->ts.tv_nsec = 0;
101 #ifdef HAVE_CLOCK_GETTIME
102 if (clock_gettime(CLOCK_REALTIME, &tobj->ts) == -1) {
103 rb_sys_fail("clock_gettime");
105 #else
107 struct timeval tv;
108 if (gettimeofday(&tv, 0) < 0) {
109 rb_sys_fail("gettimeofday");
111 tobj->ts.tv_sec = tv.tv_sec;
112 tobj->ts.tv_nsec = tv.tv_usec * 1000;
114 #endif
116 return time;
119 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
120 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
122 static void
123 time_overflow_p(time_t *secp, long *nsecp)
125 time_t tmp, sec = *secp;
126 long nsec = *nsecp;
128 if (nsec >= 1000000000) { /* nsec positive overflow */
129 tmp = sec + nsec / 1000000000;
130 nsec %= 1000000000;
131 if (sec > 0 && tmp < 0) {
132 rb_raise(rb_eRangeError, "out of Time range");
134 sec = tmp;
136 if (nsec < 0) { /* nsec negative overflow */
137 tmp = sec + NDIV(nsec,1000000000); /* negative div */
138 nsec = NMOD(nsec,1000000000); /* negative mod */
139 if (sec < 0 && tmp > 0) {
140 rb_raise(rb_eRangeError, "out of Time range");
142 sec = tmp;
144 #ifndef NEGATIVE_TIME_T
145 if (sec < 0)
146 rb_raise(rb_eArgError, "time must be positive");
147 #endif
148 *secp = sec;
149 *nsecp = nsec;
152 static VALUE
153 time_new_internal(VALUE klass, time_t sec, long nsec)
155 VALUE time = time_s_alloc(klass);
156 struct time_object *tobj;
158 GetTimeval(time, tobj);
159 time_overflow_p(&sec, &nsec);
160 tobj->ts.tv_sec = sec;
161 tobj->ts.tv_nsec = nsec;
163 return time;
166 VALUE
167 rb_time_new(time_t sec, long usec)
169 return time_new_internal(rb_cTime, sec, usec * 1000);
172 VALUE
173 rb_time_nano_new(time_t sec, long nsec)
175 return time_new_internal(rb_cTime, sec, nsec);
178 static struct timespec
179 time_timespec(VALUE num, int interval)
181 struct timespec t;
182 const char *tstr = interval ? "time interval" : "time";
183 VALUE i, f, ary;
185 #ifndef NEGATIVE_TIME_T
186 interval = 1;
187 #endif
189 switch (TYPE(num)) {
190 case T_FIXNUM:
191 t.tv_sec = FIX2LONG(num);
192 if (interval && t.tv_sec < 0)
193 rb_raise(rb_eArgError, "%s must be positive", tstr);
194 t.tv_nsec = 0;
195 break;
197 case T_FLOAT:
198 if (interval && RFLOAT_VALUE(num) < 0.0)
199 rb_raise(rb_eArgError, "%s must be positive", tstr);
200 else {
201 double f, d;
203 d = modf(RFLOAT_VALUE(num), &f);
204 if (d < 0) {
205 d += 1;
206 f -= 1;
208 t.tv_sec = (time_t)f;
209 if (f != t.tv_sec) {
210 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT_VALUE(num));
212 t.tv_nsec = (long)(d*1e9+0.5);
214 break;
216 case T_BIGNUM:
217 t.tv_sec = NUM2LONG(num);
218 if (interval && t.tv_sec < 0)
219 rb_raise(rb_eArgError, "%s must be positive", tstr);
220 t.tv_nsec = 0;
221 break;
223 default:
224 if (rb_respond_to(num, id_divmod)) {
225 ary = rb_check_array_type(rb_funcall(num, id_divmod, 1, INT2FIX(1)));
226 if (NIL_P(ary)) {
227 goto typeerror;
229 i = rb_ary_entry(ary, 0);
230 f = rb_ary_entry(ary, 1);
231 t.tv_sec = NUM2LONG(i);
232 if (interval && t.tv_sec < 0)
233 rb_raise(rb_eArgError, "%s must be positive", tstr);
234 f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
235 t.tv_nsec = NUM2LONG(f);
237 else {
238 typeerror:
239 rb_raise(rb_eTypeError, "can't convert %s into %s",
240 rb_obj_classname(num), tstr);
242 break;
244 return t;
247 static struct timeval
248 time_timeval(VALUE num, int interval)
250 struct timespec ts;
251 struct timeval tv;
253 ts = time_timespec(num, interval);
254 tv.tv_sec = ts.tv_sec;
255 tv.tv_usec = ts.tv_nsec / 1000;
257 return tv;
260 struct timeval
261 rb_time_interval(VALUE num)
263 return time_timeval(num, Qtrue);
266 struct timeval
267 rb_time_timeval(VALUE time)
269 struct time_object *tobj;
270 struct timeval t;
272 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
273 GetTimeval(time, tobj);
274 t.tv_sec = tobj->ts.tv_sec;
275 t.tv_usec = tobj->ts.tv_nsec / 1000;
276 return t;
278 return time_timeval(time, Qfalse);
281 struct timespec
282 rb_time_timespec(VALUE time)
284 struct time_object *tobj;
285 struct timespec t;
287 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
288 GetTimeval(time, tobj);
289 t = tobj->ts;
290 return t;
292 return time_timespec(time, Qfalse);
296 * call-seq:
297 * Time.at(time) => time
298 * Time.at(seconds_with_frac) => time
299 * Time.at(seconds, microseconds_with_frac) => time
301 * Creates a new time object with the value given by <i>time</i>,
302 * the given number of <i>seconds_with_frac</i>, or
303 * <i>seconds</i> and <i>microseconds_with_frac</i> from the Epoch.
304 * <i>seconds_with_frac</i> and <i>microseconds_with_frac</i>
305 * can be Integer, Float, Rational, or other Numeric.
306 * non-portable feature allows the offset to be negative on some systems.
308 * Time.at(0) #=> 1969-12-31 18:00:00 -0600
309 * Time.at(Time.at(0)) #=> 1969-12-31 18:00:00 -0600
310 * Time.at(946702800) #=> 1999-12-31 23:00:00 -0600
311 * Time.at(-284061600) #=> 1960-12-31 00:00:00 -0600
312 * Time.at(946684800.2).usec #=> 200000
313 * Time.at(946684800, 123456.789).nsec #=> 123456789
316 static VALUE
317 time_s_at(int argc, VALUE *argv, VALUE klass)
319 struct timespec ts;
320 VALUE time, t;
322 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
323 ts.tv_sec = NUM2LONG(time);
324 ts.tv_nsec = NUM2LONG(rb_funcall(t, id_mul, 1, INT2FIX(1000)));
326 else {
327 ts = rb_time_timespec(time);
329 t = time_new_internal(klass, ts.tv_sec, ts.tv_nsec);
330 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
331 struct time_object *tobj, *tobj2;
333 GetTimeval(time, tobj);
334 GetTimeval(t, tobj2);
335 tobj2->gmt = tobj->gmt;
337 return t;
340 static const char months[][4] = {
341 "jan", "feb", "mar", "apr", "may", "jun",
342 "jul", "aug", "sep", "oct", "nov", "dec",
345 static long
346 obj2long(VALUE obj)
348 if (TYPE(obj) == T_STRING) {
349 obj = rb_str_to_inum(obj, 10, Qfalse);
352 return NUM2LONG(obj);
355 static long
356 obj2nsec(VALUE obj, long *nsec)
358 struct timespec ts;
360 if (TYPE(obj) == T_STRING) {
361 obj = rb_str_to_inum(obj, 10, Qfalse);
362 *nsec = 0;
363 return NUM2LONG(obj);
366 ts = time_timespec(obj, 1);
367 *nsec = ts.tv_nsec;
368 return ts.tv_sec;
371 static long
372 obj2long1000(VALUE obj)
374 if (TYPE(obj) == T_STRING) {
375 obj = rb_str_to_inum(obj, 10, Qfalse);
376 return NUM2LONG(obj) * 1000;
379 return NUM2LONG(rb_funcall(obj, id_mul, 1, INT2FIX(1000)));
382 static void
383 time_arg(int argc, VALUE *argv, struct tm *tm, long *nsec)
385 VALUE v[8];
386 int i;
387 long year;
389 MEMZERO(tm, struct tm, 1);
390 *nsec = 0;
391 if (argc == 10) {
392 v[0] = argv[5];
393 v[1] = argv[4];
394 v[2] = argv[3];
395 v[3] = argv[2];
396 v[4] = argv[1];
397 v[5] = argv[0];
398 v[6] = Qnil;
399 tm->tm_isdst = RTEST(argv[8]) ? 1 : 0;
401 else {
402 rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
403 /* v[6] may be usec or zone (parsedate) */
404 /* v[7] is wday (parsedate; ignored) */
405 tm->tm_wday = -1;
406 tm->tm_isdst = -1;
409 year = obj2long(v[0]);
411 if (0 <= year && year < 39) {
412 rb_warning("2 digits year is used: %ld", year);
413 year += 100;
415 else if (69 <= year && year < 139) {
416 rb_warning("2 or 3 digits year is used: %ld", year);
418 else {
419 year -= 1900;
422 tm->tm_year = year;
424 if (NIL_P(v[1])) {
425 tm->tm_mon = 0;
427 else {
428 VALUE s = rb_check_string_type(v[1]);
429 if (!NIL_P(s)) {
430 tm->tm_mon = -1;
431 for (i=0; i<12; i++) {
432 if (RSTRING_LEN(s) == 3 &&
433 STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
434 tm->tm_mon = i;
435 break;
438 if (tm->tm_mon == -1) {
439 char c = RSTRING_PTR(s)[0];
441 if ('0' <= c && c <= '9') {
442 tm->tm_mon = obj2long(s)-1;
446 else {
447 tm->tm_mon = obj2long(v[1])-1;
450 if (NIL_P(v[2])) {
451 tm->tm_mday = 1;
453 else {
454 tm->tm_mday = obj2long(v[2]);
456 tm->tm_hour = NIL_P(v[3])?0:obj2long(v[3]);
457 tm->tm_min = NIL_P(v[4])?0:obj2long(v[4]);
458 if (!NIL_P(v[6]) && argc == 7) {
459 tm->tm_sec = NIL_P(v[5])?0:obj2long(v[5]);
460 *nsec = obj2long1000(v[6]);
462 else {
463 /* when argc == 8, v[6] is timezone, but ignored */
464 tm->tm_sec = NIL_P(v[5])?0:obj2nsec(v[5], nsec);
467 /* value validation */
468 if (
469 tm->tm_year != year ||
470 #ifndef NEGATIVE_TIME_T
471 tm->tm_year < 69 ||
472 #endif
473 tm->tm_mon < 0 || tm->tm_mon > 11
474 || tm->tm_mday < 1 || tm->tm_mday > 31
475 || tm->tm_hour < 0 || tm->tm_hour > 24
476 || (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0))
477 || tm->tm_min < 0 || tm->tm_min > 59
478 || tm->tm_sec < 0 || tm->tm_sec > 60)
479 rb_raise(rb_eArgError, "argument out of range");
482 static VALUE time_gmtime(VALUE);
483 static VALUE time_localtime(VALUE);
484 static VALUE time_get_tm(VALUE, int);
486 static int
487 leap_year_p(long y)
489 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
492 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
494 static time_t
495 timegm_noleapsecond(struct tm *tm)
497 static const int common_year_yday_offset[] = {
499 -1 + 31,
500 -1 + 31 + 28,
501 -1 + 31 + 28 + 31,
502 -1 + 31 + 28 + 31 + 30,
503 -1 + 31 + 28 + 31 + 30 + 31,
504 -1 + 31 + 28 + 31 + 30 + 31 + 30,
505 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
506 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
507 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
508 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
509 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
510 /* 1 2 3 4 5 6 7 8 9 10 11 */
512 static const int leap_year_yday_offset[] = {
514 -1 + 31,
515 -1 + 31 + 29,
516 -1 + 31 + 29 + 31,
517 -1 + 31 + 29 + 31 + 30,
518 -1 + 31 + 29 + 31 + 30 + 31,
519 -1 + 31 + 29 + 31 + 30 + 31 + 30,
520 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
521 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
522 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
523 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
524 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
525 /* 1 2 3 4 5 6 7 8 9 10 11 */
528 long tm_year = tm->tm_year;
529 int tm_yday = tm->tm_mday;
530 if (leap_year_p(tm_year + 1900))
531 tm_yday += leap_year_yday_offset[tm->tm_mon];
532 else
533 tm_yday += common_year_yday_offset[tm->tm_mon];
536 * `Seconds Since the Epoch' in SUSv3:
537 * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
538 * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
539 * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
541 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
542 (time_t)(tm_yday +
543 (tm_year-70)*365 +
544 DIV(tm_year-69,4) -
545 DIV(tm_year-1,100) +
546 DIV(tm_year+299,400))*86400;
549 static int
550 tmcmp(struct tm *a, struct tm *b)
552 if (a->tm_year != b->tm_year)
553 return a->tm_year < b->tm_year ? -1 : 1;
554 else if (a->tm_mon != b->tm_mon)
555 return a->tm_mon < b->tm_mon ? -1 : 1;
556 else if (a->tm_mday != b->tm_mday)
557 return a->tm_mday < b->tm_mday ? -1 : 1;
558 else if (a->tm_hour != b->tm_hour)
559 return a->tm_hour < b->tm_hour ? -1 : 1;
560 else if (a->tm_min != b->tm_min)
561 return a->tm_min < b->tm_min ? -1 : 1;
562 else if (a->tm_sec != b->tm_sec)
563 return a->tm_sec < b->tm_sec ? -1 : 1;
564 else
565 return 0;
568 #if SIZEOF_TIME_T == SIZEOF_LONG
569 typedef unsigned long unsigned_time_t;
570 #elif SIZEOF_TIME_T == SIZEOF_INT
571 typedef unsigned int unsigned_time_t;
572 #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
573 typedef unsigned LONG_LONG unsigned_time_t;
574 #else
575 # error cannot find integer type which size is same as time_t.
576 #endif
578 static time_t
579 search_time_t(struct tm *tptr, int utc_p)
581 time_t guess, guess_lo, guess_hi;
582 struct tm *tm, tm_lo, tm_hi;
583 int d, have_guess;
584 int find_dst;
586 find_dst = 0 < tptr->tm_isdst;
588 #ifdef NEGATIVE_TIME_T
589 guess_lo = (time_t)~((unsigned_time_t)~(time_t)0 >> 1);
590 #else
591 guess_lo = 0;
592 #endif
593 guess_hi = ((time_t)-1) < ((time_t)0) ?
594 (time_t)((unsigned_time_t)~(time_t)0 >> 1) :
595 ~(time_t)0;
597 guess = timegm_noleapsecond(tptr);
598 tm = (utc_p ? gmtime : localtime)(&guess);
599 if (tm) {
600 d = tmcmp(tptr, tm);
601 if (d == 0) return guess;
602 if (d < 0) {
603 guess_hi = guess;
604 guess -= 24 * 60 * 60;
606 else {
607 guess_lo = guess;
608 guess += 24 * 60 * 60;
610 if (guess_lo < guess && guess < guess_hi &&
611 (tm = (utc_p ? gmtime : localtime)(&guess)) != NULL) {
612 d = tmcmp(tptr, tm);
613 if (d == 0) return guess;
614 if (d < 0)
615 guess_hi = guess;
616 else
617 guess_lo = guess;
621 tm = (utc_p ? gmtime : localtime)(&guess_lo);
622 if (!tm) goto error;
623 d = tmcmp(tptr, tm);
624 if (d < 0) goto out_of_range;
625 if (d == 0) return guess_lo;
626 tm_lo = *tm;
628 tm = (utc_p ? gmtime : localtime)(&guess_hi);
629 if (!tm) goto error;
630 d = tmcmp(tptr, tm);
631 if (d > 0) goto out_of_range;
632 if (d == 0) return guess_hi;
633 tm_hi = *tm;
635 have_guess = 0;
637 while (guess_lo + 1 < guess_hi) {
638 /* there is a gap between guess_lo and guess_hi. */
639 unsigned long range = 0;
640 if (!have_guess) {
641 int a, b;
643 Try precious guess by a linear interpolation at first.
644 `a' and `b' is a coefficient of guess_lo and guess_hi as:
646 guess = (guess_lo * a + guess_hi * b) / (a + b)
648 However this causes overflow in most cases, following assignment
649 is used instead:
651 guess = guess_lo / d * a + (guess_lo % d) * a / d
652 + guess_hi / d * b + (guess_hi % d) * b / d
653 where d = a + b
655 To avoid overflow in this assignment, `d' is restricted to less than
656 sqrt(2**31). By this restriction and other reasons, the guess is
657 not accurate and some error is expected. `range' approximates
658 the maximum error.
660 When these parameters are not suitable, i.e. guess is not within
661 guess_lo and guess_hi, simple guess by binary search is used.
663 range = 366 * 24 * 60 * 60;
664 a = (tm_hi.tm_year - tptr->tm_year);
665 b = (tptr->tm_year - tm_lo.tm_year);
666 /* 46000 is selected as `some big number less than sqrt(2**31)'. */
667 if (a + b <= 46000 / 12) {
668 range = 31 * 24 * 60 * 60;
669 a *= 12;
670 b *= 12;
671 a += tm_hi.tm_mon - tptr->tm_mon;
672 b += tptr->tm_mon - tm_lo.tm_mon;
673 if (a + b <= 46000 / 31) {
674 range = 24 * 60 * 60;
675 a *= 31;
676 b *= 31;
677 a += tm_hi.tm_mday - tptr->tm_mday;
678 b += tptr->tm_mday - tm_lo.tm_mday;
679 if (a + b <= 46000 / 24) {
680 range = 60 * 60;
681 a *= 24;
682 b *= 24;
683 a += tm_hi.tm_hour - tptr->tm_hour;
684 b += tptr->tm_hour - tm_lo.tm_hour;
685 if (a + b <= 46000 / 60) {
686 range = 60;
687 a *= 60;
688 b *= 60;
689 a += tm_hi.tm_min - tptr->tm_min;
690 b += tptr->tm_min - tm_lo.tm_min;
691 if (a + b <= 46000 / 60) {
692 range = 1;
693 a *= 60;
694 b *= 60;
695 a += tm_hi.tm_sec - tptr->tm_sec;
696 b += tptr->tm_sec - tm_lo.tm_sec;
702 if (a <= 0) a = 1;
703 if (b <= 0) b = 1;
704 d = a + b;
706 Although `/' and `%' may produce unexpected result with negative
707 argument, it doesn't cause serious problem because there is a
708 fail safe.
710 guess = guess_lo / d * a + (guess_lo % d) * a / d
711 + guess_hi / d * b + (guess_hi % d) * b / d;
712 have_guess = 1;
715 if (guess <= guess_lo || guess_hi <= guess) {
716 /* Precious guess is invalid. try binary search. */
717 guess = guess_lo / 2 + guess_hi / 2;
718 if (guess <= guess_lo)
719 guess = guess_lo + 1;
720 else if (guess >= guess_hi)
721 guess = guess_hi - 1;
722 range = 0;
725 tm = (utc_p ? gmtime : localtime)(&guess);
726 if (!tm) goto error;
727 have_guess = 0;
729 d = tmcmp(tptr, tm);
730 if (d < 0) {
731 guess_hi = guess;
732 tm_hi = *tm;
733 if (range) {
734 guess = guess - range;
735 range = 0;
736 if (guess_lo < guess && guess < guess_hi)
737 have_guess = 1;
740 else if (d > 0) {
741 guess_lo = guess;
742 tm_lo = *tm;
743 if (range) {
744 guess = guess + range;
745 range = 0;
746 if (guess_lo < guess && guess < guess_hi)
747 have_guess = 1;
750 else {
751 if (!utc_p) {
752 /* If localtime is nonmonotonic, another result may exist. */
753 time_t guess2;
754 if (find_dst) {
755 guess2 = guess - 2 * 60 * 60;
756 tm = localtime(&guess2);
757 if (tm) {
758 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
759 tptr->tm_min != tm->tm_min ||
760 tptr->tm_sec != tm->tm_sec
762 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
763 (tm->tm_min - tptr->tm_min) * 60 +
764 (tm->tm_sec - tptr->tm_sec);
765 if (tptr->tm_mday != tm->tm_mday)
766 guess2 += 24 * 60 * 60;
767 if (guess != guess2) {
768 tm = localtime(&guess2);
769 if (tmcmp(tptr, tm) == 0) {
770 if (guess < guess2)
771 return guess;
772 else
773 return guess2;
779 else {
780 guess2 = guess + 2 * 60 * 60;
781 tm = localtime(&guess2);
782 if (tm) {
783 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
784 tptr->tm_min != tm->tm_min ||
785 tptr->tm_sec != tm->tm_sec
787 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
788 (tm->tm_min - tptr->tm_min) * 60 +
789 (tm->tm_sec - tptr->tm_sec);
790 if (tptr->tm_mday != tm->tm_mday)
791 guess2 -= 24 * 60 * 60;
792 if (guess != guess2) {
793 tm = localtime(&guess2);
794 if (tmcmp(tptr, tm) == 0) {
795 if (guess < guess2)
796 return guess2;
797 else
798 return guess;
805 return guess;
808 /* Given argument has no corresponding time_t. Let's outerpolation. */
809 if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) {
810 return guess_lo +
811 (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 +
812 (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 +
813 (tptr->tm_min - tm_lo.tm_min) * 60 +
814 (tptr->tm_sec - tm_lo.tm_sec);
816 else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
817 return guess_hi +
818 (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
819 (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
820 (tptr->tm_min - tm_hi.tm_min) * 60 +
821 (tptr->tm_sec - tm_hi.tm_sec);
824 out_of_range:
825 rb_raise(rb_eArgError, "time out of range");
827 error:
828 rb_raise(rb_eArgError, "gmtime/localtime error");
829 return 0; /* not reached */
832 static time_t
833 make_time_t(struct tm *tptr, int utc_p)
835 time_t t;
836 #ifdef NEGATIVE_TIME_T
837 struct tm *tmp;
838 #endif
839 struct tm buf;
840 buf = *tptr;
841 if (utc_p) {
842 #if defined(HAVE_TIMEGM)
843 if ((t = timegm(&buf)) != -1)
844 return t;
845 #ifdef NEGATIVE_TIME_T
846 if ((tmp = gmtime(&t)) &&
847 tptr->tm_year == tmp->tm_year &&
848 tptr->tm_mon == tmp->tm_mon &&
849 tptr->tm_mday == tmp->tm_mday &&
850 tptr->tm_hour == tmp->tm_hour &&
851 tptr->tm_min == tmp->tm_min &&
852 tptr->tm_sec == tmp->tm_sec
854 return t;
855 #endif
856 #endif
857 return search_time_t(&buf, utc_p);
859 else {
860 #if defined(HAVE_MKTIME)
861 if ((t = mktime(&buf)) != -1)
862 return t;
863 #ifdef NEGATIVE_TIME_T
864 if ((tmp = localtime(&t)) &&
865 tptr->tm_year == tmp->tm_year &&
866 tptr->tm_mon == tmp->tm_mon &&
867 tptr->tm_mday == tmp->tm_mday &&
868 tptr->tm_hour == tmp->tm_hour &&
869 tptr->tm_min == tmp->tm_min &&
870 tptr->tm_sec == tmp->tm_sec
872 return t;
873 #endif
874 #endif
875 return search_time_t(&buf, utc_p);
879 static VALUE
880 time_utc_or_local(int argc, VALUE *argv, int utc_p, VALUE klass)
882 struct tm tm;
883 VALUE time;
884 long nsec;
886 time_arg(argc, argv, &tm, &nsec);
887 time = time_new_internal(klass, make_time_t(&tm, utc_p), nsec);
888 if (utc_p) return time_gmtime(time);
889 return time_localtime(time);
893 * call-seq:
894 * Time.utc(year) => time
895 * Time.utc(year, month) => time
896 * Time.utc(year, month, day) => time
897 * Time.utc(year, month, day, hour) => time
898 * Time.utc(year, month, day, hour, min) => time
899 * Time.utc(year, month, day, hour, min, sec_with_frac) => time
900 * Time.utc(year, month, day, hour, min, sec, usec_with_frac) => time
901 * Time.utc(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
902 * Time.gm(year) => time
903 * Time.gm(year, month) => time
904 * Time.gm(year, month, day) => time
905 * Time.gm(year, month, day, hour) => time
906 * Time.gm(year, month, day, hour, min) => time
907 * Time.gm(year, month, day, hour, min, sec_with_frac) => time
908 * Time.gm(year, month, day, hour, min, sec, usec_with_frac) => time
909 * Time.gm(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
911 * Creates a time based on given values, interpreted as UTC (GMT). The
912 * year must be specified. Other values default to the minimum value
913 * for that field (and may be <code>nil</code> or omitted). Months may
914 * be specified by numbers from 1 to 12, or by the three-letter English
915 * month names. Hours are specified on a 24-hour clock (0..23). Raises
916 * an <code>ArgumentError</code> if any values are out of range. Will
917 * also accept ten arguments in the order output by
918 * <code>Time#to_a</code>.
919 * <i>sec_with_frac</i> and <i>usec_with_frac</i> can have a fractional part.
921 * Time.utc(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
922 * Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
924 static VALUE
925 time_s_mkutc(int argc, VALUE *argv, VALUE klass)
927 return time_utc_or_local(argc, argv, Qtrue, klass);
931 * call-seq:
932 * Time.local(year) => time
933 * Time.local(year, month) => time
934 * Time.local(year, month, day) => time
935 * Time.local(year, month, day, hour) => time
936 * Time.local(year, month, day, hour, min) => time
937 * Time.local(year, month, day, hour, min, sec_with_frac) => time
938 * Time.local(year, month, day, hour, min, sec, usec_with_frac) => time
939 * Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
940 * Time.mktime(year) => time
941 * Time.mktime(year, month) => time
942 * Time.mktime(year, month, day) => time
943 * Time.mktime(year, month, day, hour) => time
944 * Time.mktime(year, month, day, hour, min) => time
945 * Time.mktime(year, month, day, hour, min, sec_with_frac) => time
946 * Time.mktime(year, month, day, hour, min, sec, usec_with_frac) => time
947 * Time.mktime(sec, min, hour, day, month, year, wday, yday, isdst, tz) => time
949 * Same as <code>Time::gm</code>, but interprets the values in the
950 * local time zone.
952 * Time.local(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 -0600
955 static VALUE
956 time_s_mktime(int argc, VALUE *argv, VALUE klass)
958 return time_utc_or_local(argc, argv, Qfalse, klass);
962 * call-seq:
963 * time.to_i => int
964 * time.tv_sec => int
966 * Returns the value of <i>time</i> as an integer number of seconds
967 * since the Epoch.
969 * t = Time.now
970 * "%10.5f" % t.to_f #=> "1049896564.17839"
971 * t.to_i #=> 1049896564
974 static VALUE
975 time_to_i(VALUE time)
977 struct time_object *tobj;
979 GetTimeval(time, tobj);
980 return LONG2NUM(tobj->ts.tv_sec);
984 * call-seq:
985 * time.to_f => float
987 * Returns the value of <i>time</i> as a floating point number of
988 * seconds since the Epoch.
990 * t = Time.now
991 * "%10.5f" % t.to_f #=> "1049896564.13654"
992 * t.to_i #=> 1049896564
994 * Note that IEEE 754 double is not accurate enough to represent
995 * nanoseconds from the Epoch.
998 static VALUE
999 time_to_f(VALUE time)
1001 struct time_object *tobj;
1003 GetTimeval(time, tobj);
1004 return DOUBLE2NUM((double)tobj->ts.tv_sec+(double)tobj->ts.tv_nsec/1e9);
1008 * call-seq:
1009 * time.usec => int
1010 * time.tv_usec => int
1012 * Returns just the number of microseconds for <i>time</i>.
1014 * t = Time.now #=> 2007-11-19 08:03:26 -0600
1015 * "%10.6f" % t.to_f #=> "1195481006.775195"
1016 * t.usec #=> 775195
1019 static VALUE
1020 time_usec(VALUE time)
1022 struct time_object *tobj;
1024 GetTimeval(time, tobj);
1025 return LONG2NUM(tobj->ts.tv_nsec/1000);
1029 * call-seq:
1030 * time.nsec => int
1031 * time.tv_nsec => int
1033 * Returns just the number of nanoseconds for <i>time</i>.
1035 * t = Time.now #=> 2007-11-17 15:18:03 +0900
1036 * "%10.9f" % t.to_f #=> "1195280283.536151409"
1037 * t.nsec #=> 536151406
1039 * The lowest digit of to_f and nsec is different because
1040 * IEEE 754 double is not accurate enough to represent
1041 * nanoseconds from the Epoch.
1042 * The accurate value is returned by nsec.
1045 static VALUE
1046 time_nsec(VALUE time)
1048 struct time_object *tobj;
1050 GetTimeval(time, tobj);
1051 return LONG2NUM(tobj->ts.tv_nsec);
1055 * call-seq:
1056 * time <=> other_time => -1, 0, +1
1058 * Comparison---Compares <i>time</i> with <i>other_time</i>.
1060 * t = Time.now #=> 2007-11-19 08:12:12 -0600
1061 * t2 = t + 2592000 #=> 2007-12-19 08:12:12 -0600
1062 * t <=> t2 #=> -1
1063 * t2 <=> t #=> 1
1065 * t = Time.now #=> 2007-11-19 08:13:38 -0600
1066 * t2 = t + 0.1 #=> 2007-11-19 08:13:38 -0600
1067 * t.nsec #=> 98222999
1068 * t2.nsec #=> 198222999
1069 * t <=> t2 #=> -1
1070 * t2 <=> t #=> 1
1071 * t <=> t #=> 0
1074 static VALUE
1075 time_cmp(VALUE time1, VALUE time2)
1077 struct time_object *tobj1, *tobj2;
1079 GetTimeval(time1, tobj1);
1080 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
1081 GetTimeval(time2, tobj2);
1082 if (tobj1->ts.tv_sec == tobj2->ts.tv_sec) {
1083 if (tobj1->ts.tv_nsec == tobj2->ts.tv_nsec) return INT2FIX(0);
1084 if (tobj1->ts.tv_nsec > tobj2->ts.tv_nsec) return INT2FIX(1);
1085 return INT2FIX(-1);
1087 if (tobj1->ts.tv_sec > tobj2->ts.tv_sec) return INT2FIX(1);
1088 return INT2FIX(-1);
1090 else {
1091 VALUE cmp;
1092 int n;
1094 cmp = rb_funcall(time2, rb_intern("<=>"), 1, time1);
1095 if (NIL_P(cmp)) return Qnil;
1097 n = rb_cmpint(cmp, time1, time2);
1098 if (n == 0) return INT2FIX(0);
1099 if (n > 0) return INT2FIX(1);
1100 return INT2FIX(-1);
1105 * call-seq:
1106 * time.eql?(other_time)
1108 * Return <code>true</code> if <i>time</i> and <i>other_time</i> are
1109 * both <code>Time</code> objects with the same seconds and fractional
1110 * seconds.
1113 static VALUE
1114 time_eql(VALUE time1, VALUE time2)
1116 struct time_object *tobj1, *tobj2;
1118 GetTimeval(time1, tobj1);
1119 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
1120 GetTimeval(time2, tobj2);
1121 if (tobj1->ts.tv_sec == tobj2->ts.tv_sec) {
1122 if (tobj1->ts.tv_nsec == tobj2->ts.tv_nsec) return Qtrue;
1125 return Qfalse;
1129 * call-seq:
1130 * time.utc? => true or false
1131 * time.gmt? => true or false
1133 * Returns <code>true</code> if <i>time</i> represents a time in UTC
1134 * (GMT).
1136 * t = Time.now #=> 2007-11-19 08:15:23 -0600
1137 * t.utc? #=> false
1138 * t = Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1139 * t.utc? #=> true
1141 * t = Time.now #=> 2007-11-19 08:16:03 -0600
1142 * t.gmt? #=> false
1143 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1144 * t.gmt? #=> true
1147 static VALUE
1148 time_utc_p(VALUE time)
1150 struct time_object *tobj;
1152 GetTimeval(time, tobj);
1153 if (tobj->gmt) return Qtrue;
1154 return Qfalse;
1158 * call-seq:
1159 * time.hash => fixnum
1161 * Return a hash code for this time object.
1164 static VALUE
1165 time_hash(VALUE time)
1167 struct time_object *tobj;
1168 long hash;
1170 GetTimeval(time, tobj);
1171 hash = tobj->ts.tv_sec ^ tobj->ts.tv_nsec;
1172 return LONG2FIX(hash);
1175 /* :nodoc: */
1176 static VALUE
1177 time_init_copy(VALUE copy, VALUE time)
1179 struct time_object *tobj, *tcopy;
1181 if (copy == time) return copy;
1182 time_modify(copy);
1183 if (TYPE(time) != T_DATA || RDATA(time)->dfree != time_free) {
1184 rb_raise(rb_eTypeError, "wrong argument type");
1186 GetTimeval(time, tobj);
1187 GetTimeval(copy, tcopy);
1188 MEMCPY(tcopy, tobj, struct time_object, 1);
1190 return copy;
1193 static VALUE
1194 time_dup(VALUE time)
1196 VALUE dup = time_s_alloc(CLASS_OF(time));
1197 time_init_copy(dup, time);
1198 return dup;
1202 * call-seq:
1203 * time.localtime => time
1205 * Converts <i>time</i> to local time (using the local time zone in
1206 * effect for this process) modifying the receiver.
1208 * t = Time.gm(2000, "jan", 1, 20, 15, 1) #=> 2000-01-01 20:15:01 UTC
1209 * t.gmt? #=> true
1210 * t.localtime #=> 2000-01-01 14:15:01 -0600
1211 * t.gmt? #=> false
1214 static VALUE
1215 time_localtime(VALUE time)
1217 struct time_object *tobj;
1218 struct tm *tm_tmp;
1219 time_t t;
1221 GetTimeval(time, tobj);
1222 if (!tobj->gmt) {
1223 if (tobj->tm_got)
1224 return time;
1226 else {
1227 time_modify(time);
1229 t = tobj->ts.tv_sec;
1230 tm_tmp = localtime(&t);
1231 if (!tm_tmp)
1232 rb_raise(rb_eArgError, "localtime error");
1233 tobj->tm = *tm_tmp;
1234 tobj->tm_got = 1;
1235 tobj->gmt = 0;
1236 return time;
1240 * call-seq:
1241 * time.gmtime => time
1242 * time.utc => time
1244 * Converts <i>time</i> to UTC (GMT), modifying the receiver.
1246 * t = Time.now #=> 2007-11-19 08:18:31 -0600
1247 * t.gmt? #=> false
1248 * t.gmtime #=> 2007-11-19 14:18:31 UTC
1249 * t.gmt? #=> true
1251 * t = Time.now #=> 2007-11-19 08:18:51 -0600
1252 * t.utc? #=> false
1253 * t.utc #=> 2007-11-19 14:18:51 UTC
1254 * t.utc? #=> true
1257 static VALUE
1258 time_gmtime(VALUE time)
1260 struct time_object *tobj;
1261 struct tm *tm_tmp;
1262 time_t t;
1264 GetTimeval(time, tobj);
1265 if (tobj->gmt) {
1266 if (tobj->tm_got)
1267 return time;
1269 else {
1270 time_modify(time);
1272 t = tobj->ts.tv_sec;
1273 tm_tmp = gmtime(&t);
1274 if (!tm_tmp)
1275 rb_raise(rb_eArgError, "gmtime error");
1276 tobj->tm = *tm_tmp;
1277 tobj->tm_got = 1;
1278 tobj->gmt = 1;
1279 return time;
1283 * call-seq:
1284 * time.getlocal => new_time
1286 * Returns a new <code>new_time</code> object representing <i>time</i> in
1287 * local time (using the local time zone in effect for this process).
1289 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1290 * t.gmt? #=> true
1291 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
1292 * l.gmt? #=> false
1293 * t == l #=> true
1296 static VALUE
1297 time_getlocaltime(VALUE time)
1299 return time_localtime(time_dup(time));
1303 * call-seq:
1304 * time.getgm => new_time
1305 * time.getutc => new_time
1307 * Returns a new <code>new_time</code> object representing <i>time</i> in
1308 * UTC.
1310 * t = Time.local(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 -0600
1311 * t.gmt? #=> false
1312 * y = t.getgm #=> 2000-01-02 02:15:01 UTC
1313 * y.gmt? #=> true
1314 * t == y #=> true
1317 static VALUE
1318 time_getgmtime(VALUE time)
1320 return time_gmtime(time_dup(time));
1323 static VALUE
1324 time_get_tm(VALUE time, int gmt)
1326 if (gmt) return time_gmtime(time);
1327 return time_localtime(time);
1331 * call-seq:
1332 * time.asctime => string
1333 * time.ctime => string
1335 * Returns a canonical string representation of <i>time</i>.
1337 * Time.now.asctime #=> "Wed Apr 9 08:56:03 2003"
1340 static VALUE
1341 time_asctime(VALUE time)
1343 struct time_object *tobj;
1344 char *s;
1346 GetTimeval(time, tobj);
1347 if (tobj->tm_got == 0) {
1348 time_get_tm(time, tobj->gmt);
1350 s = asctime(&tobj->tm);
1351 if (s[24] == '\n') s[24] = '\0';
1353 return rb_str_new2(s);
1357 * call-seq:
1358 * time.inspect => string
1359 * time.to_s => string
1361 * Returns a string representing <i>time</i>. Equivalent to calling
1362 * <code>Time#strftime</code> with a format string of
1363 * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>%z</code>''
1364 * for a local time and
1365 * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>UTC</code>''
1366 * for a UTC time.
1368 * Time.now.to_s #=> "2007-10-05 16:09:51 +0900"
1369 * Time.now.utc.to_s #=> "2007-10-05 07:09:51 UTC"
1372 static VALUE
1373 time_to_s(VALUE time)
1375 struct time_object *tobj;
1376 char buf[128];
1377 int len;
1379 GetTimeval(time, tobj);
1380 if (tobj->tm_got == 0) {
1381 time_get_tm(time, tobj->gmt);
1383 if (tobj->gmt == 1) {
1384 len = strftime(buf, 128, "%Y-%m-%d %H:%M:%S UTC", &tobj->tm);
1386 else {
1387 long off;
1388 char sign = '+';
1389 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1390 off = tobj->tm.tm_gmtoff;
1391 #else
1392 VALUE tmp = time_utc_offset(time);
1393 off = NUM2INT(tmp);
1394 #endif
1395 if (off < 0) {
1396 sign = '-';
1397 off = -off;
1399 len = strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S ", &tobj->tm);
1400 len += snprintf(buf+len, sizeof(buf)-len, "%c%02d%02d", sign,
1401 (int)(off/3600), (int)(off%3600/60));
1403 return rb_str_new(buf, len);
1406 static VALUE
1407 time_add(struct time_object *tobj, VALUE offset, int sign)
1409 double v = NUM2DBL(offset);
1410 double f, d;
1411 unsigned_time_t sec_off;
1412 time_t sec;
1413 long nsec_off, nsec;
1414 VALUE result;
1416 if (v < 0) {
1417 v = -v;
1418 sign = -sign;
1420 d = modf(v, &f);
1421 sec_off = (unsigned_time_t)f;
1422 if (f != (double)sec_off)
1423 rb_raise(rb_eRangeError, "time %s %f out of Time range",
1424 sign < 0 ? "-" : "+", v);
1425 nsec_off = (long)(d*1e9+0.5);
1427 if (sign < 0) {
1428 sec = tobj->ts.tv_sec - sec_off;
1429 nsec = tobj->ts.tv_nsec - nsec_off;
1430 if (sec > tobj->ts.tv_sec)
1431 rb_raise(rb_eRangeError, "time - %f out of Time range", v);
1433 else {
1434 sec = tobj->ts.tv_sec + sec_off;
1435 nsec = tobj->ts.tv_nsec + nsec_off;
1436 if (sec < tobj->ts.tv_sec)
1437 rb_raise(rb_eRangeError, "time + %f out of Time range", v);
1439 result = rb_time_nano_new(sec, nsec);
1440 if (tobj->gmt) {
1441 GetTimeval(result, tobj);
1442 tobj->gmt = 1;
1444 return result;
1448 * call-seq:
1449 * time + numeric => time
1451 * Addition---Adds some number of seconds (possibly fractional) to
1452 * <i>time</i> and returns that value as a new time.
1454 * t = Time.now #=> 2007-11-19 08:22:21 -0600
1455 * t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
1458 static VALUE
1459 time_plus(VALUE time1, VALUE time2)
1461 struct time_object *tobj;
1462 GetTimeval(time1, tobj);
1464 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
1465 rb_raise(rb_eTypeError, "time + time?");
1467 return time_add(tobj, time2, 1);
1471 * call-seq:
1472 * time - other_time => float
1473 * time - numeric => time
1475 * Difference---Returns a new time that represents the difference
1476 * between two times, or subtracts the given number of seconds in
1477 * <i>numeric</i> from <i>time</i>.
1479 * t = Time.now #=> 2007-11-19 08:23:10 -0600
1480 * t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
1481 * t2 - t #=> 2592000.0
1482 * t2 - 2592000 #=> 2007-11-19 08:23:10 -0600
1485 static VALUE
1486 time_minus(VALUE time1, VALUE time2)
1488 struct time_object *tobj;
1490 GetTimeval(time1, tobj);
1491 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
1492 struct time_object *tobj2;
1493 double f;
1495 GetTimeval(time2, tobj2);
1496 if (tobj->ts.tv_sec < tobj2->ts.tv_sec)
1497 f = -(double)(unsigned_time_t)(tobj2->ts.tv_sec - tobj->ts.tv_sec);
1498 else
1499 f = (double)(unsigned_time_t)(tobj->ts.tv_sec - tobj2->ts.tv_sec);
1500 f += ((double)tobj->ts.tv_nsec - (double)tobj2->ts.tv_nsec)*1e-9;
1502 return DOUBLE2NUM(f);
1504 return time_add(tobj, time2, -1);
1508 * call-seq:
1509 * time.succ => new_time
1511 * Return a new time object, one second later than <code>time</code>.
1513 * t = Time.now #=> 2007-11-19 08:23:57 -0600
1514 * t.succ #=> 2007-11-19 08:23:58 -0600
1517 static VALUE
1518 time_succ(VALUE time)
1520 struct time_object *tobj;
1521 int gmt;
1523 GetTimeval(time, tobj);
1524 gmt = tobj->gmt;
1525 time = rb_time_nano_new(tobj->ts.tv_sec + 1, tobj->ts.tv_nsec);
1526 GetTimeval(time, tobj);
1527 tobj->gmt = gmt;
1528 return time;
1531 VALUE
1532 rb_time_succ(VALUE time)
1534 return time_succ(time);
1538 * call-seq:
1539 * time.sec => fixnum
1541 * Returns the second of the minute (0..60)<em>[Yes, seconds really can
1542 * range from zero to 60. This allows the system to inject leap seconds
1543 * every now and then to correct for the fact that years are not really
1544 * a convenient number of hours long.]</em> for <i>time</i>.
1546 * t = Time.now #=> 2007-11-19 08:25:02 -0600
1547 * t.sec #=> 2
1550 static VALUE
1551 time_sec(VALUE time)
1553 struct time_object *tobj;
1555 GetTimeval(time, tobj);
1556 if (tobj->tm_got == 0) {
1557 time_get_tm(time, tobj->gmt);
1559 return INT2FIX(tobj->tm.tm_sec);
1563 * call-seq:
1564 * time.min => fixnum
1566 * Returns the minute of the hour (0..59) for <i>time</i>.
1568 * t = Time.now #=> 2007-11-19 08:25:51 -0600
1569 * t.min #=> 25
1572 static VALUE
1573 time_min(VALUE time)
1575 struct time_object *tobj;
1577 GetTimeval(time, tobj);
1578 if (tobj->tm_got == 0) {
1579 time_get_tm(time, tobj->gmt);
1581 return INT2FIX(tobj->tm.tm_min);
1585 * call-seq:
1586 * time.hour => fixnum
1588 * Returns the hour of the day (0..23) for <i>time</i>.
1590 * t = Time.now #=> 2007-11-19 08:26:20 -0600
1591 * t.hour #=> 8
1594 static VALUE
1595 time_hour(VALUE time)
1597 struct time_object *tobj;
1599 GetTimeval(time, tobj);
1600 if (tobj->tm_got == 0) {
1601 time_get_tm(time, tobj->gmt);
1603 return INT2FIX(tobj->tm.tm_hour);
1607 * call-seq:
1608 * time.day => fixnum
1609 * time.mday => fixnum
1611 * Returns the day of the month (1..n) for <i>time</i>.
1613 * t = Time.now #=> 2007-11-19 08:27:03 -0600
1614 * t.day #=> 19
1615 * t.mday #=> 19
1618 static VALUE
1619 time_mday(VALUE time)
1621 struct time_object *tobj;
1623 GetTimeval(time, tobj);
1624 if (tobj->tm_got == 0) {
1625 time_get_tm(time, tobj->gmt);
1627 return INT2FIX(tobj->tm.tm_mday);
1631 * call-seq:
1632 * time.mon => fixnum
1633 * time.month => fixnum
1635 * Returns the month of the year (1..12) for <i>time</i>.
1637 * t = Time.now #=> 2007-11-19 08:27:30 -0600
1638 * t.mon #=> 11
1639 * t.month #=> 11
1642 static VALUE
1643 time_mon(VALUE time)
1645 struct time_object *tobj;
1647 GetTimeval(time, tobj);
1648 if (tobj->tm_got == 0) {
1649 time_get_tm(time, tobj->gmt);
1651 return INT2FIX(tobj->tm.tm_mon+1);
1655 * call-seq:
1656 * time.year => fixnum
1658 * Returns the year for <i>time</i> (including the century).
1660 * t = Time.now #=> 2007-11-19 08:27:51 -0600
1661 * t.year #=> 2007
1664 static VALUE
1665 time_year(VALUE time)
1667 struct time_object *tobj;
1669 GetTimeval(time, tobj);
1670 if (tobj->tm_got == 0) {
1671 time_get_tm(time, tobj->gmt);
1673 return LONG2NUM((long)tobj->tm.tm_year+1900);
1677 * call-seq:
1678 * time.wday => fixnum
1680 * Returns an integer representing the day of the week, 0..6, with
1681 * Sunday == 0.
1683 * t = Time.now #=> 2007-11-20 02:35:35 -0600
1684 * t.wday #=> 2
1685 * t.sunday? #=> false
1686 * t.monday? #=> false
1687 * t.tuesday? #=> true
1688 * t.wednesday? #=> false
1689 * t.thursday? #=> false
1690 * t.friday? #=> false
1691 * t.saturday? #=> false
1694 static VALUE
1695 time_wday(VALUE time)
1697 struct time_object *tobj;
1699 GetTimeval(time, tobj);
1700 if (tobj->tm_got == 0) {
1701 time_get_tm(time, tobj->gmt);
1703 return INT2FIX(tobj->tm.tm_wday);
1706 #define wday_p(n) {\
1707 struct time_object *tobj;\
1708 GetTimeval(time, tobj);\
1709 if (tobj->tm_got == 0) {\
1710 time_get_tm(time, tobj->gmt);\
1712 return (tobj->tm.tm_wday == (n)) ? Qtrue : Qfalse;\
1716 * call-seq:
1717 * time.sunday? => true or false
1719 * Returns <code>true</code> if <i>time</i> represents Sunday.
1721 * t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
1722 * t.sunday? #=> true
1725 static VALUE
1726 time_sunday(VALUE time)
1728 wday_p(0);
1732 * call-seq:
1733 * time.monday? => true or false
1735 * Returns <code>true</code> if <i>time</i> represents Monday.
1737 * t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
1738 * p t.monday? #=> true
1741 static VALUE
1742 time_monday(VALUE time)
1744 wday_p(1);
1748 * call-seq:
1749 * time.tuesday? => true or false
1751 * Returns <code>true</code> if <i>time</i> represents Tuesday.
1753 * t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
1754 * p t.tuesday? #=> true
1757 static VALUE
1758 time_tuesday(VALUE time)
1760 wday_p(2);
1764 * call-seq:
1765 * time.wednesday? => true or false
1767 * Returns <code>true</code> if <i>time</i> represents Wednesday.
1769 * t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
1770 * p t.wednesday? #=> true
1773 static VALUE
1774 time_wednesday(VALUE time)
1776 wday_p(3);
1780 * call-seq:
1781 * time.thursday? => true or false
1783 * Returns <code>true</code> if <i>time</i> represents Thursday.
1785 * t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
1786 * p t.thursday? #=> true
1789 static VALUE
1790 time_thursday(VALUE time)
1792 wday_p(4);
1796 * call-seq:
1797 * time.friday? => true or false
1799 * Returns <code>true</code> if <i>time</i> represents Friday.
1801 * t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
1802 * t.friday? #=> true
1805 static VALUE
1806 time_friday(VALUE time)
1808 wday_p(5);
1812 * call-seq:
1813 * time.saturday? => true or false
1815 * Returns <code>true</code> if <i>time</i> represents Saturday.
1817 * t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
1818 * t.saturday? #=> true
1821 static VALUE
1822 time_saturday(VALUE time)
1824 wday_p(6);
1828 * call-seq:
1829 * time.yday => fixnum
1831 * Returns an integer representing the day of the year, 1..366.
1833 * t = Time.now #=> 2007-11-19 08:32:31 -0600
1834 * t.yday #=> 323
1837 static VALUE
1838 time_yday(VALUE time)
1840 struct time_object *tobj;
1842 GetTimeval(time, tobj);
1843 if (tobj->tm_got == 0) {
1844 time_get_tm(time, tobj->gmt);
1846 return INT2FIX(tobj->tm.tm_yday+1);
1850 * call-seq:
1851 * time.isdst => true or false
1852 * time.dst? => true or false
1854 * Returns <code>true</code> if <i>time</i> occurs during Daylight
1855 * Saving Time in its time zone.
1857 * # CST6CDT:
1858 * Time.local(2000, 1, 1).zone #=> "CST"
1859 * Time.local(2000, 1, 1).isdst #=> false
1860 * Time.local(2000, 1, 1).dst? #=> false
1861 * Time.local(2000, 7, 1).zone #=> "CDT"
1862 * Time.local(2000, 7, 1).isdst #=> true
1863 * Time.local(2000, 7, 1).dst? #=> true
1865 * # Asia/Tokyo:
1866 * Time.local(2000, 1, 1).zone #=> "JST"
1867 * Time.local(2000, 1, 1).isdst #=> false
1868 * Time.local(2000, 1, 1).dst? #=> false
1869 * Time.local(2000, 7, 1).zone #=> "JST"
1870 * Time.local(2000, 7, 1).isdst #=> false
1871 * Time.local(2000, 7, 1).dst? #=> false
1874 static VALUE
1875 time_isdst(VALUE time)
1877 struct time_object *tobj;
1879 GetTimeval(time, tobj);
1880 if (tobj->tm_got == 0) {
1881 time_get_tm(time, tobj->gmt);
1883 return tobj->tm.tm_isdst?Qtrue:Qfalse;
1887 * call-seq:
1888 * time.zone => string
1890 * Returns the name of the time zone used for <i>time</i>. As of Ruby
1891 * 1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
1893 * t = Time.gm(2000, "jan", 1, 20, 15, 1)
1894 * t.zone #=> "UTC"
1895 * t = Time.local(2000, "jan", 1, 20, 15, 1)
1896 * t.zone #=> "CST"
1899 static VALUE
1900 time_zone(VALUE time)
1902 struct time_object *tobj;
1903 #if !defined(HAVE_TM_ZONE) && (!defined(HAVE_TZNAME) || !defined(HAVE_DAYLIGHT))
1904 char buf[64];
1905 int len;
1906 #endif
1908 GetTimeval(time, tobj);
1909 if (tobj->tm_got == 0) {
1910 time_get_tm(time, tobj->gmt);
1913 if (tobj->gmt == 1) {
1914 return rb_str_new2("UTC");
1916 #if defined(HAVE_TM_ZONE)
1917 return rb_str_new2(tobj->tm.tm_zone);
1918 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1919 return rb_str_new2(tzname[daylight && tobj->tm.tm_isdst]);
1920 #else
1921 len = strftime(buf, 64, "%Z", &tobj->tm);
1922 return rb_str_new(buf, len);
1923 #endif
1927 * call-seq:
1928 * time.gmt_offset => fixnum
1929 * time.gmtoff => fixnum
1930 * time.utc_offset => fixnum
1932 * Returns the offset in seconds between the timezone of <i>time</i>
1933 * and UTC.
1935 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1936 * t.gmt_offset #=> 0
1937 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
1938 * l.gmt_offset #=> -21600
1941 static VALUE
1942 time_utc_offset(VALUE time)
1944 struct time_object *tobj;
1946 GetTimeval(time, tobj);
1947 if (tobj->tm_got == 0) {
1948 time_get_tm(time, tobj->gmt);
1951 if (tobj->gmt == 1) {
1952 return INT2FIX(0);
1954 else {
1955 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1956 return INT2NUM(tobj->tm.tm_gmtoff);
1957 #else
1958 struct tm *u, *l;
1959 time_t t;
1960 long off;
1961 l = &tobj->tm;
1962 t = tobj->ts.tv_sec;
1963 u = gmtime(&t);
1964 if (!u)
1965 rb_raise(rb_eArgError, "gmtime error");
1966 if (l->tm_year != u->tm_year)
1967 off = l->tm_year < u->tm_year ? -1 : 1;
1968 else if (l->tm_mon != u->tm_mon)
1969 off = l->tm_mon < u->tm_mon ? -1 : 1;
1970 else if (l->tm_mday != u->tm_mday)
1971 off = l->tm_mday < u->tm_mday ? -1 : 1;
1972 else
1973 off = 0;
1974 off = off * 24 + l->tm_hour - u->tm_hour;
1975 off = off * 60 + l->tm_min - u->tm_min;
1976 off = off * 60 + l->tm_sec - u->tm_sec;
1977 return LONG2FIX(off);
1978 #endif
1983 * call-seq:
1984 * time.to_a => array
1986 * Returns a ten-element <i>array</i> of values for <i>time</i>:
1987 * {<code>[ sec, min, hour, day, month, year, wday, yday, isdst, zone
1988 * ]</code>}. See the individual methods for an explanation of the
1989 * valid ranges of each value. The ten elements can be passed directly
1990 * to <code>Time::utc</code> or <code>Time::local</code> to create a
1991 * new <code>Time</code>.
1993 * t = Time.now #=> 2007-11-19 08:36:01 -0600
1994 * now = t.to_a #=> [1, 36, 8, 19, 11, 2007, 1, 323, false, "CST"]
1997 static VALUE
1998 time_to_a(VALUE time)
2000 struct time_object *tobj;
2002 GetTimeval(time, tobj);
2003 if (tobj->tm_got == 0) {
2004 time_get_tm(time, tobj->gmt);
2006 return rb_ary_new3(10,
2007 INT2FIX(tobj->tm.tm_sec),
2008 INT2FIX(tobj->tm.tm_min),
2009 INT2FIX(tobj->tm.tm_hour),
2010 INT2FIX(tobj->tm.tm_mday),
2011 INT2FIX(tobj->tm.tm_mon+1),
2012 LONG2NUM((long)tobj->tm.tm_year+1900),
2013 INT2FIX(tobj->tm.tm_wday),
2014 INT2FIX(tobj->tm.tm_yday+1),
2015 tobj->tm.tm_isdst?Qtrue:Qfalse,
2016 time_zone(time));
2019 #define SMALLBUF 100
2020 static int
2021 rb_strftime(char **buf, const char *format, struct tm *time)
2023 int size, len, flen;
2025 (*buf)[0] = '\0';
2026 flen = strlen(format);
2027 if (flen == 0) {
2028 return 0;
2030 errno = 0;
2031 len = strftime(*buf, SMALLBUF, format, time);
2032 if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
2033 for (size=1024; ; size*=2) {
2034 *buf = xmalloc(size);
2035 (*buf)[0] = '\0';
2036 len = strftime(*buf, size, format, time);
2038 * buflen can be zero EITHER because there's not enough
2039 * room in the string, or because the control command
2040 * goes to the empty string. Make a reasonable guess that
2041 * if the buffer is 1024 times bigger than the length of the
2042 * format string, it's not failing for lack of room.
2044 if (len > 0 || size >= 1024 * flen) return len;
2045 xfree(*buf);
2047 /* not reached */
2051 * call-seq:
2052 * time.strftime( string ) => string
2054 * Formats <i>time</i> according to the directives in the given format
2055 * string. Any text not listed as a directive will be passed through
2056 * to the output string.
2058 * Format meaning:
2059 * %a - The abbreviated weekday name (``Sun'')
2060 * %A - The full weekday name (``Sunday'')
2061 * %b - The abbreviated month name (``Jan'')
2062 * %B - The full month name (``January'')
2063 * %c - The preferred local date and time representation
2064 * %d - Day of the month (01..31)
2065 * %H - Hour of the day, 24-hour clock (00..23)
2066 * %I - Hour of the day, 12-hour clock (01..12)
2067 * %j - Day of the year (001..366)
2068 * %m - Month of the year (01..12)
2069 * %M - Minute of the hour (00..59)
2070 * %p - Meridian indicator (``AM'' or ``PM'')
2071 * %S - Second of the minute (00..60)
2072 * %U - Week number of the current year,
2073 * starting with the first Sunday as the first
2074 * day of the first week (00..53)
2075 * %W - Week number of the current year,
2076 * starting with the first Monday as the first
2077 * day of the first week (00..53)
2078 * %w - Day of the week (Sunday is 0, 0..6)
2079 * %x - Preferred representation for the date alone, no time
2080 * %X - Preferred representation for the time alone, no date
2081 * %y - Year without a century (00..99)
2082 * %Y - Year with century
2083 * %Z - Time zone name
2084 * %% - Literal ``%'' character
2086 * t = Time.now #=> 2007-11-19 08:37:48 -0600
2087 * t.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007"
2088 * t.strftime("at %I:%M%p") #=> "at 08:37AM"
2091 static VALUE
2092 time_strftime(VALUE time, VALUE format)
2094 void rb_enc_copy(VALUE, VALUE);
2095 struct time_object *tobj;
2096 char buffer[SMALLBUF], *buf = buffer;
2097 const char *fmt;
2098 long len;
2099 VALUE str;
2101 GetTimeval(time, tobj);
2102 if (tobj->tm_got == 0) {
2103 time_get_tm(time, tobj->gmt);
2105 StringValue(format);
2106 if (!rb_enc_str_asciicompat_p(format)) {
2107 rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
2109 format = rb_str_new4(format);
2110 fmt = RSTRING_PTR(format);
2111 len = RSTRING_LEN(format);
2112 if (len == 0) {
2113 rb_warning("strftime called with empty format string");
2115 else if (strlen(fmt) < len) {
2116 /* Ruby string may contain \0's. */
2117 const char *p = fmt, *pe = fmt + len;
2119 str = rb_str_new(0, 0);
2120 while (p < pe) {
2121 len = rb_strftime(&buf, p, &tobj->tm);
2122 rb_str_cat(str, buf, len);
2123 p += strlen(p);
2124 if (buf != buffer) {
2125 xfree(buf);
2126 buf = buffer;
2128 for (fmt = p; p < pe && !*p; ++p);
2129 if (p > fmt) rb_str_cat(str, fmt, p - fmt);
2131 return str;
2133 else {
2134 len = rb_strftime(&buf, RSTRING_PTR(format), &tobj->tm);
2136 str = rb_str_new(buf, len);
2137 if (buf != buffer) xfree(buf);
2138 rb_enc_copy(str, format);
2139 return str;
2143 * undocumented
2146 static VALUE
2147 time_mdump(VALUE time)
2149 struct time_object *tobj;
2150 struct tm *tm;
2151 unsigned long p, s;
2152 char buf[8];
2153 time_t t;
2154 int nsec;
2155 int i;
2156 VALUE str;
2158 GetTimeval(time, tobj);
2160 t = tobj->ts.tv_sec;
2161 tm = gmtime(&t);
2163 if ((tm->tm_year & 0xffff) != tm->tm_year)
2164 rb_raise(rb_eArgError, "year too big to marshal: %ld", (long)tm->tm_year);
2166 p = 0x1UL << 31 | /* 1 */
2167 tobj->gmt << 30 | /* 1 */
2168 tm->tm_year << 14 | /* 16 */
2169 tm->tm_mon << 10 | /* 4 */
2170 tm->tm_mday << 5 | /* 5 */
2171 tm->tm_hour; /* 5 */
2172 s = tm->tm_min << 26 | /* 6 */
2173 tm->tm_sec << 20 | /* 6 */
2174 tobj->ts.tv_nsec / 1000; /* 20 */
2175 nsec = tobj->ts.tv_nsec % 1000;
2177 for (i=0; i<4; i++) {
2178 buf[i] = p & 0xff;
2179 p = RSHIFT(p, 8);
2181 for (i=4; i<8; i++) {
2182 buf[i] = s & 0xff;
2183 s = RSHIFT(s, 8);
2186 str = rb_str_new(buf, 8);
2187 rb_copy_generic_ivar(str, time);
2188 if (nsec) {
2190 * submicro is formatted in fixed-point packed BCD (without sign).
2191 * It represent digits under microsecond.
2192 * For nanosecond resolution, 3 digits (2 bytes) are used.
2193 * However it can be longer.
2194 * Extra digits are ignored for loading.
2196 unsigned char buf[2];
2197 int len = sizeof(buf);
2198 buf[1] = (nsec % 10) << 4;
2199 nsec /= 10;
2200 buf[0] = nsec % 10;
2201 nsec /= 10;
2202 buf[0] |= (nsec % 10) << 4;
2203 if (buf[1] == 0)
2204 len = 1;
2205 rb_ivar_set(str, id_submicro, rb_str_new((char *)buf, len));
2207 return str;
2211 * call-seq:
2212 * time._dump => string
2214 * Dump _time_ for marshaling.
2217 static VALUE
2218 time_dump(int argc, VALUE *argv, VALUE time)
2220 VALUE str;
2222 rb_scan_args(argc, argv, "01", 0);
2223 str = time_mdump(time);
2225 return str;
2229 * undocumented
2232 static VALUE
2233 time_mload(VALUE time, VALUE str)
2235 struct time_object *tobj;
2236 unsigned long p, s;
2237 time_t sec;
2238 long usec;
2239 unsigned char *buf;
2240 struct tm tm;
2241 int i, gmt;
2242 long nsec;
2243 VALUE submicro;
2245 time_modify(time);
2247 submicro = rb_attr_get(str, id_submicro);
2248 if (submicro != Qnil) {
2249 st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_submicro, 0);
2251 rb_copy_generic_ivar(time, str);
2253 StringValue(str);
2254 buf = (unsigned char *)RSTRING_PTR(str);
2255 if (RSTRING_LEN(str) != 8) {
2256 rb_raise(rb_eTypeError, "marshaled time format differ");
2259 p = s = 0;
2260 for (i=0; i<4; i++) {
2261 p |= buf[i]<<(8*i);
2263 for (i=4; i<8; i++) {
2264 s |= buf[i]<<(8*(i-4));
2267 if ((p & (1UL<<31)) == 0) {
2268 gmt = 0;
2269 sec = p;
2270 usec = s;
2271 nsec = usec * 1000;
2273 else {
2274 p &= ~(1UL<<31);
2275 gmt = (p >> 30) & 0x1;
2276 tm.tm_year = (p >> 14) & 0xffff;
2277 tm.tm_mon = (p >> 10) & 0xf;
2278 tm.tm_mday = (p >> 5) & 0x1f;
2279 tm.tm_hour = p & 0x1f;
2280 tm.tm_min = (s >> 26) & 0x3f;
2281 tm.tm_sec = (s >> 20) & 0x3f;
2282 tm.tm_isdst = 0;
2284 sec = make_time_t(&tm, Qtrue);
2285 usec = (long)(s & 0xfffff);
2286 nsec = usec * 1000;
2288 if (submicro != Qnil) {
2289 unsigned char *ptr;
2290 long len;
2291 int digit;
2292 ptr = (unsigned char*)StringValuePtr(submicro);
2293 len = RSTRING_LEN(submicro);
2294 if (0 < len) {
2295 if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
2296 nsec += digit * 100;
2297 if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
2298 nsec += digit * 10;
2300 if (1 < len) {
2301 if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
2302 nsec += digit;
2304 end_submicro: ;
2307 time_overflow_p(&sec, &nsec);
2309 GetTimeval(time, tobj);
2310 tobj->tm_got = 0;
2311 tobj->gmt = gmt;
2312 tobj->ts.tv_sec = sec;
2313 tobj->ts.tv_nsec = nsec;
2315 return time;
2319 * call-seq:
2320 * Time._load(string) => time
2322 * Unmarshal a dumped +Time+ object.
2325 static VALUE
2326 time_load(VALUE klass, VALUE str)
2328 VALUE time = time_s_alloc(klass);
2330 time_mload(time, str);
2331 return time;
2335 * <code>Time</code> is an abstraction of dates and times. Time is
2336 * stored internally as the number of seconds and nanoseconds since
2337 * the <em>Epoch</em>, January 1, 1970 00:00 UTC. On some operating
2338 * systems, this offset is allowed to be negative. Also see the
2339 * library modules <code>Date</code>. The
2340 * <code>Time</code> class treats GMT (Greenwich Mean Time) and UTC
2341 * (Coordinated Universal Time)<em>[Yes, UTC really does stand for
2342 * Coordinated Universal Time. There was a committee involved.]</em>
2343 * as equivalent. GMT is the older way of referring to these
2344 * baseline times but persists in the names of calls on POSIX
2345 * systems.
2347 * All times are stored with some number of nanoseconds. Be aware of
2348 * this fact when comparing times with each other---times that are
2349 * apparently equal when displayed may be different when compared.
2352 void
2353 Init_Time(void)
2355 #undef rb_intern
2356 #define rb_intern(str) rb_intern_const(str)
2358 id_divmod = rb_intern("divmod");
2359 id_mul = rb_intern("*");
2360 id_submicro = rb_intern("submicro");
2362 rb_cTime = rb_define_class("Time", rb_cObject);
2363 rb_include_module(rb_cTime, rb_mComparable);
2365 rb_define_alloc_func(rb_cTime, time_s_alloc);
2366 rb_define_singleton_method(rb_cTime, "now", rb_class_new_instance, -1);
2367 rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
2368 rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
2369 rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
2370 rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
2371 rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
2373 rb_define_method(rb_cTime, "to_i", time_to_i, 0);
2374 rb_define_method(rb_cTime, "to_f", time_to_f, 0);
2375 rb_define_method(rb_cTime, "<=>", time_cmp, 1);
2376 rb_define_method(rb_cTime, "eql?", time_eql, 1);
2377 rb_define_method(rb_cTime, "hash", time_hash, 0);
2378 rb_define_method(rb_cTime, "initialize", time_init, 0);
2379 rb_define_method(rb_cTime, "initialize_copy", time_init_copy, 1);
2381 rb_define_method(rb_cTime, "localtime", time_localtime, 0);
2382 rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
2383 rb_define_method(rb_cTime, "utc", time_gmtime, 0);
2384 rb_define_method(rb_cTime, "getlocal", time_getlocaltime, 0);
2385 rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
2386 rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
2388 rb_define_method(rb_cTime, "ctime", time_asctime, 0);
2389 rb_define_method(rb_cTime, "asctime", time_asctime, 0);
2390 rb_define_method(rb_cTime, "to_s", time_to_s, 0);
2391 rb_define_method(rb_cTime, "inspect", time_to_s, 0);
2392 rb_define_method(rb_cTime, "to_a", time_to_a, 0);
2394 rb_define_method(rb_cTime, "+", time_plus, 1);
2395 rb_define_method(rb_cTime, "-", time_minus, 1);
2397 rb_define_method(rb_cTime, "succ", time_succ, 0);
2398 rb_define_method(rb_cTime, "sec", time_sec, 0);
2399 rb_define_method(rb_cTime, "min", time_min, 0);
2400 rb_define_method(rb_cTime, "hour", time_hour, 0);
2401 rb_define_method(rb_cTime, "mday", time_mday, 0);
2402 rb_define_method(rb_cTime, "day", time_mday, 0);
2403 rb_define_method(rb_cTime, "mon", time_mon, 0);
2404 rb_define_method(rb_cTime, "month", time_mon, 0);
2405 rb_define_method(rb_cTime, "year", time_year, 0);
2406 rb_define_method(rb_cTime, "wday", time_wday, 0);
2407 rb_define_method(rb_cTime, "yday", time_yday, 0);
2408 rb_define_method(rb_cTime, "isdst", time_isdst, 0);
2409 rb_define_method(rb_cTime, "dst?", time_isdst, 0);
2410 rb_define_method(rb_cTime, "zone", time_zone, 0);
2411 rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
2412 rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
2413 rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
2415 rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
2416 rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
2418 rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
2419 rb_define_method(rb_cTime, "monday?", time_monday, 0);
2420 rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
2421 rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
2422 rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
2423 rb_define_method(rb_cTime, "friday?", time_friday, 0);
2424 rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
2426 rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
2427 rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
2428 rb_define_method(rb_cTime, "usec", time_usec, 0);
2429 rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
2430 rb_define_method(rb_cTime, "nsec", time_nsec, 0);
2432 rb_define_method(rb_cTime, "strftime", time_strftime, 1);
2434 /* methods for marshaling */
2435 rb_define_method(rb_cTime, "_dump", time_dump, -1);
2436 rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
2437 #if 0
2438 /* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
2439 rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0);
2440 rb_define_method(rb_cTime, "marshal_load", time_mload, 1);
2441 #endif