time.c
DEFINITIONS
This source file includes following functions.
- time_free
- time_s_alloc
- time_s_now
- time_new_internal
- rb_time_new
- time_timeval
- rb_time_interval
- rb_time_timeval
- time_s_at
- obj2long
- time_arg
- tmcmp
- search_time_t
- make_time_t
- time_utc_or_local
- time_s_mkutc
- time_s_mktime
- time_to_i
- time_to_f
- time_usec
- time_cmp
- time_eql
- time_utc_p
- time_hash
- time_modify
- time_become
- time_dup
- time_localtime
- time_gmtime
- time_getlocaltime
- time_getgmtime
- time_get_tm
- time_asctime
- time_to_s
- time_plus
- time_minus
- time_sec
- time_min
- time_hour
- time_mday
- time_mon
- time_year
- time_wday
- time_yday
- time_isdst
- time_zone
- time_utc_offset
- time_to_a
- rb_strftime
- time_strftime
- time_s_times
- time_dump
- time_load
- Init_Time
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14 #include <sys/types.h>
15
16 #include <time.h>
17 #ifndef NT
18 #ifdef HAVE_SYS_TIME_H
19 # include <sys/time.h>
20 #else
21 #define time_t long
22 struct timeval {
23 time_t tv_sec;
24 time_t tv_usec;
25 };
26 #endif
27 #endif
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <math.h>
33
34 VALUE rb_cTime;
35
36 struct time_object {
37 struct timeval tv;
38 struct tm tm;
39 int gmt;
40 int tm_got;
41 };
42
43 #define GetTimeval(obj, tobj) \
44 Data_Get_Struct(obj, struct time_object, tobj)
45
46 static void time_free _((void *));
47
48 static void
49 time_free(tobj)
50 void *tobj;
51 {
52 if (tobj) free(tobj);
53 }
54
55 static VALUE
56 time_s_alloc(klass)
57 VALUE klass;
58 {
59 VALUE obj;
60 struct time_object *tobj;
61
62 obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
63 tobj->tm_got=0;
64 if (gettimeofday(&tobj->tv, 0) < 0) {
65 rb_sys_fail("gettimeofday");
66 }
67
68 return obj;
69 }
70
71 static VALUE
72 time_s_now(klass)
73 VALUE klass;
74 {
75 return rb_obj_alloc(klass);
76 }
77
78
79 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
80 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
81
82 static VALUE
83 time_new_internal(klass, sec, usec)
84 VALUE klass;
85 time_t sec, usec;
86 {
87 VALUE obj;
88 time_t tmp;
89 struct time_object *tobj;
90
91 if (usec >= 1000000) {
92 tmp = sec + usec / 1000000;
93 usec %= 1000000;
94 if (sec > 0 && tmp < 0) {
95 rb_raise(rb_eRangeError, "out of Time range");
96 }
97 sec = tmp;
98 }
99 if (usec < 0) {
100 tmp = sec + NDIV(usec,1000000);
101 usec = NMOD(usec,1000000);
102 if (sec < 0 && tmp > 0) {
103 rb_raise(rb_eRangeError, "out of Time range");
104 }
105 sec = tmp;
106 }
107 #ifndef NEGATIVE_TIME_T
108 if (sec < 0 || (sec == 0 && usec < 0))
109 rb_raise(rb_eArgError, "time must be positive");
110 #endif
111
112 obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
113 tobj->tm_got = 0;
114 tobj->tv.tv_sec = sec;
115 tobj->tv.tv_usec = usec;
116
117 return obj;
118 }
119
120 VALUE
121 rb_time_new(sec, usec)
122 time_t sec, usec;
123 {
124 return time_new_internal(rb_cTime, sec, usec);
125 }
126
127 static struct timeval
128 time_timeval(time, interval)
129 VALUE time;
130 int interval;
131 {
132 struct timeval t;
133 char *tstr = interval ? "time interval" : "time";
134
135 #ifndef NEGATIVE_TIME_T
136 interval = 1;
137 #endif
138
139 switch (TYPE(time)) {
140 case T_FIXNUM:
141 t.tv_sec = FIX2LONG(time);
142 if (interval && t.tv_sec < 0)
143 rb_raise(rb_eArgError, "%s must be positive", tstr);
144 t.tv_usec = 0;
145 break;
146
147 case T_FLOAT:
148 if (interval && RFLOAT(time)->value < 0.0)
149 rb_raise(rb_eArgError, "%s must be positive", tstr);
150 else {
151 double f, d;
152
153 d = modf(RFLOAT(time)->value, &f);
154 t.tv_sec = (time_t)f;
155 if (f != t.tv_sec) {
156 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT(time)->value);
157 }
158 t.tv_usec = (time_t)(d*1e6);
159 }
160 break;
161
162 case T_BIGNUM:
163 t.tv_sec = NUM2LONG(time);
164 if (interval && t.tv_sec < 0)
165 rb_raise(rb_eArgError, "%s must be positive", tstr);
166 t.tv_usec = 0;
167 break;
168
169 default:
170 rb_raise(rb_eTypeError, "can't convert %s into %s",
171 rb_class2name(CLASS_OF(time)), tstr);
172 break;
173 }
174 return t;
175 }
176
177 struct timeval
178 rb_time_interval(time)
179 VALUE time;
180 {
181 return time_timeval(time, Qtrue);
182 }
183
184 struct timeval
185 rb_time_timeval(time)
186 VALUE time;
187 {
188 struct time_object *tobj;
189 struct timeval t;
190
191 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
192 GetTimeval(time, tobj);
193 t = tobj->tv;
194 return t;
195 }
196 return time_timeval(time, Qfalse);
197 }
198
199 static VALUE
200 time_s_at(argc, argv, klass)
201 int argc;
202 VALUE *argv;
203 VALUE klass;
204 {
205 struct timeval tv;
206 VALUE time, t;
207
208 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
209 tv.tv_sec = NUM2LONG(time);
210 tv.tv_usec = NUM2LONG(t);
211 }
212 else {
213 tv = rb_time_timeval(time);
214 }
215 t = time_new_internal(klass, tv.tv_sec, tv.tv_usec);
216 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
217 struct time_object *tobj, *tobj2;
218
219 GetTimeval(time, tobj);
220 GetTimeval(t, tobj2);
221 tobj2->gmt = tobj->gmt;
222 }
223 return t;
224 }
225
226 static char *months [12] = {
227 "jan", "feb", "mar", "apr", "may", "jun",
228 "jul", "aug", "sep", "oct", "nov", "dec",
229 };
230
231 static long
232 obj2long(obj)
233 VALUE obj;
234 {
235 if (TYPE(obj) == T_STRING) {
236 obj = rb_str_to_inum(obj, 10, Qfalse);
237 }
238
239 return NUM2LONG(obj);
240 }
241
242 static void
243 time_arg(argc, argv, tm, usec)
244 int argc;
245 VALUE *argv;
246 struct tm *tm;
247 time_t *usec;
248 {
249 VALUE v[7];
250 int i;
251 long year;
252
253 MEMZERO(tm, struct tm, 1);
254 if (argc == 10) {
255 v[0] = argv[5];
256 v[1] = argv[4];
257 v[2] = argv[3];
258 v[3] = argv[2];
259 v[4] = argv[1];
260 v[5] = argv[0];
261 *usec = 0;
262 tm->tm_isdst = RTEST(argv[8]) ? 1 : 0;
263 }
264 else {
265 rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
266 *usec = NIL_P(v[6]) ? 0 : obj2long(v[6]);
267 tm->tm_isdst = -1;
268 }
269
270 year = obj2long(v[0]);
271
272 if (0 <= year && year < 39) {
273 year += 100;
274 rb_warning("2 digits year is used");
275 }
276 else if (69 <= year && year < 139) {
277 rb_warning("2 or 3 digits year is used");
278 }
279 else {
280 year -= 1900;
281 }
282
283 tm->tm_year = year;
284
285 if (NIL_P(v[1])) {
286 tm->tm_mon = 0;
287 }
288 else if (TYPE(v[1]) == T_STRING) {
289 tm->tm_mon = -1;
290 for (i=0; i<12; i++) {
291 if (RSTRING(v[1])->len == 3 &&
292 strcasecmp(months[i], RSTRING(v[1])->ptr) == 0) {
293 tm->tm_mon = i;
294 break;
295 }
296 }
297 if (tm->tm_mon == -1) {
298 char c = RSTRING(v[1])->ptr[0];
299
300 if ('0' <= c && c <= '9') {
301 tm->tm_mon = obj2long(v[1])-1;
302 }
303 }
304 }
305 else {
306 tm->tm_mon = obj2long(v[1]) - 1;
307 }
308 if (NIL_P(v[2])) {
309 tm->tm_mday = 1;
310 }
311 else {
312 tm->tm_mday = obj2long(v[2]);
313 }
314 tm->tm_hour = NIL_P(v[3])?0:obj2long(v[3]);
315 tm->tm_min = NIL_P(v[4])?0:obj2long(v[4]);
316 tm->tm_sec = NIL_P(v[5])?0:obj2long(v[5]);
317
318
319 if (
320 tm->tm_year != year ||
321 #ifndef NEGATIVE_TIME_T
322 tm->tm_year < 69 ||
323 #endif
324 tm->tm_mon < 0 || tm->tm_mon > 11
325 || tm->tm_mday < 1 || tm->tm_mday > 31
326 || tm->tm_hour < 0 || tm->tm_hour > 23
327 || tm->tm_min < 0 || tm->tm_min > 59
328 || tm->tm_sec < 0 || tm->tm_sec > 60)
329 rb_raise(rb_eArgError, "argument out of range");
330 }
331
332 static VALUE time_gmtime _((VALUE));
333 static VALUE time_localtime _((VALUE));
334 static VALUE time_get_tm _((VALUE, int));
335
336 #if !defined HAVE_TIMEGM
337 static int
338 tmcmp(a, b)
339 struct tm *a;
340 struct tm *b;
341 {
342 if (a->tm_year != b->tm_year)
343 return a->tm_year < b->tm_year ? -1 : 1;
344 else if (a->tm_mon != b->tm_mon)
345 return a->tm_mon < b->tm_mon ? -1 : 1;
346 else if (a->tm_mday != b->tm_mday)
347 return a->tm_mday < b->tm_mday ? -1 : 1;
348 else if (a->tm_hour != b->tm_hour)
349 return a->tm_hour < b->tm_hour ? -1 : 1;
350 else if (a->tm_min != b->tm_min)
351 return a->tm_min < b->tm_min ? -1 : 1;
352 else if (a->tm_sec != b->tm_sec)
353 return a->tm_sec < b->tm_sec ? -1 : 1;
354 else
355 return 0;
356 }
357
358 static time_t
359 search_time_t(tptr, utc_p)
360 struct tm *tptr;
361 int utc_p;
362 {
363 time_t guess, guess_lo, guess_hi;
364 struct tm *tm, tm_lo, tm_hi;
365 int d, have_guess;
366 int find_dst;
367
368 find_dst = 0 < tptr->tm_isdst;
369
370 #ifdef NEGATIVE_TIME_T
371 guess_lo = 1L << (8 * sizeof(time_t) - 1);
372 #else
373 guess_lo = 0;
374 #endif
375 guess_hi = ((time_t)-1) < ((time_t)0) ?
376 (1UL << (8 * sizeof(time_t) - 1)) - 1 :
377 ~(time_t)0;
378
379 tm = (utc_p ? gmtime : localtime)(&guess_lo);
380 if (!tm) goto error;
381 d = tmcmp(tptr, tm);
382 if (d < 0) goto out_of_range;
383 if (d == 0) return guess_lo;
384 tm_lo = *tm;
385
386 tm = (utc_p ? gmtime : localtime)(&guess_hi);
387 if (!tm) goto error;
388 d = tmcmp(tptr, tm);
389 if (d > 0) goto out_of_range;
390 if (d == 0) return guess_hi;
391 tm_hi = *tm;
392
393 have_guess = 0;
394
395 while (guess_lo + 1 < guess_hi) {
396
397 unsigned long range = 0;
398 if (!have_guess) {
399 int a, b;
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421 range = 366 * 24 * 60 * 60;
422 a = (tm_hi.tm_year - tptr->tm_year);
423 b = (tptr->tm_year - tm_lo.tm_year);
424
425 if (a + b <= 46000 / 12) {
426 range = 31 * 24 * 60 * 60;
427 a *= 12;
428 b *= 12;
429 a += tm_hi.tm_mon - tptr->tm_mon;
430 b += tptr->tm_mon - tm_lo.tm_mon;
431 if (a + b <= 46000 / 31) {
432 range = 24 * 60 * 60;
433 a *= 31;
434 b *= 31;
435 a += tm_hi.tm_mday - tptr->tm_mday;
436 b += tptr->tm_mday - tm_lo.tm_mday;
437 if (a + b <= 46000 / 24) {
438 range = 60 * 60;
439 a *= 24;
440 b *= 24;
441 a += tm_hi.tm_hour - tptr->tm_hour;
442 b += tptr->tm_hour - tm_lo.tm_hour;
443 if (a + b <= 46000 / 60) {
444 range = 60;
445 a *= 60;
446 b *= 60;
447 a += tm_hi.tm_min - tptr->tm_min;
448 b += tptr->tm_min - tm_lo.tm_min;
449 if (a + b <= 46000 / 60) {
450 range = 1;
451 a *= 60;
452 b *= 60;
453 a += tm_hi.tm_sec - tptr->tm_sec;
454 b += tptr->tm_sec - tm_lo.tm_sec;
455 }
456 }
457 }
458 }
459 }
460 if (a <= 0) a = 1;
461 if (b <= 0) b = 1;
462 d = a + b;
463
464
465
466
467
468 guess = guess_lo / d * a + (guess_lo % d) * a / d
469 + guess_hi / d * b + (guess_hi % d) * b / d;
470 have_guess = 1;
471 }
472
473 if (guess <= guess_lo || guess_hi <= guess) {
474
475 guess = guess_lo / 2 + guess_hi / 2;
476 if (guess <= guess_lo)
477 guess = guess_lo + 1;
478 else if (guess >= guess_hi)
479 guess = guess_hi - 1;
480 range = 0;
481 }
482
483 tm = (utc_p ? gmtime : localtime)(&guess);
484 if (!tm) goto error;
485 have_guess = 0;
486
487 d = tmcmp(tptr, tm);
488 if (d < 0) {
489 guess_hi = guess;
490 tm_hi = *tm;
491 if (range) {
492 guess = guess - range;
493 range = 0;
494 if (guess_lo < guess && guess < guess_hi)
495 have_guess = 1;
496 }
497 }
498 else if (d > 0) {
499 guess_lo = guess;
500 tm_lo = *tm;
501 if (range) {
502 guess = guess + range;
503 range = 0;
504 if (guess_lo < guess && guess < guess_hi)
505 have_guess = 1;
506 }
507 }
508 else {
509 if (!utc_p) {
510
511 time_t guess2;
512 if (find_dst) {
513 guess2 = guess - 2 * 60 * 60;
514 tm = localtime(&guess2);
515 if (tm) {
516 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
517 tptr->tm_min != tm->tm_min ||
518 tptr->tm_sec != tm->tm_sec) {
519 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
520 (tm->tm_min - tptr->tm_min) * 60 +
521 (tm->tm_sec - tptr->tm_sec);
522 if (tptr->tm_mday != tm->tm_mday)
523 guess2 += 24 * 60 * 60;
524 if (guess != guess2) {
525 tm = localtime(&guess2);
526 if (tmcmp(tptr, tm) == 0) {
527 if (guess < guess2)
528 return guess;
529 else
530 return guess2;
531 }
532 }
533 }
534 }
535 }
536 else {
537 guess2 = guess + 2 * 60 * 60;
538 tm = localtime(&guess2);
539 if (tm) {
540 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
541 tptr->tm_min != tm->tm_min ||
542 tptr->tm_sec != tm->tm_sec) {
543 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
544 (tm->tm_min - tptr->tm_min) * 60 +
545 (tm->tm_sec - tptr->tm_sec);
546 if (tptr->tm_mday != tm->tm_mday)
547 guess2 -= 24 * 60 * 60;
548 if (guess != guess2) {
549 tm = localtime(&guess2);
550 if (tmcmp(tptr, tm) == 0) {
551 if (guess < guess2)
552 return guess2;
553 else
554 return guess;
555 }
556 }
557 }
558 }
559 }
560 }
561 return guess;
562 }
563 }
564
565 if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) {
566 return guess_lo +
567 (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 +
568 (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 +
569 (tptr->tm_min - tm_lo.tm_min) * 60 +
570 (tptr->tm_sec - tm_lo.tm_sec);
571 }
572 else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
573 return guess_hi +
574 (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
575 (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
576 (tptr->tm_min - tm_hi.tm_min) * 60 +
577 (tptr->tm_sec - tm_hi.tm_sec);
578 }
579
580 out_of_range:
581 rb_raise(rb_eArgError, "time out of range");
582
583 error:
584 rb_raise(rb_eArgError, "gmtime/localtime error");
585 return 0;
586 }
587 #endif
588
589 static time_t
590 make_time_t(tptr, utc_p)
591 struct tm *tptr;
592 int utc_p;
593 {
594 time_t t;
595 struct tm *tmp, buf;
596 buf = *tptr;
597 if (utc_p) {
598 #if defined(HAVE_TIMEGM)
599 t = timegm(&buf);
600 if (t == -1) {
601 #ifdef NEGATIVE_TIME_T
602 if (!(tmp = gmtime(&t)) ||
603 tptr->tm_year != tmp->tm_year ||
604 tptr->tm_mon != tmp->tm_mon ||
605 tptr->tm_mday != tmp->tm_mday ||
606 tptr->tm_hour != tmp->tm_hour ||
607 tptr->tm_min != tmp->tm_min ||
608 tptr->tm_sec != tmp->tm_sec)
609 #endif
610 rb_raise(rb_eArgError, "gmtime error");
611 }
612 #else
613 t = search_time_t(&buf, utc_p);
614 #endif
615 }
616 else {
617 #if defined(HAVE_MKTIME)
618 t = mktime(&buf);
619 if (t == -1) {
620 #ifdef NEGATIVE_TIME_T
621 if (!(tmp = localtime(&t)) ||
622 tptr->tm_year != tmp->tm_year ||
623 tptr->tm_mon != tmp->tm_mon ||
624 tptr->tm_mday != tmp->tm_mday ||
625 tptr->tm_hour != tmp->tm_hour ||
626 tptr->tm_min != tmp->tm_min ||
627 tptr->tm_sec != tmp->tm_sec)
628 #endif
629 rb_raise(rb_eArgError, "localtime error");
630 }
631 #else
632 t = search_time_t(&buf, utc_p);
633 #endif
634 }
635 return t;
636 }
637
638 static VALUE
639 time_utc_or_local(argc, argv, utc_p, klass)
640 int argc;
641 VALUE *argv;
642 int utc_p;
643 VALUE klass;
644 {
645 struct tm tm;
646 VALUE time;
647 time_t usec;
648
649 time_arg(argc, argv, &tm, &usec);
650 time = time_new_internal(klass, make_time_t(&tm, utc_p), usec);
651 if (utc_p) return time_gmtime(time);
652 return time_localtime(time);
653 }
654
655 static VALUE
656 time_s_mkutc(argc, argv, klass)
657 int argc;
658 VALUE *argv;
659 VALUE klass;
660 {
661 return time_utc_or_local(argc, argv, Qtrue, klass);
662 }
663
664 static VALUE
665 time_s_mktime(argc, argv, klass)
666 int argc;
667 VALUE *argv;
668 VALUE klass;
669 {
670 return time_utc_or_local(argc, argv, Qfalse, klass);
671 }
672
673 static VALUE
674 time_to_i(time)
675 VALUE time;
676 {
677 struct time_object *tobj;
678
679 GetTimeval(time, tobj);
680 return LONG2NUM(tobj->tv.tv_sec);
681 }
682
683 static VALUE
684 time_to_f(time)
685 VALUE time;
686 {
687 struct time_object *tobj;
688
689 GetTimeval(time, tobj);
690 return rb_float_new((double)tobj->tv.tv_sec+(double)tobj->tv.tv_usec/1e6);
691 }
692
693 static VALUE
694 time_usec(time)
695 VALUE time;
696 {
697 struct time_object *tobj;
698
699 GetTimeval(time, tobj);
700 return LONG2NUM(tobj->tv.tv_usec);
701 }
702
703 static VALUE
704 time_cmp(time1, time2)
705 VALUE time1, time2;
706 {
707 struct time_object *tobj1, *tobj2;
708 long i;
709
710 GetTimeval(time1, tobj1);
711 switch (TYPE(time2)) {
712 case T_FIXNUM:
713 i = FIX2LONG(time2);
714 if (tobj1->tv.tv_sec == i) {
715 if (tobj1->tv.tv_usec == 0)
716 return INT2FIX(0);
717 if (tobj1->tv.tv_usec > 0)
718 return INT2FIX(1);
719 return INT2FIX(-1);
720 }
721 if (tobj1->tv.tv_sec > i) return INT2FIX(1);
722 return INT2FIX(-1);
723
724 case T_FLOAT:
725 return rb_dbl_cmp((double)tobj1->tv.tv_sec + (double)tobj1->tv.tv_usec*1e-6,
726 RFLOAT(time2)->value);
727 }
728
729 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
730 GetTimeval(time2, tobj2);
731 if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) {
732 if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return INT2FIX(0);
733 if (tobj1->tv.tv_usec > tobj2->tv.tv_usec) return INT2FIX(1);
734 return INT2FIX(-1);
735 }
736 if (tobj1->tv.tv_sec > tobj2->tv.tv_sec) return INT2FIX(1);
737 return INT2FIX(-1);
738 }
739 if (TYPE(time2) == T_BIGNUM) {
740 double a = (double)tobj1->tv.tv_sec+(double)tobj1->tv.tv_usec/1e6;
741 double b = rb_big2dbl(time2);
742
743 if (a == b) return INT2FIX(0);
744 if (a > b) return INT2FIX(1);
745 if (a < b) return INT2FIX(-1);
746 }
747 i = NUM2LONG(time2);
748 if (tobj1->tv.tv_sec == i) {
749 if (tobj1->tv.tv_usec == 0)
750 return INT2FIX(0);
751 if (tobj1->tv.tv_usec > 0)
752 return INT2FIX(1);
753 return INT2FIX(-1);
754 }
755 if (tobj1->tv.tv_sec > i) return INT2FIX(1);
756 return INT2FIX(-1);
757 }
758
759 static VALUE
760 time_eql(time1, time2)
761 VALUE time1, time2;
762 {
763 struct time_object *tobj1, *tobj2;
764
765 GetTimeval(time1, tobj1);
766 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
767 GetTimeval(time2, tobj2);
768 if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) {
769 if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return Qtrue;
770 }
771 }
772 return Qfalse;
773 }
774
775 static VALUE
776 time_utc_p(time)
777 VALUE time;
778 {
779 struct time_object *tobj;
780
781 GetTimeval(time, tobj);
782 if (tobj->gmt) return Qtrue;
783 return Qfalse;
784 }
785
786 static VALUE
787 time_hash(time)
788 VALUE time;
789 {
790 struct time_object *tobj;
791 long hash;
792
793 GetTimeval(time, tobj);
794 hash = tobj->tv.tv_sec ^ tobj->tv.tv_usec;
795 return LONG2FIX(hash);
796 }
797
798 static void
799 time_modify(time)
800 VALUE time;
801 {
802 rb_check_frozen(time);
803 if (!OBJ_TAINTED(time) && rb_safe_level() >= 4)
804 rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
805 }
806
807 static VALUE
808 time_become(copy, time)
809 VALUE copy, time;
810 {
811 struct time_object *tobj, *tcopy;
812
813 if (copy == time) return copy;
814 time_modify(copy);
815 if (TYPE(time) != T_DATA || RDATA(time)->dfree != time_free) {
816 rb_raise(rb_eTypeError, "wrong argument type");
817 }
818 GetTimeval(time, tobj);
819 GetTimeval(copy, tcopy);
820 MEMCPY(tcopy, tobj, struct time_object, 1);
821
822 return copy;
823 }
824
825 static VALUE
826 time_dup(time)
827 VALUE time;
828 {
829 VALUE dup = time_s_alloc(rb_cTime);
830 time_become(dup, time);
831 return dup;
832 }
833
834 static VALUE
835 time_localtime(time)
836 VALUE time;
837 {
838 struct time_object *tobj;
839 struct tm *tm_tmp;
840 time_t t;
841
842 GetTimeval(time, tobj);
843 if (!tobj->gmt) {
844 if (tobj->tm_got)
845 return time;
846 }
847 else {
848 time_modify(time);
849 }
850 t = tobj->tv.tv_sec;
851 tm_tmp = localtime(&t);
852 if (!tm_tmp)
853 rb_raise(rb_eArgError, "localtime error");
854 tobj->tm = *tm_tmp;
855 tobj->tm_got = 1;
856 tobj->gmt = 0;
857 return time;
858 }
859
860 static VALUE
861 time_gmtime(time)
862 VALUE time;
863 {
864 struct time_object *tobj;
865 struct tm *tm_tmp;
866 time_t t;
867
868 GetTimeval(time, tobj);
869 if (tobj->gmt) {
870 if (tobj->tm_got)
871 return time;
872 }
873 else {
874 time_modify(time);
875 }
876 t = tobj->tv.tv_sec;
877 tm_tmp = gmtime(&t);
878 if (!tm_tmp)
879 rb_raise(rb_eArgError, "gmtime error");
880 tobj->tm = *tm_tmp;
881 tobj->tm_got = 1;
882 tobj->gmt = 1;
883 return time;
884 }
885
886 static VALUE
887 time_getlocaltime(time)
888 VALUE time;
889 {
890 return time_localtime(time_dup(time));
891 }
892
893 static VALUE
894 time_getgmtime(time)
895 VALUE time;
896 {
897 return time_gmtime(time_dup(time));
898 }
899
900 static VALUE
901 time_get_tm(time, gmt)
902 VALUE time;
903 int gmt;
904 {
905 if (gmt) return time_gmtime(time);
906 return time_localtime(time);
907 }
908
909 static VALUE
910 time_asctime(time)
911 VALUE time;
912 {
913 struct time_object *tobj;
914 char *s;
915
916 GetTimeval(time, tobj);
917 if (tobj->tm_got == 0) {
918 time_get_tm(time, tobj->gmt);
919 }
920 s = asctime(&tobj->tm);
921 if (s[24] == '\n') s[24] = '\0';
922
923 return rb_str_new2(s);
924 }
925
926 static VALUE
927 time_to_s(time)
928 VALUE time;
929 {
930 struct time_object *tobj;
931 char buf[128];
932 int len;
933
934 GetTimeval(time, tobj);
935 if (tobj->tm_got == 0) {
936 time_get_tm(time, tobj->gmt);
937 }
938 if (tobj->gmt == 1) {
939 len = strftime(buf, 128, "%a %b %d %H:%M:%S UTC %Y", &tobj->tm);
940 }
941 else {
942 len = strftime(buf, 128, "%a %b %d %H:%M:%S %Z %Y", &tobj->tm);
943 }
944 return rb_str_new(buf, len);
945 }
946
947 static VALUE
948 time_plus(time1, time2)
949 VALUE time1, time2;
950 {
951 struct time_object *tobj;
952 time_t sec, usec;
953 double f, d, v;
954
955 GetTimeval(time1, tobj);
956
957 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
958 rb_raise(rb_eTypeError, "time + time?");
959 }
960 v = NUM2DBL(time2);
961 d = modf(v, &f);
962 sec = (time_t)f;
963 if (f != (double)sec) {
964 rb_raise(rb_eRangeError, "time + %f out of Time range", v);
965 }
966 #ifndef NEGATIVE_TIME_T
967 if (f < 0 && -f >= tobj->tv.tv_sec) {
968 rb_raise(rb_eArgError, "time must be positive");
969 }
970 #endif
971 usec = tobj->tv.tv_usec + (time_t)(d*1e6);
972 sec = tobj->tv.tv_sec + (time_t)f;
973
974 #ifdef NEGATIVE_TIME_T
975 if ((tobj->tv.tv_sec >= 0 && f >= 0 && sec < 0) ||
976 (tobj->tv.tv_sec <= 0 && f <= 0 && sec > 0)) {
977 rb_raise(rb_eRangeError, "time + %f out of Time range", v);
978 }
979 #endif
980 time2 = rb_time_new(sec, usec);
981 if (tobj->gmt) {
982 GetTimeval(time2, tobj);
983 tobj->gmt = 1;
984 }
985 return time2;
986 }
987
988 static VALUE
989 time_minus(time1, time2)
990 VALUE time1, time2;
991 {
992 struct time_object *tobj;
993 time_t sec, usec;
994 double f, d, v;
995
996 GetTimeval(time1, tobj);
997 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
998 struct time_object *tobj2;
999
1000 GetTimeval(time2, tobj2);
1001 f = (double)tobj->tv.tv_sec - (double)tobj2->tv.tv_sec;
1002 f += ((double)tobj->tv.tv_usec - (double)tobj2->tv.tv_usec)*1e-6;
1003
1004
1005 return rb_float_new(f);
1006 }
1007 v = NUM2DBL(time2);
1008 d = modf(v, &f);
1009 sec = (time_t)f;
1010 if (f != (double)sec) {
1011 rb_raise(rb_eRangeError, "time - %f out of Time range", v);
1012 }
1013 #ifndef NEGATIVE_TIME_T
1014 if (f > 0 && f >= tobj->tv.tv_sec) {
1015 rb_raise(rb_eArgError, "time must be positive");
1016 }
1017 #endif
1018 usec = tobj->tv.tv_usec - (time_t)(d*1e6);
1019 sec = tobj->tv.tv_sec - (time_t)f;
1020 #ifdef NEGATIVE_TIME_T
1021 if ((tobj->tv.tv_sec <= 0 && f >= 0 && sec > 0) ||
1022 (tobj->tv.tv_sec >= 0 && f <= 0 && sec < 0)) {
1023 rb_raise(rb_eRangeError, "time - %f out of Time range", v);
1024 }
1025 #endif
1026
1027 time2 = rb_time_new(sec, usec);
1028 if (tobj->gmt) {
1029 GetTimeval(time2, tobj);
1030 tobj->gmt = 1;
1031 }
1032 return time2;
1033 }
1034
1035 static VALUE
1036 time_sec(time)
1037 VALUE time;
1038 {
1039 struct time_object *tobj;
1040
1041 GetTimeval(time, tobj);
1042 if (tobj->tm_got == 0) {
1043 time_get_tm(time, tobj->gmt);
1044 }
1045 return INT2FIX(tobj->tm.tm_sec);
1046 }
1047
1048 static VALUE
1049 time_min(time)
1050 VALUE time;
1051 {
1052 struct time_object *tobj;
1053
1054 GetTimeval(time, tobj);
1055 if (tobj->tm_got == 0) {
1056 time_get_tm(time, tobj->gmt);
1057 }
1058 return INT2FIX(tobj->tm.tm_min);
1059 }
1060
1061 static VALUE
1062 time_hour(time)
1063 VALUE time;
1064 {
1065 struct time_object *tobj;
1066
1067 GetTimeval(time, tobj);
1068 if (tobj->tm_got == 0) {
1069 time_get_tm(time, tobj->gmt);
1070 }
1071 return INT2FIX(tobj->tm.tm_hour);
1072 }
1073
1074 static VALUE
1075 time_mday(time)
1076 VALUE time;
1077 {
1078 struct time_object *tobj;
1079
1080 GetTimeval(time, tobj);
1081 if (tobj->tm_got == 0) {
1082 time_get_tm(time, tobj->gmt);
1083 }
1084 return INT2FIX(tobj->tm.tm_mday);
1085 }
1086
1087 static VALUE
1088 time_mon(time)
1089 VALUE time;
1090 {
1091 struct time_object *tobj;
1092
1093 GetTimeval(time, tobj);
1094 if (tobj->tm_got == 0) {
1095 time_get_tm(time, tobj->gmt);
1096 }
1097 return INT2FIX(tobj->tm.tm_mon+1);
1098 }
1099
1100 static VALUE
1101 time_year(time)
1102 VALUE time;
1103 {
1104 struct time_object *tobj;
1105
1106 GetTimeval(time, tobj);
1107 if (tobj->tm_got == 0) {
1108 time_get_tm(time, tobj->gmt);
1109 }
1110 return LONG2NUM((long)tobj->tm.tm_year+1900);
1111 }
1112
1113 static VALUE
1114 time_wday(time)
1115 VALUE time;
1116 {
1117 struct time_object *tobj;
1118
1119 GetTimeval(time, tobj);
1120 if (tobj->tm_got == 0) {
1121 time_get_tm(time, tobj->gmt);
1122 }
1123 return INT2FIX(tobj->tm.tm_wday);
1124 }
1125
1126 static VALUE
1127 time_yday(time)
1128 VALUE time;
1129 {
1130 struct time_object *tobj;
1131
1132 GetTimeval(time, tobj);
1133 if (tobj->tm_got == 0) {
1134 time_get_tm(time, tobj->gmt);
1135 }
1136 return INT2FIX(tobj->tm.tm_yday+1);
1137 }
1138
1139 static VALUE
1140 time_isdst(time)
1141 VALUE time;
1142 {
1143 struct time_object *tobj;
1144
1145 GetTimeval(time, tobj);
1146 if (tobj->tm_got == 0) {
1147 time_get_tm(time, tobj->gmt);
1148 }
1149 return tobj->tm.tm_isdst?Qtrue:Qfalse;
1150 }
1151
1152 static VALUE
1153 time_zone(time)
1154 VALUE time;
1155 {
1156 struct time_object *tobj;
1157 #if !defined(HAVE_TM_ZONE) && (!defined(HAVE_TZNAME) || !defined(HAVE_DAYLIGHT))
1158 char buf[64];
1159 int len;
1160 #endif
1161
1162 GetTimeval(time, tobj);
1163 if (tobj->tm_got == 0) {
1164 time_get_tm(time, tobj->gmt);
1165 }
1166
1167 if (tobj->gmt == 1) {
1168 return rb_str_new2("UTC");
1169 }
1170 #if defined(HAVE_TM_ZONE)
1171 return rb_str_new2(tobj->tm.tm_zone);
1172 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1173 return rb_str_new2(tzname[daylight && tobj->tm.tm_isdst]);
1174 #else
1175 len = strftime(buf, 64, "%Z", &tobj->tm);
1176 return rb_str_new(buf, len);
1177 #endif
1178 }
1179
1180 static VALUE
1181 time_utc_offset(time)
1182 VALUE time;
1183 {
1184 struct time_object *tobj;
1185
1186 GetTimeval(time, tobj);
1187 if (tobj->tm_got == 0) {
1188 time_get_tm(time, tobj->gmt);
1189 }
1190
1191 if (tobj->gmt == 1) {
1192 return INT2FIX(0);
1193 }
1194 else {
1195 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1196 return INT2NUM(tobj->tm.tm_gmtoff);
1197 #else
1198 struct tm *u, *l;
1199 time_t t;
1200 long off;
1201 l = &tobj->tm;
1202 t = tobj->tv.tv_sec;
1203 u = gmtime(&t);
1204 if (!u)
1205 rb_raise(rb_eArgError, "gmtime error");
1206 if (l->tm_year != u->tm_year)
1207 off = l->tm_year < u->tm_year ? -1 : 1;
1208 else if (l->tm_mon != u->tm_mon)
1209 off = l->tm_mon < u->tm_mon ? -1 : 1;
1210 else if (l->tm_mday != u->tm_mday)
1211 off = l->tm_mday < u->tm_mday ? -1 : 1;
1212 else
1213 off = 0;
1214 off = off * 24 + l->tm_hour - u->tm_hour;
1215 off = off * 60 + l->tm_min - u->tm_min;
1216 off = off * 60 + l->tm_sec - u->tm_sec;
1217 return LONG2FIX(off);
1218 #endif
1219 }
1220 }
1221
1222 static VALUE
1223 time_to_a(time)
1224 VALUE time;
1225 {
1226 struct time_object *tobj;
1227
1228 GetTimeval(time, tobj);
1229 if (tobj->tm_got == 0) {
1230 time_get_tm(time, tobj->gmt);
1231 }
1232 return rb_ary_new3(10,
1233 INT2FIX(tobj->tm.tm_sec),
1234 INT2FIX(tobj->tm.tm_min),
1235 INT2FIX(tobj->tm.tm_hour),
1236 INT2FIX(tobj->tm.tm_mday),
1237 INT2FIX(tobj->tm.tm_mon+1),
1238 LONG2NUM((long)tobj->tm.tm_year+1900),
1239 INT2FIX(tobj->tm.tm_wday),
1240 INT2FIX(tobj->tm.tm_yday+1),
1241 tobj->tm.tm_isdst?Qtrue:Qfalse,
1242 time_zone(time));
1243 }
1244
1245 #define SMALLBUF 100
1246 static int
1247 rb_strftime(buf, format, time)
1248 char ** volatile buf;
1249 char * volatile format;
1250 struct tm * volatile time;
1251 {
1252 volatile int size;
1253 int len, flen;
1254
1255 (*buf)[0] = '\0';
1256 flen = strlen(format);
1257 if (flen == 0) {
1258 return 0;
1259 }
1260 len = strftime(*buf, SMALLBUF, format, time);
1261 if (len != 0 || **buf == '\0') return len;
1262 for (size=1024; ; size*=2) {
1263 *buf = xmalloc(size);
1264 (*buf)[0] = '\0';
1265 len = strftime(*buf, size, format, time);
1266
1267
1268
1269
1270
1271
1272
1273 if (len > 0 || size >= 1024 * flen) return len;
1274 free(*buf);
1275 }
1276
1277 }
1278
1279 static VALUE
1280 time_strftime(time, format)
1281 VALUE time, format;
1282 {
1283 struct time_object *tobj;
1284 char buffer[SMALLBUF];
1285 char *fmt, *buf = buffer;
1286 long len;
1287 VALUE str;
1288
1289 GetTimeval(time, tobj);
1290 if (tobj->tm_got == 0) {
1291 time_get_tm(time, tobj->gmt);
1292 }
1293 StringValue(format);
1294 fmt = RSTRING(format)->ptr;
1295 len = RSTRING(format)->len;
1296 if (len == 0) {
1297 rb_warning("strftime called with empty format string");
1298 }
1299 if (strlen(fmt) < len) {
1300
1301 char *p = fmt, *pe = fmt + len;
1302
1303 str = rb_str_new(0, 0);
1304 while (p < pe) {
1305 len = rb_strftime(&buf, p, &tobj->tm);
1306 rb_str_cat(str, buf, len);
1307 p += strlen(p) + 1;
1308 if (p <= pe)
1309 rb_str_cat(str, "\0", 1);
1310 if (buf != buffer) {
1311 free(buf);
1312 buf = buffer;
1313 }
1314 }
1315 return str;
1316 }
1317 len = rb_strftime(&buf, RSTRING(format)->ptr, &tobj->tm);
1318 str = rb_str_new(buf, len);
1319 if (buf != buffer) free(buf);
1320 return str;
1321 }
1322
1323 static VALUE
1324 time_s_times(obj)
1325 VALUE obj;
1326 {
1327 rb_warn("obsolete method Time::times; use Process::times");
1328 return rb_proc_times(obj);
1329 }
1330
1331 static VALUE
1332 time_dump(argc, argv, time)
1333 int argc;
1334 VALUE *argv;
1335 VALUE time;
1336 {
1337 VALUE dummy;
1338 struct time_object *tobj;
1339 struct tm *tm;
1340 unsigned long p, s;
1341 unsigned char buf[8];
1342 time_t t;
1343 int i;
1344
1345 rb_scan_args(argc, argv, "01", &dummy);
1346 GetTimeval(time, tobj);
1347
1348 t = tobj->tv.tv_sec;
1349 tm = gmtime(&t);
1350
1351 if ((tm->tm_year & 0x1ffff) != tm->tm_year)
1352 rb_raise(rb_eArgError, "too big year to marshal");
1353
1354 p = 0x1 << 31 |
1355 tm->tm_year << 14 |
1356 tm->tm_mon << 10 |
1357 tm->tm_mday << 5 |
1358 tm->tm_hour;
1359 s = tm->tm_min << 26 |
1360 tm->tm_sec << 20 |
1361 tobj->tv.tv_usec;
1362
1363 for (i=0; i<4; i++) {
1364 buf[i] = p & 0xff;
1365 p = RSHIFT(p, 8);
1366 }
1367 for (i=4; i<8; i++) {
1368 buf[i] = s & 0xff;
1369 s = RSHIFT(s, 8);
1370 }
1371
1372 return rb_str_new(buf, 8);
1373 }
1374
1375 static VALUE
1376 time_load(klass, str)
1377 VALUE klass, str;
1378 {
1379 unsigned long p, s;
1380 time_t sec, usec;
1381 unsigned char *buf;
1382 struct tm tm;
1383 int i;
1384
1385 StringValue(str);
1386 buf = (unsigned char *)RSTRING(str)->ptr;
1387 if (RSTRING(str)->len != 8) {
1388 rb_raise(rb_eTypeError, "marshaled time format differ");
1389 }
1390
1391 p = s = 0;
1392 for (i=0; i<4; i++) {
1393 p |= buf[i]<<(8*i);
1394 }
1395 for (i=4; i<8; i++) {
1396 s |= buf[i]<<(8*(i-4));
1397 }
1398
1399 if ((p & (1<<31)) == 0) {
1400 return time_new_internal(klass, p, s);
1401 }
1402 p &= ~(1<<31);
1403 tm.tm_year = (p >> 14) & 0x1ffff;
1404 tm.tm_mon = (p >> 10) & 0xf;
1405 tm.tm_mday = (p >> 5) & 0x1f;
1406 tm.tm_hour = p & 0x1f;
1407 tm.tm_min = (s >> 26) & 0x3f;
1408 tm.tm_sec = (s >> 20) & 0x3f;
1409 tm.tm_isdst = 0;
1410
1411 sec = make_time_t(&tm, Qtrue);
1412 usec = (time_t)(s & 0xfffff);
1413
1414 return time_new_internal(klass, sec, usec);
1415 }
1416
1417 void
1418 Init_Time()
1419 {
1420 rb_cTime = rb_define_class("Time", rb_cObject);
1421 rb_include_module(rb_cTime, rb_mComparable);
1422
1423 rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
1424 rb_define_singleton_method(rb_cTime, "allocate", time_s_alloc, 0);
1425 rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
1426 rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
1427 rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
1428 rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
1429 rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
1430
1431 rb_define_singleton_method(rb_cTime, "times", time_s_times, 0);
1432
1433 rb_define_method(rb_cTime, "to_i", time_to_i, 0);
1434 rb_define_method(rb_cTime, "to_f", time_to_f, 0);
1435 rb_define_method(rb_cTime, "<=>", time_cmp, 1);
1436 rb_define_method(rb_cTime, "eql?", time_eql, 1);
1437 rb_define_method(rb_cTime, "hash", time_hash, 0);
1438 rb_define_method(rb_cTime, "become", time_become, 1);
1439
1440 rb_define_method(rb_cTime, "localtime", time_localtime, 0);
1441 rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
1442 rb_define_method(rb_cTime, "utc", time_gmtime, 0);
1443 rb_define_method(rb_cTime, "getlocal", time_getlocaltime, 0);
1444 rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
1445 rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
1446
1447 rb_define_method(rb_cTime, "ctime", time_asctime, 0);
1448 rb_define_method(rb_cTime, "asctime", time_asctime, 0);
1449 rb_define_method(rb_cTime, "to_s", time_to_s, 0);
1450 rb_define_method(rb_cTime, "inspect", time_to_s, 0);
1451 rb_define_method(rb_cTime, "to_a", time_to_a, 0);
1452
1453 rb_define_method(rb_cTime, "+", time_plus, 1);
1454 rb_define_method(rb_cTime, "-", time_minus, 1);
1455
1456 rb_define_method(rb_cTime, "sec", time_sec, 0);
1457 rb_define_method(rb_cTime, "min", time_min, 0);
1458 rb_define_method(rb_cTime, "hour", time_hour, 0);
1459 rb_define_method(rb_cTime, "mday", time_mday, 0);
1460 rb_define_method(rb_cTime, "day", time_mday, 0);
1461 rb_define_method(rb_cTime, "mon", time_mon, 0);
1462 rb_define_method(rb_cTime, "month", time_mon, 0);
1463 rb_define_method(rb_cTime, "year", time_year, 0);
1464 rb_define_method(rb_cTime, "wday", time_wday, 0);
1465 rb_define_method(rb_cTime, "yday", time_yday, 0);
1466 rb_define_method(rb_cTime, "isdst", time_isdst, 0);
1467 rb_define_method(rb_cTime, "dst?", time_isdst, 0);
1468 rb_define_method(rb_cTime, "zone", time_zone, 0);
1469 rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
1470 rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
1471 rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
1472
1473 rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
1474 rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
1475
1476 rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
1477 rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
1478 rb_define_method(rb_cTime, "usec", time_usec, 0);
1479
1480 rb_define_method(rb_cTime, "strftime", time_strftime, 1);
1481
1482
1483 rb_define_method(rb_cTime, "_dump", time_dump, -1);
1484 rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
1485 }