1 /**********************************************************************
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>
16 #include "ruby/encoding.h"
25 static VALUE time_utc_offset
_((VALUE
));
27 static ID id_divmod
, id_mul
, id_submicro
;
36 #define GetTimeval(obj, tobj) \
37 Data_Get_Struct(obj, struct time_object, tobj)
42 if (tobj
) xfree(tobj
);
46 time_s_alloc(VALUE klass
)
49 struct time_object
*tobj
;
51 obj
= Data_Make_Struct(klass
, struct time_object
, 0, time_free
, tobj
);
60 time_modify(VALUE time
)
62 rb_check_frozen(time
);
63 if (!OBJ_TAINTED(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.
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
83 * a = Time.new #=> 2007-11-19 07:50:02 -0600
84 * b = Time.new #=> 2007-11-19 07:50:02 -0600
86 * "%.6f" % a.to_f #=> "1195480202.282373"
87 * "%.6f" % b.to_f #=> "1195480202.283415"
94 struct time_object
*tobj
;
97 GetTimeval(time
, tobj
);
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");
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;
119 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
120 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
123 time_overflow_p(time_t *secp
, long *nsecp
)
125 time_t tmp
, sec
= *secp
;
128 if (nsec
>= 1000000000) { /* nsec positive overflow */
129 tmp
= sec
+ nsec
/ 1000000000;
131 if (sec
> 0 && tmp
< 0) {
132 rb_raise(rb_eRangeError
, "out of Time range");
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");
144 #ifndef NEGATIVE_TIME_T
146 rb_raise(rb_eArgError
, "time must be positive");
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
;
167 rb_time_new(time_t sec
, long usec
)
169 return time_new_internal(rb_cTime
, sec
, usec
* 1000);
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
)
182 const char *tstr
= interval
? "time interval" : "time";
185 #ifndef NEGATIVE_TIME_T
191 t
.tv_sec
= FIX2LONG(num
);
192 if (interval
&& t
.tv_sec
< 0)
193 rb_raise(rb_eArgError
, "%s must be positive", tstr
);
198 if (interval
&& RFLOAT_VALUE(num
) < 0.0)
199 rb_raise(rb_eArgError
, "%s must be positive", tstr
);
203 d
= modf(RFLOAT_VALUE(num
), &f
);
208 t
.tv_sec
= (time_t)f
;
210 rb_raise(rb_eRangeError
, "%f out of Time range", RFLOAT_VALUE(num
));
212 t
.tv_nsec
= (long)(d
*1e9
+0.5);
217 t
.tv_sec
= NUM2LONG(num
);
218 if (interval
&& t
.tv_sec
< 0)
219 rb_raise(rb_eArgError
, "%s must be positive", tstr
);
224 if (rb_respond_to(num
, id_divmod
)) {
225 ary
= rb_check_array_type(rb_funcall(num
, id_divmod
, 1, INT2FIX(1)));
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
);
239 rb_raise(rb_eTypeError
, "can't convert %s into %s",
240 rb_obj_classname(num
), tstr
);
247 static struct timeval
248 time_timeval(VALUE num
, int interval
)
253 ts
= time_timespec(num
, interval
);
254 tv
.tv_sec
= ts
.tv_sec
;
255 tv
.tv_usec
= ts
.tv_nsec
/ 1000;
261 rb_time_interval(VALUE num
)
263 return time_timeval(num
, Qtrue
);
267 rb_time_timeval(VALUE time
)
269 struct time_object
*tobj
;
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;
278 return time_timeval(time
, Qfalse
);
282 rb_time_timespec(VALUE time
)
284 struct time_object
*tobj
;
287 if (TYPE(time
) == T_DATA
&& RDATA(time
)->dfree
== time_free
) {
288 GetTimeval(time
, tobj
);
292 return time_timespec(time
, Qfalse
);
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
317 time_s_at(int argc
, VALUE
*argv
, VALUE klass
)
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)));
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
;
340 static const char months
[][4] = {
341 "jan", "feb", "mar", "apr", "may", "jun",
342 "jul", "aug", "sep", "oct", "nov", "dec",
348 if (TYPE(obj
) == T_STRING
) {
349 obj
= rb_str_to_inum(obj
, 10, Qfalse
);
352 return NUM2LONG(obj
);
356 obj2nsec(VALUE obj
, long *nsec
)
360 if (TYPE(obj
) == T_STRING
) {
361 obj
= rb_str_to_inum(obj
, 10, Qfalse
);
363 return NUM2LONG(obj
);
366 ts
= time_timespec(obj
, 1);
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)));
383 time_arg(int argc
, VALUE
*argv
, struct tm
*tm
, long *nsec
)
389 MEMZERO(tm
, struct tm
, 1);
399 tm
->tm_isdst
= RTEST(argv
[8]) ? 1 : 0;
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) */
409 year
= obj2long(v
[0]);
411 if (0 <= year
&& year
< 39) {
412 rb_warning("2 digits year is used: %ld", year
);
415 else if (69 <= year
&& year
< 139) {
416 rb_warning("2 or 3 digits year is used: %ld", year
);
428 VALUE s
= rb_check_string_type(v
[1]);
431 for (i
=0; i
<12; i
++) {
432 if (RSTRING_LEN(s
) == 3 &&
433 STRCASECMP(months
[i
], RSTRING_PTR(s
)) == 0) {
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;
447 tm
->tm_mon
= obj2long(v
[1])-1;
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]);
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 */
469 tm
->tm_year
!= year
||
470 #ifndef NEGATIVE_TIME_T
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);
489 return ((y
% 4 == 0) && (y
% 100 != 0)) || (y
% 400 == 0);
492 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
495 timegm_noleapsecond(struct tm
*tm
)
497 static const int common_year_yday_offset
[] = {
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
[] = {
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
];
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 +
546 DIV(tm_year
+299,400))*86400;
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;
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
;
575 # error cannot find integer type which size is same as 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
;
586 find_dst
= 0 < tptr
->tm_isdst
;
588 #ifdef NEGATIVE_TIME_T
589 guess_lo
= (time_t)~((unsigned_time_t
)~(time_t)0 >> 1);
593 guess_hi
= ((time_t)-1) < ((time_t)0) ?
594 (time_t)((unsigned_time_t
)~(time_t)0 >> 1) :
597 guess
= timegm_noleapsecond(tptr
);
598 tm
= (utc_p
? gmtime
: localtime
)(&guess
);
601 if (d
== 0) return guess
;
604 guess
-= 24 * 60 * 60;
608 guess
+= 24 * 60 * 60;
610 if (guess_lo
< guess
&& guess
< guess_hi
&&
611 (tm
= (utc_p
? gmtime
: localtime
)(&guess
)) != NULL
) {
613 if (d
== 0) return guess
;
621 tm
= (utc_p
? gmtime
: localtime
)(&guess_lo
);
624 if (d
< 0) goto out_of_range
;
625 if (d
== 0) return guess_lo
;
628 tm
= (utc_p
? gmtime
: localtime
)(&guess_hi
);
631 if (d
> 0) goto out_of_range
;
632 if (d
== 0) return guess_hi
;
637 while (guess_lo
+ 1 < guess_hi
) {
638 /* there is a gap between guess_lo and guess_hi. */
639 unsigned long range
= 0;
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
651 guess = guess_lo / d * a + (guess_lo % d) * a / d
652 + guess_hi / d * b + (guess_hi % d) * b / d
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
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;
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;
677 a
+= tm_hi
.tm_mday
- tptr
->tm_mday
;
678 b
+= tptr
->tm_mday
- tm_lo
.tm_mday
;
679 if (a
+ b
<= 46000 / 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) {
689 a
+= tm_hi
.tm_min
- tptr
->tm_min
;
690 b
+= tptr
->tm_min
- tm_lo
.tm_min
;
691 if (a
+ b
<= 46000 / 60) {
695 a
+= tm_hi
.tm_sec
- tptr
->tm_sec
;
696 b
+= tptr
->tm_sec
- tm_lo
.tm_sec
;
706 Although `/' and `%' may produce unexpected result with negative
707 argument, it doesn't cause serious problem because there is a
710 guess
= guess_lo
/ d
* a
+ (guess_lo
% d
) * a
/ d
711 + guess_hi
/ d
* b
+ (guess_hi
% d
) * b
/ d
;
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;
725 tm
= (utc_p
? gmtime
: localtime
)(&guess
);
734 guess
= guess
- range
;
736 if (guess_lo
< guess
&& guess
< guess_hi
)
744 guess
= guess
+ range
;
746 if (guess_lo
< guess
&& guess
< guess_hi
)
752 /* If localtime is nonmonotonic, another result may exist. */
755 guess2
= guess
- 2 * 60 * 60;
756 tm
= localtime(&guess2
);
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) {
780 guess2
= guess
+ 2 * 60 * 60;
781 tm
= localtime(&guess2
);
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) {
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
) {
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
) {
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
);
825 rb_raise(rb_eArgError
, "time out of range");
828 rb_raise(rb_eArgError
, "gmtime/localtime error");
829 return 0; /* not reached */
833 make_time_t(struct tm
*tptr
, int utc_p
)
836 #ifdef NEGATIVE_TIME_T
842 #if defined(HAVE_TIMEGM)
843 if ((t
= timegm(&buf
)) != -1)
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
857 return search_time_t(&buf
, utc_p
);
860 #if defined(HAVE_MKTIME)
861 if ((t
= mktime(&buf
)) != -1)
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
875 return search_time_t(&buf
, utc_p
);
880 time_utc_or_local(int argc
, VALUE
*argv
, int utc_p
, VALUE klass
)
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
);
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
925 time_s_mkutc(int argc
, VALUE
*argv
, VALUE klass
)
927 return time_utc_or_local(argc
, argv
, Qtrue
, klass
);
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
952 * Time.local(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 -0600
956 time_s_mktime(int argc
, VALUE
*argv
, VALUE klass
)
958 return time_utc_or_local(argc
, argv
, Qfalse
, klass
);
966 * Returns the value of <i>time</i> as an integer number of seconds
970 * "%10.5f" % t.to_f #=> "1049896564.17839"
971 * t.to_i #=> 1049896564
975 time_to_i(VALUE time
)
977 struct time_object
*tobj
;
979 GetTimeval(time
, tobj
);
980 return LONG2NUM(tobj
->ts
.tv_sec
);
987 * Returns the value of <i>time</i> as a floating point number of
988 * seconds since the Epoch.
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.
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
);
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"
1020 time_usec(VALUE time
)
1022 struct time_object
*tobj
;
1024 GetTimeval(time
, tobj
);
1025 return LONG2NUM(tobj
->ts
.tv_nsec
/1000);
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.
1046 time_nsec(VALUE time
)
1048 struct time_object
*tobj
;
1050 GetTimeval(time
, tobj
);
1051 return LONG2NUM(tobj
->ts
.tv_nsec
);
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
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
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);
1087 if (tobj1
->ts
.tv_sec
> tobj2
->ts
.tv_sec
) return INT2FIX(1);
1096 * time.eql?(other_time)
1098 * Return <code>true</code> if <i>time</i> and <i>other_time</i> are
1099 * both <code>Time</code> objects with the same seconds and fractional
1104 time_eql(VALUE time1
, VALUE time2
)
1106 struct time_object
*tobj1
, *tobj2
;
1108 GetTimeval(time1
, tobj1
);
1109 if (TYPE(time2
) == T_DATA
&& RDATA(time2
)->dfree
== time_free
) {
1110 GetTimeval(time2
, tobj2
);
1111 if (tobj1
->ts
.tv_sec
== tobj2
->ts
.tv_sec
) {
1112 if (tobj1
->ts
.tv_nsec
== tobj2
->ts
.tv_nsec
) return Qtrue
;
1120 * time.utc? => true or false
1121 * time.gmt? => true or false
1123 * Returns <code>true</code> if <i>time</i> represents a time in UTC
1126 * t = Time.now #=> 2007-11-19 08:15:23 -0600
1128 * t = Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1131 * t = Time.now #=> 2007-11-19 08:16:03 -0600
1133 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1138 time_utc_p(VALUE time
)
1140 struct time_object
*tobj
;
1142 GetTimeval(time
, tobj
);
1143 if (tobj
->gmt
) return Qtrue
;
1149 * time.hash => fixnum
1151 * Return a hash code for this time object.
1155 time_hash(VALUE time
)
1157 struct time_object
*tobj
;
1160 GetTimeval(time
, tobj
);
1161 hash
= tobj
->ts
.tv_sec
^ tobj
->ts
.tv_nsec
;
1162 return LONG2FIX(hash
);
1167 time_init_copy(VALUE copy
, VALUE time
)
1169 struct time_object
*tobj
, *tcopy
;
1171 if (copy
== time
) return copy
;
1173 if (TYPE(time
) != T_DATA
|| RDATA(time
)->dfree
!= time_free
) {
1174 rb_raise(rb_eTypeError
, "wrong argument type");
1176 GetTimeval(time
, tobj
);
1177 GetTimeval(copy
, tcopy
);
1178 MEMCPY(tcopy
, tobj
, struct time_object
, 1);
1184 time_dup(VALUE time
)
1186 VALUE dup
= time_s_alloc(CLASS_OF(time
));
1187 time_init_copy(dup
, time
);
1193 * time.localtime => time
1195 * Converts <i>time</i> to local time (using the local time zone in
1196 * effect for this process) modifying the receiver.
1198 * t = Time.gm(2000, "jan", 1, 20, 15, 1) #=> 2000-01-01 20:15:01 UTC
1200 * t.localtime #=> 2000-01-01 14:15:01 -0600
1205 time_localtime(VALUE time
)
1207 struct time_object
*tobj
;
1211 GetTimeval(time
, tobj
);
1219 t
= tobj
->ts
.tv_sec
;
1220 tm_tmp
= localtime(&t
);
1222 rb_raise(rb_eArgError
, "localtime error");
1231 * time.gmtime => time
1234 * Converts <i>time</i> to UTC (GMT), modifying the receiver.
1236 * t = Time.now #=> 2007-11-19 08:18:31 -0600
1238 * t.gmtime #=> 2007-11-19 14:18:31 UTC
1241 * t = Time.now #=> 2007-11-19 08:18:51 -0600
1243 * t.utc #=> 2007-11-19 14:18:51 UTC
1248 time_gmtime(VALUE time
)
1250 struct time_object
*tobj
;
1254 GetTimeval(time
, tobj
);
1262 t
= tobj
->ts
.tv_sec
;
1263 tm_tmp
= gmtime(&t
);
1265 rb_raise(rb_eArgError
, "gmtime error");
1274 * time.getlocal => new_time
1276 * Returns a new <code>new_time</code> object representing <i>time</i> in
1277 * local time (using the local time zone in effect for this process).
1279 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1281 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
1287 time_getlocaltime(VALUE time
)
1289 return time_localtime(time_dup(time
));
1294 * time.getgm => new_time
1295 * time.getutc => new_time
1297 * Returns a new <code>new_time</code> object representing <i>time</i> in
1300 * t = Time.local(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 -0600
1302 * y = t.getgm #=> 2000-01-02 02:15:01 UTC
1308 time_getgmtime(VALUE time
)
1310 return time_gmtime(time_dup(time
));
1314 time_get_tm(VALUE time
, int gmt
)
1316 if (gmt
) return time_gmtime(time
);
1317 return time_localtime(time
);
1322 * time.asctime => string
1323 * time.ctime => string
1325 * Returns a canonical string representation of <i>time</i>.
1327 * Time.now.asctime #=> "Wed Apr 9 08:56:03 2003"
1331 time_asctime(VALUE time
)
1333 struct time_object
*tobj
;
1336 GetTimeval(time
, tobj
);
1337 if (tobj
->tm_got
== 0) {
1338 time_get_tm(time
, tobj
->gmt
);
1340 s
= asctime(&tobj
->tm
);
1341 if (s
[24] == '\n') s
[24] = '\0';
1343 return rb_str_new2(s
);
1348 * time.inspect => string
1349 * time.to_s => string
1351 * Returns a string representing <i>time</i>. Equivalent to calling
1352 * <code>Time#strftime</code> with a format string of
1353 * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>%z</code>''
1354 * for a local time and
1355 * ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>UTC</code>''
1358 * Time.now.to_s #=> "2007-10-05 16:09:51 +0900"
1359 * Time.now.utc.to_s #=> "2007-10-05 07:09:51 UTC"
1363 time_to_s(VALUE time
)
1365 struct time_object
*tobj
;
1369 GetTimeval(time
, tobj
);
1370 if (tobj
->tm_got
== 0) {
1371 time_get_tm(time
, tobj
->gmt
);
1373 if (tobj
->gmt
== 1) {
1374 len
= strftime(buf
, 128, "%Y-%m-%d %H:%M:%S UTC", &tobj
->tm
);
1379 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1380 off
= tobj
->tm
.tm_gmtoff
;
1382 VALUE tmp
= time_utc_offset(time
);
1389 len
= strftime(buf
, sizeof(buf
), "%Y-%m-%d %H:%M:%S ", &tobj
->tm
);
1390 len
+= snprintf(buf
+len
, sizeof(buf
)-len
, "%c%02d%02d", sign
,
1391 (int)(off
/3600), (int)(off
%3600/60));
1393 return rb_str_new(buf
, len
);
1397 time_add(struct time_object
*tobj
, VALUE offset
, int sign
)
1399 double v
= NUM2DBL(offset
);
1401 unsigned_time_t sec_off
;
1403 long nsec_off
, nsec
;
1411 sec_off
= (unsigned_time_t
)f
;
1412 if (f
!= (double)sec_off
)
1413 rb_raise(rb_eRangeError
, "time %s %f out of Time range",
1414 sign
< 0 ? "-" : "+", v
);
1415 nsec_off
= (long)(d
*1e9
+0.5);
1418 sec
= tobj
->ts
.tv_sec
- sec_off
;
1419 nsec
= tobj
->ts
.tv_nsec
- nsec_off
;
1420 if (sec
> tobj
->ts
.tv_sec
)
1421 rb_raise(rb_eRangeError
, "time - %f out of Time range", v
);
1424 sec
= tobj
->ts
.tv_sec
+ sec_off
;
1425 nsec
= tobj
->ts
.tv_nsec
+ nsec_off
;
1426 if (sec
< tobj
->ts
.tv_sec
)
1427 rb_raise(rb_eRangeError
, "time + %f out of Time range", v
);
1429 result
= rb_time_nano_new(sec
, nsec
);
1431 GetTimeval(result
, tobj
);
1439 * time + numeric => time
1441 * Addition---Adds some number of seconds (possibly fractional) to
1442 * <i>time</i> and returns that value as a new time.
1444 * t = Time.now #=> 2007-11-19 08:22:21 -0600
1445 * t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
1449 time_plus(VALUE time1
, VALUE time2
)
1451 struct time_object
*tobj
;
1452 GetTimeval(time1
, tobj
);
1454 if (TYPE(time2
) == T_DATA
&& RDATA(time2
)->dfree
== time_free
) {
1455 rb_raise(rb_eTypeError
, "time + time?");
1457 return time_add(tobj
, time2
, 1);
1462 * time - other_time => float
1463 * time - numeric => time
1465 * Difference---Returns a new time that represents the difference
1466 * between two times, or subtracts the given number of seconds in
1467 * <i>numeric</i> from <i>time</i>.
1469 * t = Time.now #=> 2007-11-19 08:23:10 -0600
1470 * t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
1471 * t2 - t #=> 2592000.0
1472 * t2 - 2592000 #=> 2007-11-19 08:23:10 -0600
1476 time_minus(VALUE time1
, VALUE time2
)
1478 struct time_object
*tobj
;
1480 GetTimeval(time1
, tobj
);
1481 if (TYPE(time2
) == T_DATA
&& RDATA(time2
)->dfree
== time_free
) {
1482 struct time_object
*tobj2
;
1485 GetTimeval(time2
, tobj2
);
1486 if (tobj
->ts
.tv_sec
< tobj2
->ts
.tv_sec
)
1487 f
= -(double)(unsigned_time_t
)(tobj2
->ts
.tv_sec
- tobj
->ts
.tv_sec
);
1489 f
= (double)(unsigned_time_t
)(tobj
->ts
.tv_sec
- tobj2
->ts
.tv_sec
);
1490 f
+= ((double)tobj
->ts
.tv_nsec
- (double)tobj2
->ts
.tv_nsec
)*1e-9;
1492 return DOUBLE2NUM(f
);
1494 return time_add(tobj
, time2
, -1);
1499 * time.succ => new_time
1501 * Return a new time object, one second later than <code>time</code>.
1503 * t = Time.now #=> 2007-11-19 08:23:57 -0600
1504 * t.succ #=> 2007-11-19 08:23:58 -0600
1508 time_succ(VALUE time
)
1510 struct time_object
*tobj
;
1513 GetTimeval(time
, tobj
);
1515 time
= rb_time_nano_new(tobj
->ts
.tv_sec
+ 1, tobj
->ts
.tv_nsec
);
1516 GetTimeval(time
, tobj
);
1522 rb_time_succ(VALUE time
)
1524 return time_succ(time
);
1529 * time.sec => fixnum
1531 * Returns the second of the minute (0..60)<em>[Yes, seconds really can
1532 * range from zero to 60. This allows the system to inject leap seconds
1533 * every now and then to correct for the fact that years are not really
1534 * a convenient number of hours long.]</em> for <i>time</i>.
1536 * t = Time.now #=> 2007-11-19 08:25:02 -0600
1541 time_sec(VALUE time
)
1543 struct time_object
*tobj
;
1545 GetTimeval(time
, tobj
);
1546 if (tobj
->tm_got
== 0) {
1547 time_get_tm(time
, tobj
->gmt
);
1549 return INT2FIX(tobj
->tm
.tm_sec
);
1554 * time.min => fixnum
1556 * Returns the minute of the hour (0..59) for <i>time</i>.
1558 * t = Time.now #=> 2007-11-19 08:25:51 -0600
1563 time_min(VALUE time
)
1565 struct time_object
*tobj
;
1567 GetTimeval(time
, tobj
);
1568 if (tobj
->tm_got
== 0) {
1569 time_get_tm(time
, tobj
->gmt
);
1571 return INT2FIX(tobj
->tm
.tm_min
);
1576 * time.hour => fixnum
1578 * Returns the hour of the day (0..23) for <i>time</i>.
1580 * t = Time.now #=> 2007-11-19 08:26:20 -0600
1585 time_hour(VALUE time
)
1587 struct time_object
*tobj
;
1589 GetTimeval(time
, tobj
);
1590 if (tobj
->tm_got
== 0) {
1591 time_get_tm(time
, tobj
->gmt
);
1593 return INT2FIX(tobj
->tm
.tm_hour
);
1598 * time.day => fixnum
1599 * time.mday => fixnum
1601 * Returns the day of the month (1..n) for <i>time</i>.
1603 * t = Time.now #=> 2007-11-19 08:27:03 -0600
1609 time_mday(VALUE time
)
1611 struct time_object
*tobj
;
1613 GetTimeval(time
, tobj
);
1614 if (tobj
->tm_got
== 0) {
1615 time_get_tm(time
, tobj
->gmt
);
1617 return INT2FIX(tobj
->tm
.tm_mday
);
1622 * time.mon => fixnum
1623 * time.month => fixnum
1625 * Returns the month of the year (1..12) for <i>time</i>.
1627 * t = Time.now #=> 2007-11-19 08:27:30 -0600
1633 time_mon(VALUE time
)
1635 struct time_object
*tobj
;
1637 GetTimeval(time
, tobj
);
1638 if (tobj
->tm_got
== 0) {
1639 time_get_tm(time
, tobj
->gmt
);
1641 return INT2FIX(tobj
->tm
.tm_mon
+1);
1646 * time.year => fixnum
1648 * Returns the year for <i>time</i> (including the century).
1650 * t = Time.now #=> 2007-11-19 08:27:51 -0600
1655 time_year(VALUE time
)
1657 struct time_object
*tobj
;
1659 GetTimeval(time
, tobj
);
1660 if (tobj
->tm_got
== 0) {
1661 time_get_tm(time
, tobj
->gmt
);
1663 return LONG2NUM((long)tobj
->tm
.tm_year
+1900);
1668 * time.wday => fixnum
1670 * Returns an integer representing the day of the week, 0..6, with
1673 * t = Time.now #=> 2007-11-20 02:35:35 -0600
1675 * t.sunday? #=> false
1676 * t.monday? #=> false
1677 * t.tuesday? #=> true
1678 * t.wednesday? #=> false
1679 * t.thursday? #=> false
1680 * t.friday? #=> false
1681 * t.saturday? #=> false
1685 time_wday(VALUE time
)
1687 struct time_object
*tobj
;
1689 GetTimeval(time
, tobj
);
1690 if (tobj
->tm_got
== 0) {
1691 time_get_tm(time
, tobj
->gmt
);
1693 return INT2FIX(tobj
->tm
.tm_wday
);
1696 #define wday_p(n) {\
1697 struct time_object *tobj;\
1698 GetTimeval(time, tobj);\
1699 if (tobj->tm_got == 0) {\
1700 time_get_tm(time, tobj->gmt);\
1702 return (tobj->tm.tm_wday == (n)) ? Qtrue : Qfalse;\
1707 * time.sunday? => true or false
1709 * Returns <code>true</code> if <i>time</i> represents Sunday.
1711 * t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
1712 * t.sunday? #=> true
1716 time_sunday(VALUE time
)
1723 * time.monday? => true or false
1725 * Returns <code>true</code> if <i>time</i> represents Monday.
1727 * t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
1728 * p t.monday? #=> true
1732 time_monday(VALUE time
)
1739 * time.tuesday? => true or false
1741 * Returns <code>true</code> if <i>time</i> represents Tuesday.
1743 * t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
1744 * p t.tuesday? #=> true
1748 time_tuesday(VALUE time
)
1755 * time.wednesday? => true or false
1757 * Returns <code>true</code> if <i>time</i> represents Wednesday.
1759 * t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
1760 * p t.wednesday? #=> true
1764 time_wednesday(VALUE time
)
1771 * time.thursday? => true or false
1773 * Returns <code>true</code> if <i>time</i> represents Thursday.
1775 * t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
1776 * p t.thursday? #=> true
1780 time_thursday(VALUE time
)
1787 * time.friday? => true or false
1789 * Returns <code>true</code> if <i>time</i> represents Friday.
1791 * t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
1792 * t.friday? #=> true
1796 time_friday(VALUE time
)
1803 * time.saturday? => true or false
1805 * Returns <code>true</code> if <i>time</i> represents Saturday.
1807 * t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
1808 * t.saturday? #=> true
1812 time_saturday(VALUE time
)
1819 * time.yday => fixnum
1821 * Returns an integer representing the day of the year, 1..366.
1823 * t = Time.now #=> 2007-11-19 08:32:31 -0600
1828 time_yday(VALUE time
)
1830 struct time_object
*tobj
;
1832 GetTimeval(time
, tobj
);
1833 if (tobj
->tm_got
== 0) {
1834 time_get_tm(time
, tobj
->gmt
);
1836 return INT2FIX(tobj
->tm
.tm_yday
+1);
1841 * time.isdst => true or false
1842 * time.dst? => true or false
1844 * Returns <code>true</code> if <i>time</i> occurs during Daylight
1845 * Saving Time in its time zone.
1848 * Time.local(2000, 1, 1).zone #=> "CST"
1849 * Time.local(2000, 1, 1).isdst #=> false
1850 * Time.local(2000, 1, 1).dst? #=> false
1851 * Time.local(2000, 7, 1).zone #=> "CDT"
1852 * Time.local(2000, 7, 1).isdst #=> true
1853 * Time.local(2000, 7, 1).dst? #=> true
1856 * Time.local(2000, 1, 1).zone #=> "JST"
1857 * Time.local(2000, 1, 1).isdst #=> false
1858 * Time.local(2000, 1, 1).dst? #=> false
1859 * Time.local(2000, 7, 1).zone #=> "JST"
1860 * Time.local(2000, 7, 1).isdst #=> false
1861 * Time.local(2000, 7, 1).dst? #=> false
1865 time_isdst(VALUE time
)
1867 struct time_object
*tobj
;
1869 GetTimeval(time
, tobj
);
1870 if (tobj
->tm_got
== 0) {
1871 time_get_tm(time
, tobj
->gmt
);
1873 return tobj
->tm
.tm_isdst
?Qtrue
:Qfalse
;
1878 * time.zone => string
1880 * Returns the name of the time zone used for <i>time</i>. As of Ruby
1881 * 1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
1883 * t = Time.gm(2000, "jan", 1, 20, 15, 1)
1885 * t = Time.local(2000, "jan", 1, 20, 15, 1)
1890 time_zone(VALUE time
)
1892 struct time_object
*tobj
;
1893 #if !defined(HAVE_TM_ZONE) && (!defined(HAVE_TZNAME) || !defined(HAVE_DAYLIGHT))
1898 GetTimeval(time
, tobj
);
1899 if (tobj
->tm_got
== 0) {
1900 time_get_tm(time
, tobj
->gmt
);
1903 if (tobj
->gmt
== 1) {
1904 return rb_str_new2("UTC");
1906 #if defined(HAVE_TM_ZONE)
1907 return rb_str_new2(tobj
->tm
.tm_zone
);
1908 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1909 return rb_str_new2(tzname
[daylight
&& tobj
->tm
.tm_isdst
]);
1911 len
= strftime(buf
, 64, "%Z", &tobj
->tm
);
1912 return rb_str_new(buf
, len
);
1918 * time.gmt_offset => fixnum
1919 * time.gmtoff => fixnum
1920 * time.utc_offset => fixnum
1922 * Returns the offset in seconds between the timezone of <i>time</i>
1925 * t = Time.gm(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
1926 * t.gmt_offset #=> 0
1927 * l = t.getlocal #=> 2000-01-01 14:15:01 -0600
1928 * l.gmt_offset #=> -21600
1932 time_utc_offset(VALUE time
)
1934 struct time_object
*tobj
;
1936 GetTimeval(time
, tobj
);
1937 if (tobj
->tm_got
== 0) {
1938 time_get_tm(time
, tobj
->gmt
);
1941 if (tobj
->gmt
== 1) {
1945 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1946 return INT2NUM(tobj
->tm
.tm_gmtoff
);
1952 t
= tobj
->ts
.tv_sec
;
1955 rb_raise(rb_eArgError
, "gmtime error");
1956 if (l
->tm_year
!= u
->tm_year
)
1957 off
= l
->tm_year
< u
->tm_year
? -1 : 1;
1958 else if (l
->tm_mon
!= u
->tm_mon
)
1959 off
= l
->tm_mon
< u
->tm_mon
? -1 : 1;
1960 else if (l
->tm_mday
!= u
->tm_mday
)
1961 off
= l
->tm_mday
< u
->tm_mday
? -1 : 1;
1964 off
= off
* 24 + l
->tm_hour
- u
->tm_hour
;
1965 off
= off
* 60 + l
->tm_min
- u
->tm_min
;
1966 off
= off
* 60 + l
->tm_sec
- u
->tm_sec
;
1967 return LONG2FIX(off
);
1974 * time.to_a => array
1976 * Returns a ten-element <i>array</i> of values for <i>time</i>:
1977 * {<code>[ sec, min, hour, day, month, year, wday, yday, isdst, zone
1978 * ]</code>}. See the individual methods for an explanation of the
1979 * valid ranges of each value. The ten elements can be passed directly
1980 * to <code>Time::utc</code> or <code>Time::local</code> to create a
1981 * new <code>Time</code>.
1983 * t = Time.now #=> 2007-11-19 08:36:01 -0600
1984 * now = t.to_a #=> [1, 36, 8, 19, 11, 2007, 1, 323, false, "CST"]
1988 time_to_a(VALUE time
)
1990 struct time_object
*tobj
;
1992 GetTimeval(time
, tobj
);
1993 if (tobj
->tm_got
== 0) {
1994 time_get_tm(time
, tobj
->gmt
);
1996 return rb_ary_new3(10,
1997 INT2FIX(tobj
->tm
.tm_sec
),
1998 INT2FIX(tobj
->tm
.tm_min
),
1999 INT2FIX(tobj
->tm
.tm_hour
),
2000 INT2FIX(tobj
->tm
.tm_mday
),
2001 INT2FIX(tobj
->tm
.tm_mon
+1),
2002 LONG2NUM((long)tobj
->tm
.tm_year
+1900),
2003 INT2FIX(tobj
->tm
.tm_wday
),
2004 INT2FIX(tobj
->tm
.tm_yday
+1),
2005 tobj
->tm
.tm_isdst
?Qtrue
:Qfalse
,
2009 #define SMALLBUF 100
2011 rb_strftime(char **buf
, const char *format
, struct tm
*time
)
2013 int size
, len
, flen
;
2016 flen
= strlen(format
);
2021 len
= strftime(*buf
, SMALLBUF
, format
, time
);
2022 if (len
!= 0 || (**buf
== '\0' && errno
!= ERANGE
)) return len
;
2023 for (size
=1024; ; size
*=2) {
2024 *buf
= xmalloc(size
);
2026 len
= strftime(*buf
, size
, format
, time
);
2028 * buflen can be zero EITHER because there's not enough
2029 * room in the string, or because the control command
2030 * goes to the empty string. Make a reasonable guess that
2031 * if the buffer is 1024 times bigger than the length of the
2032 * format string, it's not failing for lack of room.
2034 if (len
> 0 || size
>= 1024 * flen
) return len
;
2042 * time.strftime( string ) => string
2044 * Formats <i>time</i> according to the directives in the given format
2045 * string. Any text not listed as a directive will be passed through
2046 * to the output string.
2049 * %a - The abbreviated weekday name (``Sun'')
2050 * %A - The full weekday name (``Sunday'')
2051 * %b - The abbreviated month name (``Jan'')
2052 * %B - The full month name (``January'')
2053 * %c - The preferred local date and time representation
2054 * %d - Day of the month (01..31)
2055 * %H - Hour of the day, 24-hour clock (00..23)
2056 * %I - Hour of the day, 12-hour clock (01..12)
2057 * %j - Day of the year (001..366)
2058 * %m - Month of the year (01..12)
2059 * %M - Minute of the hour (00..59)
2060 * %p - Meridian indicator (``AM'' or ``PM'')
2061 * %S - Second of the minute (00..60)
2062 * %U - Week number of the current year,
2063 * starting with the first Sunday as the first
2064 * day of the first week (00..53)
2065 * %W - Week number of the current year,
2066 * starting with the first Monday as the first
2067 * day of the first week (00..53)
2068 * %w - Day of the week (Sunday is 0, 0..6)
2069 * %x - Preferred representation for the date alone, no time
2070 * %X - Preferred representation for the time alone, no date
2071 * %y - Year without a century (00..99)
2072 * %Y - Year with century
2073 * %Z - Time zone name
2074 * %% - Literal ``%'' character
2076 * t = Time.now #=> 2007-11-19 08:37:48 -0600
2077 * t.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007"
2078 * t.strftime("at %I:%M%p") #=> "at 08:37AM"
2082 time_strftime(VALUE time
, VALUE format
)
2084 void rb_enc_copy(VALUE
, VALUE
);
2085 struct time_object
*tobj
;
2086 char buffer
[SMALLBUF
], *buf
= buffer
;
2091 GetTimeval(time
, tobj
);
2092 if (tobj
->tm_got
== 0) {
2093 time_get_tm(time
, tobj
->gmt
);
2095 StringValue(format
);
2096 if (!rb_enc_str_asciicompat_p(format
)) {
2097 rb_raise(rb_eArgError
, "format should have ASCII compatible encoding");
2099 format
= rb_str_new4(format
);
2100 fmt
= RSTRING_PTR(format
);
2101 len
= RSTRING_LEN(format
);
2103 rb_warning("strftime called with empty format string");
2105 else if (strlen(fmt
) < len
) {
2106 /* Ruby string may contain \0's. */
2107 const char *p
= fmt
, *pe
= fmt
+ len
;
2109 str
= rb_str_new(0, 0);
2111 len
= rb_strftime(&buf
, p
, &tobj
->tm
);
2112 rb_str_cat(str
, buf
, len
);
2114 if (buf
!= buffer
) {
2118 for (fmt
= p
; p
< pe
&& !*p
; ++p
);
2119 if (p
> fmt
) rb_str_cat(str
, fmt
, p
- fmt
);
2124 len
= rb_strftime(&buf
, RSTRING_PTR(format
), &tobj
->tm
);
2126 str
= rb_str_new(buf
, len
);
2127 if (buf
!= buffer
) xfree(buf
);
2128 rb_enc_copy(str
, format
);
2137 time_mdump(VALUE time
)
2139 struct time_object
*tobj
;
2148 GetTimeval(time
, tobj
);
2150 t
= tobj
->ts
.tv_sec
;
2153 if ((tm
->tm_year
& 0xffff) != tm
->tm_year
)
2154 rb_raise(rb_eArgError
, "year too big to marshal: %ld", (long)tm
->tm_year
);
2156 p
= 0x1UL
<< 31 | /* 1 */
2157 tobj
->gmt
<< 30 | /* 1 */
2158 tm
->tm_year
<< 14 | /* 16 */
2159 tm
->tm_mon
<< 10 | /* 4 */
2160 tm
->tm_mday
<< 5 | /* 5 */
2161 tm
->tm_hour
; /* 5 */
2162 s
= tm
->tm_min
<< 26 | /* 6 */
2163 tm
->tm_sec
<< 20 | /* 6 */
2164 tobj
->ts
.tv_nsec
/ 1000; /* 20 */
2165 nsec
= tobj
->ts
.tv_nsec
% 1000;
2167 for (i
=0; i
<4; i
++) {
2171 for (i
=4; i
<8; i
++) {
2176 str
= rb_str_new(buf
, 8);
2177 rb_copy_generic_ivar(str
, time
);
2180 * submicro is formatted in fixed-point packed BCD (without sign).
2181 * It represent digits under microsecond.
2182 * For nanosecond resolution, 3 digits (2 bytes) are used.
2183 * However it can be longer.
2184 * Extra digits are ignored for loading.
2186 unsigned char buf
[2];
2187 int len
= sizeof(buf
);
2188 buf
[1] = (nsec
% 10) << 4;
2192 buf
[0] |= (nsec
% 10) << 4;
2195 rb_ivar_set(str
, id_submicro
, rb_str_new((char *)buf
, len
));
2202 * time._dump => string
2204 * Dump _time_ for marshaling.
2208 time_dump(int argc
, VALUE
*argv
, VALUE time
)
2212 rb_scan_args(argc
, argv
, "01", 0);
2213 str
= time_mdump(time
);
2223 time_mload(VALUE time
, VALUE str
)
2225 struct time_object
*tobj
;
2237 submicro
= rb_attr_get(str
, id_submicro
);
2238 if (submicro
!= Qnil
) {
2239 st_delete(rb_generic_ivar_table(str
), (st_data_t
*)&id_submicro
, 0);
2241 rb_copy_generic_ivar(time
, str
);
2244 buf
= (unsigned char *)RSTRING_PTR(str
);
2245 if (RSTRING_LEN(str
) != 8) {
2246 rb_raise(rb_eTypeError
, "marshaled time format differ");
2250 for (i
=0; i
<4; i
++) {
2253 for (i
=4; i
<8; i
++) {
2254 s
|= buf
[i
]<<(8*(i
-4));
2257 if ((p
& (1UL<<31)) == 0) {
2265 gmt
= (p
>> 30) & 0x1;
2266 tm
.tm_year
= (p
>> 14) & 0xffff;
2267 tm
.tm_mon
= (p
>> 10) & 0xf;
2268 tm
.tm_mday
= (p
>> 5) & 0x1f;
2269 tm
.tm_hour
= p
& 0x1f;
2270 tm
.tm_min
= (s
>> 26) & 0x3f;
2271 tm
.tm_sec
= (s
>> 20) & 0x3f;
2274 sec
= make_time_t(&tm
, Qtrue
);
2275 usec
= (long)(s
& 0xfffff);
2278 if (submicro
!= Qnil
) {
2282 ptr
= (unsigned char*)StringValuePtr(submicro
);
2283 len
= RSTRING_LEN(submicro
);
2285 if (10 <= (digit
= ptr
[0] >> 4)) goto end_submicro
;
2286 nsec
+= digit
* 100;
2287 if (10 <= (digit
= ptr
[0] & 0xf)) goto end_submicro
;
2291 if (10 <= (digit
= ptr
[1] >> 4)) goto end_submicro
;
2297 time_overflow_p(&sec
, &nsec
);
2299 GetTimeval(time
, tobj
);
2302 tobj
->ts
.tv_sec
= sec
;
2303 tobj
->ts
.tv_nsec
= nsec
;
2310 * Time._load(string) => time
2312 * Unmarshal a dumped +Time+ object.
2316 time_load(VALUE klass
, VALUE str
)
2318 VALUE time
= time_s_alloc(klass
);
2320 time_mload(time
, str
);
2325 * <code>Time</code> is an abstraction of dates and times. Time is
2326 * stored internally as the number of seconds and nanoseconds since
2327 * the <em>Epoch</em>, January 1, 1970 00:00 UTC. On some operating
2328 * systems, this offset is allowed to be negative. Also see the
2329 * library modules <code>Date</code>. The
2330 * <code>Time</code> class treats GMT (Greenwich Mean Time) and UTC
2331 * (Coordinated Universal Time)<em>[Yes, UTC really does stand for
2332 * Coordinated Universal Time. There was a committee involved.]</em>
2333 * as equivalent. GMT is the older way of referring to these
2334 * baseline times but persists in the names of calls on POSIX
2337 * All times are stored with some number of nanoseconds. Be aware of
2338 * this fact when comparing times with each other---times that are
2339 * apparently equal when displayed may be different when compared.
2347 id_divmod
= rb_intern("divmod");
2348 id_mul
= rb_intern("*");
2349 id_submicro
= rb_intern("submicro");
2351 rb_cTime
= rb_define_class("Time", rb_cObject
);
2352 rb_include_module(rb_cTime
, rb_mComparable
);
2354 rb_define_alloc_func(rb_cTime
, time_s_alloc
);
2355 rb_define_singleton_method(rb_cTime
, "now", rb_class_new_instance
, -1);
2356 rb_define_singleton_method(rb_cTime
, "at", time_s_at
, -1);
2357 rb_define_singleton_method(rb_cTime
, "utc", time_s_mkutc
, -1);
2358 rb_define_singleton_method(rb_cTime
, "gm", time_s_mkutc
, -1);
2359 rb_define_singleton_method(rb_cTime
, "local", time_s_mktime
, -1);
2360 rb_define_singleton_method(rb_cTime
, "mktime", time_s_mktime
, -1);
2362 rb_define_method(rb_cTime
, "to_i", time_to_i
, 0);
2363 rb_define_method(rb_cTime
, "to_f", time_to_f
, 0);
2364 rb_define_method(rb_cTime
, "<=>", time_cmp
, 1);
2365 rb_define_method(rb_cTime
, "eql?", time_eql
, 1);
2366 rb_define_method(rb_cTime
, "hash", time_hash
, 0);
2367 rb_define_method(rb_cTime
, "initialize", time_init
, 0);
2368 rb_define_method(rb_cTime
, "initialize_copy", time_init_copy
, 1);
2370 rb_define_method(rb_cTime
, "localtime", time_localtime
, 0);
2371 rb_define_method(rb_cTime
, "gmtime", time_gmtime
, 0);
2372 rb_define_method(rb_cTime
, "utc", time_gmtime
, 0);
2373 rb_define_method(rb_cTime
, "getlocal", time_getlocaltime
, 0);
2374 rb_define_method(rb_cTime
, "getgm", time_getgmtime
, 0);
2375 rb_define_method(rb_cTime
, "getutc", time_getgmtime
, 0);
2377 rb_define_method(rb_cTime
, "ctime", time_asctime
, 0);
2378 rb_define_method(rb_cTime
, "asctime", time_asctime
, 0);
2379 rb_define_method(rb_cTime
, "to_s", time_to_s
, 0);
2380 rb_define_method(rb_cTime
, "inspect", time_to_s
, 0);
2381 rb_define_method(rb_cTime
, "to_a", time_to_a
, 0);
2383 rb_define_method(rb_cTime
, "+", time_plus
, 1);
2384 rb_define_method(rb_cTime
, "-", time_minus
, 1);
2386 rb_define_method(rb_cTime
, "succ", time_succ
, 0);
2387 rb_define_method(rb_cTime
, "sec", time_sec
, 0);
2388 rb_define_method(rb_cTime
, "min", time_min
, 0);
2389 rb_define_method(rb_cTime
, "hour", time_hour
, 0);
2390 rb_define_method(rb_cTime
, "mday", time_mday
, 0);
2391 rb_define_method(rb_cTime
, "day", time_mday
, 0);
2392 rb_define_method(rb_cTime
, "mon", time_mon
, 0);
2393 rb_define_method(rb_cTime
, "month", time_mon
, 0);
2394 rb_define_method(rb_cTime
, "year", time_year
, 0);
2395 rb_define_method(rb_cTime
, "wday", time_wday
, 0);
2396 rb_define_method(rb_cTime
, "yday", time_yday
, 0);
2397 rb_define_method(rb_cTime
, "isdst", time_isdst
, 0);
2398 rb_define_method(rb_cTime
, "dst?", time_isdst
, 0);
2399 rb_define_method(rb_cTime
, "zone", time_zone
, 0);
2400 rb_define_method(rb_cTime
, "gmtoff", time_utc_offset
, 0);
2401 rb_define_method(rb_cTime
, "gmt_offset", time_utc_offset
, 0);
2402 rb_define_method(rb_cTime
, "utc_offset", time_utc_offset
, 0);
2404 rb_define_method(rb_cTime
, "utc?", time_utc_p
, 0);
2405 rb_define_method(rb_cTime
, "gmt?", time_utc_p
, 0);
2407 rb_define_method(rb_cTime
, "sunday?", time_sunday
, 0);
2408 rb_define_method(rb_cTime
, "monday?", time_monday
, 0);
2409 rb_define_method(rb_cTime
, "tuesday?", time_tuesday
, 0);
2410 rb_define_method(rb_cTime
, "wednesday?", time_wednesday
, 0);
2411 rb_define_method(rb_cTime
, "thursday?", time_thursday
, 0);
2412 rb_define_method(rb_cTime
, "friday?", time_friday
, 0);
2413 rb_define_method(rb_cTime
, "saturday?", time_saturday
, 0);
2415 rb_define_method(rb_cTime
, "tv_sec", time_to_i
, 0);
2416 rb_define_method(rb_cTime
, "tv_usec", time_usec
, 0);
2417 rb_define_method(rb_cTime
, "usec", time_usec
, 0);
2418 rb_define_method(rb_cTime
, "tv_nsec", time_nsec
, 0);
2419 rb_define_method(rb_cTime
, "nsec", time_nsec
, 0);
2421 rb_define_method(rb_cTime
, "strftime", time_strftime
, 1);
2423 /* methods for marshaling */
2424 rb_define_method(rb_cTime
, "_dump", time_dump
, -1);
2425 rb_define_singleton_method(rb_cTime
, "_load", time_load
, 1);
2427 /* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
2428 rb_define_method(rb_cTime
, "marshal_dump", time_mdump
, 0);
2429 rb_define_method(rb_cTime
, "marshal_load", time_mload
, 1);