00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "ruby.h"
00014 #include <sys/types.h>
00015 #include <time.h>
00016
00017 #ifdef HAVE_UNISTD_H
00018 #include <unistd.h>
00019 #endif
00020
00021 #include <math.h>
00022
00023 VALUE rb_cTime;
00024
00025 struct time_object {
00026 struct timeval tv;
00027 struct tm tm;
00028 int gmt;
00029 int tm_got;
00030 };
00031
00032 #define GetTimeval(obj, tobj) \
00033 Data_Get_Struct(obj, struct time_object, tobj)
00034
00035 static void time_free (void *);
00036
00037 static void
00038 time_free(tobj)
00039 void *tobj;
00040 {
00041 if (tobj) free(tobj);
00042 }
00043
00044 static VALUE time_s_alloc (VALUE);
00045 static VALUE
00046 time_s_alloc(klass)
00047 VALUE klass;
00048 {
00049 VALUE obj;
00050 struct time_object *tobj;
00051
00052 obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
00053 tobj->tm_got=0;
00054 tobj->tv.tv_sec = 0;
00055 tobj->tv.tv_usec = 0;
00056
00057 return obj;
00058 }
00059
00060 static void
00061 time_modify(time)
00062 VALUE time;
00063 {
00064 rb_check_frozen(time);
00065 if (!OBJ_TAINTED(time) && rb_safe_level() >= 4)
00066 rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
00067 }
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 static VALUE
00092 time_init(time)
00093 VALUE time;
00094 {
00095 struct time_object *tobj;
00096
00097 time_modify(time);
00098 GetTimeval(time, tobj);
00099 tobj->tm_got=0;
00100 tobj->tv.tv_sec = 0;
00101 tobj->tv.tv_usec = 0;
00102 if (gettimeofday(&tobj->tv, 0) < 0) {
00103 rb_sys_fail("gettimeofday");
00104 }
00105
00106 return time;
00107 }
00108
00109 #define NDIV(x,y) (-(-((x)+1)/(y))-1)
00110 #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
00111
00112 static void
00113 time_overflow_p(secp, usecp)
00114 time_t *secp, *usecp;
00115 {
00116 time_t tmp, sec = *secp, usec = *usecp;
00117
00118 if (usec >= 1000000) {
00119 tmp = sec + usec / 1000000;
00120 usec %= 1000000;
00121 if (sec > 0 && tmp < 0) {
00122 rb_raise(rb_eRangeError, "out of Time range");
00123 }
00124 sec = tmp;
00125 }
00126 if (usec < 0) {
00127 tmp = sec + NDIV(usec,1000000);
00128 usec = NMOD(usec,1000000);
00129 if (sec < 0 && tmp > 0) {
00130 rb_raise(rb_eRangeError, "out of Time range");
00131 }
00132 sec = tmp;
00133 }
00134 #ifndef NEGATIVE_TIME_T
00135 if (sec < 0 || (sec == 0 && usec < 0))
00136 rb_raise(rb_eArgError, "time must be positive");
00137 #endif
00138 *secp = sec;
00139 *usecp = usec;
00140 }
00141
00142 static VALUE
00143 time_new_internal(klass, sec, usec)
00144 VALUE klass;
00145 time_t sec, usec;
00146 {
00147 VALUE time = time_s_alloc(klass);
00148 struct time_object *tobj;
00149
00150 GetTimeval(time, tobj);
00151 time_overflow_p(&sec, &usec);
00152 tobj->tv.tv_sec = sec;
00153 tobj->tv.tv_usec = usec;
00154
00155 return time;
00156 }
00157
00158 VALUE
00159 rb_time_new(sec, usec)
00160 time_t sec, usec;
00161 {
00162 return time_new_internal(rb_cTime, sec, usec);
00163 }
00164
00165 static struct timeval
00166 time_timeval(time, interval)
00167 VALUE time;
00168 int interval;
00169 {
00170 struct timeval t;
00171 char *tstr = interval ? "time interval" : "time";
00172
00173 #ifndef NEGATIVE_TIME_T
00174 interval = 1;
00175 #endif
00176
00177 switch (TYPE(time)) {
00178 case T_FIXNUM:
00179 t.tv_sec = FIX2LONG(time);
00180 if (interval && t.tv_sec < 0)
00181 rb_raise(rb_eArgError, "%s must be positive", tstr);
00182 t.tv_usec = 0;
00183 break;
00184
00185 case T_FLOAT:
00186 if (interval && RFLOAT(time)->value < 0.0)
00187 rb_raise(rb_eArgError, "%s must be positive", tstr);
00188 else {
00189 double f, d;
00190
00191 d = modf(RFLOAT(time)->value, &f);
00192 t.tv_sec = (time_t)f;
00193 if (f != t.tv_sec) {
00194 rb_raise(rb_eRangeError, "%f out of Time range", RFLOAT(time)->value);
00195 }
00196 t.tv_usec = (time_t)(d*1e6);
00197 }
00198 break;
00199
00200 case T_BIGNUM:
00201 t.tv_sec = NUM2LONG(time);
00202 if (interval && t.tv_sec < 0)
00203 rb_raise(rb_eArgError, "%s must be positive", tstr);
00204 t.tv_usec = 0;
00205 break;
00206
00207 default:
00208 rb_raise(rb_eTypeError, "can't convert %s into %s",
00209 rb_obj_classname(time), tstr);
00210 break;
00211 }
00212 return t;
00213 }
00214
00215 struct timeval
00216 rb_time_interval(time)
00217 VALUE time;
00218 {
00219 return time_timeval(time, Qtrue);
00220 }
00221
00222 struct timeval
00223 rb_time_timeval(time)
00224 VALUE time;
00225 {
00226 struct time_object *tobj;
00227 struct timeval t;
00228
00229 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
00230 GetTimeval(time, tobj);
00231 t = tobj->tv;
00232 return t;
00233 }
00234 return time_timeval(time, Qfalse);
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 static VALUE
00253 time_s_at(argc, argv, klass)
00254 int argc;
00255 VALUE *argv;
00256 VALUE klass;
00257 {
00258 struct timeval tv;
00259 VALUE time, t;
00260
00261 if (rb_scan_args(argc, argv, "11", &time, &t) == 2) {
00262 tv.tv_sec = NUM2LONG(time);
00263 tv.tv_usec = NUM2LONG(t);
00264 }
00265 else {
00266 tv = rb_time_timeval(time);
00267 }
00268 t = time_new_internal(klass, tv.tv_sec, tv.tv_usec);
00269 if (TYPE(time) == T_DATA && RDATA(time)->dfree == time_free) {
00270 struct time_object *tobj, *tobj2;
00271
00272 GetTimeval(time, tobj);
00273 GetTimeval(t, tobj2);
00274 tobj2->gmt = tobj->gmt;
00275 }
00276 return t;
00277 }
00278
00279 static char *months [12] = {
00280 "jan", "feb", "mar", "apr", "may", "jun",
00281 "jul", "aug", "sep", "oct", "nov", "dec",
00282 };
00283
00284 static long
00285 obj2long(obj)
00286 VALUE obj;
00287 {
00288 if (TYPE(obj) == T_STRING) {
00289 obj = rb_str_to_inum(obj, 10, Qfalse);
00290 }
00291
00292 return NUM2LONG(obj);
00293 }
00294
00295 static void
00296 time_arg(argc, argv, tm, usec)
00297 int argc;
00298 VALUE *argv;
00299 struct tm *tm;
00300 time_t *usec;
00301 {
00302 VALUE v[8];
00303 int i;
00304 long year;
00305
00306 MEMZERO(tm, struct tm, 1);
00307 *usec = 0;
00308 if (argc == 10) {
00309 v[0] = argv[5];
00310 v[1] = argv[4];
00311 v[2] = argv[3];
00312 v[3] = argv[2];
00313 v[4] = argv[1];
00314 v[5] = argv[0];
00315 v[6] = Qnil;
00316 tm->tm_isdst = RTEST(argv[8]) ? 1 : 0;
00317 }
00318 else {
00319 rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
00320
00321
00322 tm->tm_wday = -1;
00323 tm->tm_isdst = -1;
00324 }
00325
00326 year = obj2long(v[0]);
00327
00328 if (0 <= year && year < 39) {
00329 year += 100;
00330 rb_warning("2 digits year is used");
00331 }
00332 else if (69 <= year && year < 139) {
00333 rb_warning("2 or 3 digits year is used");
00334 }
00335 else {
00336 year -= 1900;
00337 }
00338
00339 tm->tm_year = year;
00340
00341 if (NIL_P(v[1])) {
00342 tm->tm_mon = 0;
00343 }
00344 else {
00345 VALUE s = rb_check_string_type(v[1]);
00346 if (!NIL_P(s)) {
00347 tm->tm_mon = -1;
00348 for (i=0; i<12; i++) {
00349 if (RSTRING(s)->len == 3 &&
00350 strcasecmp(months[i], RSTRING(v[1])->ptr) == 0) {
00351 tm->tm_mon = i;
00352 break;
00353 }
00354 }
00355 if (tm->tm_mon == -1) {
00356 char c = RSTRING(s)->ptr[0];
00357
00358 if ('0' <= c && c <= '9') {
00359 tm->tm_mon = obj2long(s)-1;
00360 }
00361 }
00362 }
00363 else {
00364 tm->tm_mon = obj2long(v[1])-1;
00365 }
00366 }
00367 if (NIL_P(v[2])) {
00368 tm->tm_mday = 1;
00369 }
00370 else {
00371 tm->tm_mday = obj2long(v[2]);
00372 }
00373 tm->tm_hour = NIL_P(v[3])?0:obj2long(v[3]);
00374 tm->tm_min = NIL_P(v[4])?0:obj2long(v[4]);
00375 tm->tm_sec = NIL_P(v[5])?0:obj2long(v[5]);
00376 if (!NIL_P(v[6])) {
00377 if (argc == 8) {
00378
00379 }
00380 else if (argc == 7) {
00381 *usec = obj2long(v[6]);
00382 }
00383 }
00384
00385
00386 if (
00387 tm->tm_year != year ||
00388 #ifndef NEGATIVE_TIME_T
00389 tm->tm_year < 69 ||
00390 #endif
00391 tm->tm_mon < 0 || tm->tm_mon > 11
00392 || tm->tm_mday < 1 || tm->tm_mday > 31
00393 || tm->tm_hour < 0 || tm->tm_hour > 23
00394 || tm->tm_min < 0 || tm->tm_min > 59
00395 || tm->tm_sec < 0 || tm->tm_sec > 60)
00396 rb_raise(rb_eArgError, "argument out of range");
00397 }
00398
00399 static VALUE time_gmtime (VALUE);
00400 static VALUE time_localtime (VALUE);
00401 static VALUE time_get_tm (VALUE, int);
00402
00403 static int
00404 leap_year_p(y)
00405 long y;
00406 {
00407 return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
00408 }
00409
00410 #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
00411
00412 static time_t
00413 timegm_noleapsecond(tm)
00414 struct tm *tm;
00415 {
00416 static int common_year_yday_offset[] = {
00417 -1,
00418 -1 + 31,
00419 -1 + 31 + 28,
00420 -1 + 31 + 28 + 31,
00421 -1 + 31 + 28 + 31 + 30,
00422 -1 + 31 + 28 + 31 + 30 + 31,
00423 -1 + 31 + 28 + 31 + 30 + 31 + 30,
00424 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
00425 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
00426 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00427 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00428 -1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00429
00430 };
00431 static int leap_year_yday_offset[] = {
00432 -1,
00433 -1 + 31,
00434 -1 + 31 + 29,
00435 -1 + 31 + 29 + 31,
00436 -1 + 31 + 29 + 31 + 30,
00437 -1 + 31 + 29 + 31 + 30 + 31,
00438 -1 + 31 + 29 + 31 + 30 + 31 + 30,
00439 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
00440 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
00441 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
00442 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
00443 -1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
00444
00445 };
00446
00447 long tm_year = tm->tm_year;
00448 int tm_yday = tm->tm_mday;
00449 if (leap_year_p(tm_year + 1900))
00450 tm_yday += leap_year_yday_offset[tm->tm_mon];
00451 else
00452 tm_yday += common_year_yday_offset[tm->tm_mon];
00453
00454
00455
00456
00457
00458
00459
00460 return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
00461 (time_t)(tm_yday +
00462 (tm_year-70)*365 +
00463 DIV(tm_year-69,4) -
00464 DIV(tm_year-1,100) +
00465 DIV(tm_year+299,400))*86400;
00466 }
00467
00468 static int
00469 tmcmp(a, b)
00470 struct tm *a;
00471 struct tm *b;
00472 {
00473 if (a->tm_year != b->tm_year)
00474 return a->tm_year < b->tm_year ? -1 : 1;
00475 else if (a->tm_mon != b->tm_mon)
00476 return a->tm_mon < b->tm_mon ? -1 : 1;
00477 else if (a->tm_mday != b->tm_mday)
00478 return a->tm_mday < b->tm_mday ? -1 : 1;
00479 else if (a->tm_hour != b->tm_hour)
00480 return a->tm_hour < b->tm_hour ? -1 : 1;
00481 else if (a->tm_min != b->tm_min)
00482 return a->tm_min < b->tm_min ? -1 : 1;
00483 else if (a->tm_sec != b->tm_sec)
00484 return a->tm_sec < b->tm_sec ? -1 : 1;
00485 else
00486 return 0;
00487 }
00488
00489 static time_t
00490 search_time_t(tptr, utc_p)
00491 struct tm *tptr;
00492 int utc_p;
00493 {
00494 time_t guess, guess_lo, guess_hi;
00495 struct tm *tm, tm_lo, tm_hi;
00496 int d, have_guess;
00497 int find_dst;
00498
00499 find_dst = 0 < tptr->tm_isdst;
00500
00501 #ifdef NEGATIVE_TIME_T
00502 guess_lo = 1L << (8 * sizeof(time_t) - 1);
00503 #else
00504 guess_lo = 0;
00505 #endif
00506 guess_hi = ((time_t)-1) < ((time_t)0) ?
00507 (1UL << (8 * sizeof(time_t) - 1)) - 1 :
00508 ~(time_t)0;
00509
00510 guess = timegm_noleapsecond(tptr);
00511 tm = (utc_p ? gmtime : localtime)(&guess);
00512 if (tm) {
00513 d = tmcmp(tptr, tm);
00514 if (d == 0) return guess;
00515 if (d < 0) {
00516 guess_hi = guess;
00517 guess -= 24 * 60 * 60;
00518 }
00519 else {
00520 guess_lo = guess;
00521 guess += 24 * 60 * 60;
00522 }
00523 if (guess_lo < guess && guess < guess_hi &&
00524 (tm = (utc_p ? gmtime : localtime)(&guess)) != NULL) {
00525 d = tmcmp(tptr, tm);
00526 if (d == 0) return guess;
00527 if (d < 0)
00528 guess_hi = guess;
00529 else
00530 guess_lo = guess;
00531 }
00532 }
00533
00534 tm = (utc_p ? gmtime : localtime)(&guess_lo);
00535 if (!tm) goto error;
00536 d = tmcmp(tptr, tm);
00537 if (d < 0) goto out_of_range;
00538 if (d == 0) return guess_lo;
00539 tm_lo = *tm;
00540
00541 tm = (utc_p ? gmtime : localtime)(&guess_hi);
00542 if (!tm) goto error;
00543 d = tmcmp(tptr, tm);
00544 if (d > 0) goto out_of_range;
00545 if (d == 0) return guess_hi;
00546 tm_hi = *tm;
00547
00548 have_guess = 0;
00549
00550 while (guess_lo + 1 < guess_hi) {
00551
00552 unsigned long range = 0;
00553 if (!have_guess) {
00554 int a, b;
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 range = 366 * 24 * 60 * 60;
00577 a = (tm_hi.tm_year - tptr->tm_year);
00578 b = (tptr->tm_year - tm_lo.tm_year);
00579
00580 if (a + b <= 46000 / 12) {
00581 range = 31 * 24 * 60 * 60;
00582 a *= 12;
00583 b *= 12;
00584 a += tm_hi.tm_mon - tptr->tm_mon;
00585 b += tptr->tm_mon - tm_lo.tm_mon;
00586 if (a + b <= 46000 / 31) {
00587 range = 24 * 60 * 60;
00588 a *= 31;
00589 b *= 31;
00590 a += tm_hi.tm_mday - tptr->tm_mday;
00591 b += tptr->tm_mday - tm_lo.tm_mday;
00592 if (a + b <= 46000 / 24) {
00593 range = 60 * 60;
00594 a *= 24;
00595 b *= 24;
00596 a += tm_hi.tm_hour - tptr->tm_hour;
00597 b += tptr->tm_hour - tm_lo.tm_hour;
00598 if (a + b <= 46000 / 60) {
00599 range = 60;
00600 a *= 60;
00601 b *= 60;
00602 a += tm_hi.tm_min - tptr->tm_min;
00603 b += tptr->tm_min - tm_lo.tm_min;
00604 if (a + b <= 46000 / 60) {
00605 range = 1;
00606 a *= 60;
00607 b *= 60;
00608 a += tm_hi.tm_sec - tptr->tm_sec;
00609 b += tptr->tm_sec - tm_lo.tm_sec;
00610 }
00611 }
00612 }
00613 }
00614 }
00615 if (a <= 0) a = 1;
00616 if (b <= 0) b = 1;
00617 d = a + b;
00618
00619
00620
00621
00622
00623 guess = guess_lo / d * a + (guess_lo % d) * a / d
00624 + guess_hi / d * b + (guess_hi % d) * b / d;
00625 have_guess = 1;
00626 }
00627
00628 if (guess <= guess_lo || guess_hi <= guess) {
00629
00630 guess = guess_lo / 2 + guess_hi / 2;
00631 if (guess <= guess_lo)
00632 guess = guess_lo + 1;
00633 else if (guess >= guess_hi)
00634 guess = guess_hi - 1;
00635 range = 0;
00636 }
00637
00638 tm = (utc_p ? gmtime : localtime)(&guess);
00639 if (!tm) goto error;
00640 have_guess = 0;
00641
00642 d = tmcmp(tptr, tm);
00643 if (d < 0) {
00644 guess_hi = guess;
00645 tm_hi = *tm;
00646 if (range) {
00647 guess = guess - range;
00648 range = 0;
00649 if (guess_lo < guess && guess < guess_hi)
00650 have_guess = 1;
00651 }
00652 }
00653 else if (d > 0) {
00654 guess_lo = guess;
00655 tm_lo = *tm;
00656 if (range) {
00657 guess = guess + range;
00658 range = 0;
00659 if (guess_lo < guess && guess < guess_hi)
00660 have_guess = 1;
00661 }
00662 }
00663 else {
00664 if (!utc_p) {
00665
00666 time_t guess2;
00667 if (find_dst) {
00668 guess2 = guess - 2 * 60 * 60;
00669 tm = localtime(&guess2);
00670 if (tm) {
00671 if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
00672 tptr->tm_min != tm->tm_min ||
00673 tptr->tm_sec != tm->tm_sec) {
00674 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
00675 (tm->tm_min - tptr->tm_min) * 60 +
00676 (tm->tm_sec - tptr->tm_sec);
00677 if (tptr->tm_mday != tm->tm_mday)
00678 guess2 += 24 * 60 * 60;
00679 if (guess != guess2) {
00680 tm = localtime(&guess2);
00681 if (tmcmp(tptr, tm) == 0) {
00682 if (guess < guess2)
00683 return guess;
00684 else
00685 return guess2;
00686 }
00687 }
00688 }
00689 }
00690 }
00691 else {
00692 guess2 = guess + 2 * 60 * 60;
00693 tm = localtime(&guess2);
00694 if (tm) {
00695 if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
00696 tptr->tm_min != tm->tm_min ||
00697 tptr->tm_sec != tm->tm_sec) {
00698 guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
00699 (tm->tm_min - tptr->tm_min) * 60 +
00700 (tm->tm_sec - tptr->tm_sec);
00701 if (tptr->tm_mday != tm->tm_mday)
00702 guess2 -= 24 * 60 * 60;
00703 if (guess != guess2) {
00704 tm = localtime(&guess2);
00705 if (tmcmp(tptr, tm) == 0) {
00706 if (guess < guess2)
00707 return guess2;
00708 else
00709 return guess;
00710 }
00711 }
00712 }
00713 }
00714 }
00715 }
00716 return guess;
00717 }
00718 }
00719
00720 if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) {
00721 return guess_lo +
00722 (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 +
00723 (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 +
00724 (tptr->tm_min - tm_lo.tm_min) * 60 +
00725 (tptr->tm_sec - tm_lo.tm_sec);
00726 }
00727 else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
00728 return guess_hi +
00729 (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
00730 (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
00731 (tptr->tm_min - tm_hi.tm_min) * 60 +
00732 (tptr->tm_sec - tm_hi.tm_sec);
00733 }
00734
00735 out_of_range:
00736 rb_raise(rb_eArgError, "time out of range");
00737
00738 error:
00739 rb_raise(rb_eArgError, "gmtime/localtime error");
00740 return 0;
00741 }
00742
00743 static time_t
00744 make_time_t(tptr, utc_p)
00745 struct tm *tptr;
00746 int utc_p;
00747 {
00748 time_t t;
00749 struct tm *tmp, buf;
00750 buf = *tptr;
00751 if (utc_p) {
00752 #if defined(HAVE_TIMEGM)
00753 if ((t = timegm(&buf)) != -1)
00754 return t;
00755 #ifdef NEGATIVE_TIME_T
00756 if ((tmp = gmtime(&t)) &&
00757 tptr->tm_year == tmp->tm_year &&
00758 tptr->tm_mon == tmp->tm_mon &&
00759 tptr->tm_mday == tmp->tm_mday &&
00760 tptr->tm_hour == tmp->tm_hour &&
00761 tptr->tm_min == tmp->tm_min &&
00762 tptr->tm_sec == tmp->tm_sec)
00763 return t;
00764 #endif
00765 #endif
00766 return search_time_t(&buf, utc_p);
00767 }
00768 else {
00769 #if defined(HAVE_MKTIME)
00770 if ((t = mktime(&buf)) != -1)
00771 return t;
00772 #ifdef NEGATIVE_TIME_T
00773 if ((tmp = localtime(&t)) &&
00774 tptr->tm_year == tmp->tm_year &&
00775 tptr->tm_mon == tmp->tm_mon &&
00776 tptr->tm_mday == tmp->tm_mday &&
00777 tptr->tm_hour == tmp->tm_hour &&
00778 tptr->tm_min == tmp->tm_min &&
00779 tptr->tm_sec == tmp->tm_sec)
00780 return t;
00781 #endif
00782 #endif
00783 return search_time_t(&buf, utc_p);
00784 }
00785 }
00786
00787 static VALUE
00788 time_utc_or_local(argc, argv, utc_p, klass)
00789 int argc;
00790 VALUE *argv;
00791 int utc_p;
00792 VALUE klass;
00793 {
00794 struct tm tm;
00795 VALUE time;
00796 time_t usec;
00797
00798 time_arg(argc, argv, &tm, &usec);
00799 time = time_new_internal(klass, make_time_t(&tm, utc_p), usec);
00800 if (utc_p) return time_gmtime(time);
00801 return time_localtime(time);
00802 }
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825 static VALUE
00826 time_s_mkutc(argc, argv, klass)
00827 int argc;
00828 VALUE *argv;
00829 VALUE klass;
00830 {
00831 return time_utc_or_local(argc, argv, Qtrue, klass);
00832 }
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 static VALUE
00848 time_s_mktime(argc, argv, klass)
00849 int argc;
00850 VALUE *argv;
00851 VALUE klass;
00852 {
00853 return time_utc_or_local(argc, argv, Qfalse, klass);
00854 }
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 static VALUE
00870 time_to_i(time)
00871 VALUE time;
00872 {
00873 struct time_object *tobj;
00874
00875 GetTimeval(time, tobj);
00876 return LONG2NUM(tobj->tv.tv_sec);
00877 }
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 static VALUE
00892 time_to_f(time)
00893 VALUE time;
00894 {
00895 struct time_object *tobj;
00896
00897 GetTimeval(time, tobj);
00898 return rb_float_new((double)tobj->tv.tv_sec+(double)tobj->tv.tv_usec/1e6);
00899 }
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913 static VALUE
00914 time_usec(time)
00915 VALUE time;
00916 {
00917 struct time_object *tobj;
00918
00919 GetTimeval(time, tobj);
00920 return LONG2NUM(tobj->tv.tv_usec);
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939 static VALUE
00940 time_cmp(time1, time2)
00941 VALUE time1, time2;
00942 {
00943 struct time_object *tobj1, *tobj2;
00944
00945 GetTimeval(time1, tobj1);
00946 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
00947 GetTimeval(time2, tobj2);
00948 if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) {
00949 if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return INT2FIX(0);
00950 if (tobj1->tv.tv_usec > tobj2->tv.tv_usec) return INT2FIX(1);
00951 return INT2FIX(-1);
00952 }
00953 if (tobj1->tv.tv_sec > tobj2->tv.tv_sec) return INT2FIX(1);
00954 return INT2FIX(-1);
00955 }
00956
00957 return Qnil;
00958 }
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969 static VALUE
00970 time_eql(time1, time2)
00971 VALUE time1, time2;
00972 {
00973 struct time_object *tobj1, *tobj2;
00974
00975 GetTimeval(time1, tobj1);
00976 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
00977 GetTimeval(time2, tobj2);
00978 if (tobj1->tv.tv_sec == tobj2->tv.tv_sec) {
00979 if (tobj1->tv.tv_usec == tobj2->tv.tv_usec) return Qtrue;
00980 }
00981 }
00982 return Qfalse;
00983 }
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004 static VALUE
01005 time_utc_p(time)
01006 VALUE time;
01007 {
01008 struct time_object *tobj;
01009
01010 GetTimeval(time, tobj);
01011 if (tobj->gmt) return Qtrue;
01012 return Qfalse;
01013 }
01014
01015
01016
01017
01018
01019
01020
01021
01022 static VALUE
01023 time_hash(time)
01024 VALUE time;
01025 {
01026 struct time_object *tobj;
01027 long hash;
01028
01029 GetTimeval(time, tobj);
01030 hash = tobj->tv.tv_sec ^ tobj->tv.tv_usec;
01031 return LONG2FIX(hash);
01032 }
01033
01034
01035 static VALUE
01036 time_init_copy(copy, time)
01037 VALUE copy, time;
01038 {
01039 struct time_object *tobj, *tcopy;
01040
01041 if (copy == time) return copy;
01042 time_modify(copy);
01043 if (TYPE(time) != T_DATA || RDATA(time)->dfree != time_free) {
01044 rb_raise(rb_eTypeError, "wrong argument type");
01045 }
01046 GetTimeval(time, tobj);
01047 GetTimeval(copy, tcopy);
01048 MEMCPY(tcopy, tobj, struct time_object, 1);
01049
01050 return copy;
01051 }
01052
01053 static VALUE
01054 time_dup(time)
01055 VALUE time;
01056 {
01057 VALUE dup = time_s_alloc(rb_cTime);
01058 time_init_copy(dup, time);
01059 return dup;
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 static VALUE
01076 time_localtime(time)
01077 VALUE time;
01078 {
01079 struct time_object *tobj;
01080 struct tm *tm_tmp;
01081 time_t t;
01082
01083 GetTimeval(time, tobj);
01084 if (!tobj->gmt) {
01085 if (tobj->tm_got)
01086 return time;
01087 }
01088 else {
01089 time_modify(time);
01090 }
01091 t = tobj->tv.tv_sec;
01092 tm_tmp = localtime(&t);
01093 if (!tm_tmp)
01094 rb_raise(rb_eArgError, "localtime error");
01095 tobj->tm = *tm_tmp;
01096 tobj->tm_got = 1;
01097 tobj->gmt = 0;
01098 return time;
01099 }
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119 static VALUE
01120 time_gmtime(time)
01121 VALUE time;
01122 {
01123 struct time_object *tobj;
01124 struct tm *tm_tmp;
01125 time_t t;
01126
01127 GetTimeval(time, tobj);
01128 if (tobj->gmt) {
01129 if (tobj->tm_got)
01130 return time;
01131 }
01132 else {
01133 time_modify(time);
01134 }
01135 t = tobj->tv.tv_sec;
01136 tm_tmp = gmtime(&t);
01137 if (!tm_tmp)
01138 rb_raise(rb_eArgError, "gmtime error");
01139 tobj->tm = *tm_tmp;
01140 tobj->tm_got = 1;
01141 tobj->gmt = 1;
01142 return time;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 static VALUE
01160 time_getlocaltime(time)
01161 VALUE time;
01162 {
01163 return time_localtime(time_dup(time));
01164 }
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181 static VALUE
01182 time_getgmtime(time)
01183 VALUE time;
01184 {
01185 return time_gmtime(time_dup(time));
01186 }
01187
01188 static VALUE
01189 time_get_tm(time, gmt)
01190 VALUE time;
01191 int gmt;
01192 {
01193 if (gmt) return time_gmtime(time);
01194 return time_localtime(time);
01195 }
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207 static VALUE
01208 time_asctime(time)
01209 VALUE time;
01210 {
01211 struct time_object *tobj;
01212 char *s;
01213
01214 GetTimeval(time, tobj);
01215 if (tobj->tm_got == 0) {
01216 time_get_tm(time, tobj->gmt);
01217 }
01218 s = asctime(&tobj->tm);
01219 if (s[24] == '\n') s[24] = '\0';
01220
01221 return rb_str_new2(s);
01222 }
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237 static VALUE
01238 time_to_s(time)
01239 VALUE time;
01240 {
01241 struct time_object *tobj;
01242 char buf[128];
01243 int len;
01244
01245 GetTimeval(time, tobj);
01246 if (tobj->tm_got == 0) {
01247 time_get_tm(time, tobj->gmt);
01248 }
01249 if (tobj->gmt == 1) {
01250 len = strftime(buf, 128, "%a %b %d %H:%M:%S UTC %Y", &tobj->tm);
01251 }
01252 else {
01253 len = strftime(buf, 128, "%a %b %d %H:%M:%S %Z %Y", &tobj->tm);
01254 }
01255 return rb_str_new(buf, len);
01256 }
01257
01258 #if SIZEOF_TIME_T == SIZEOF_LONG
01259 typedef unsigned long unsigned_time_t;
01260 #elif SIZEOF_TIME_T == SIZEOF_INT
01261 typedef unsigned int unsigned_time_t;
01262 #elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
01263 typedef unsigned LONG_LONG unsigned_time_t;
01264 #else
01265 # error cannot find integer type which size is same as time_t.
01266 #endif
01267
01268 static VALUE
01269 time_add(tobj, offset, sign)
01270 struct time_object *tobj;
01271 VALUE offset;
01272 int sign;
01273 {
01274 double v = NUM2DBL(offset);
01275 double f, d;
01276 unsigned_time_t sec_off;
01277 time_t usec_off, sec, usec;
01278 VALUE result;
01279
01280 if (v < 0) {
01281 v = -v;
01282 sign = -sign;
01283 }
01284 d = modf(v, &f);
01285 sec_off = (unsigned_time_t)f;
01286 if (f != (double)sec_off)
01287 rb_raise(rb_eRangeError, "time %s %f out of Time range",
01288 sign < 0 ? "-" : "+", v);
01289 usec_off = (time_t)(d*1e6);
01290
01291 if (sign < 0) {
01292 sec = tobj->tv.tv_sec - sec_off;
01293 usec = tobj->tv.tv_usec - usec_off;
01294 if (sec > tobj->tv.tv_sec)
01295 rb_raise(rb_eRangeError, "time - %f out of Time range", v);
01296 }
01297 else {
01298 sec = tobj->tv.tv_sec + sec_off;
01299 usec = tobj->tv.tv_usec + usec_off;
01300 if (sec < tobj->tv.tv_sec)
01301 rb_raise(rb_eRangeError, "time + %f out of Time range", v);
01302 }
01303 result = rb_time_new(sec, usec);
01304 if (tobj->gmt) {
01305 GetTimeval(result, tobj);
01306 tobj->gmt = 1;
01307 }
01308 return result;
01309 }
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322 static VALUE
01323 time_plus(time1, time2)
01324 VALUE time1, time2;
01325 {
01326 struct time_object *tobj;
01327 GetTimeval(time1, tobj);
01328
01329 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
01330 rb_raise(rb_eTypeError, "time + time?");
01331 }
01332 return time_add(tobj, time2, 1);
01333 }
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350 static VALUE
01351 time_minus(time1, time2)
01352 VALUE time1, time2;
01353 {
01354 struct time_object *tobj;
01355
01356 GetTimeval(time1, tobj);
01357 if (TYPE(time2) == T_DATA && RDATA(time2)->dfree == time_free) {
01358 struct time_object *tobj2;
01359 double f;
01360
01361 GetTimeval(time2, tobj2);
01362 f = (double)tobj->tv.tv_sec - (double)tobj2->tv.tv_sec;
01363 f += ((double)tobj->tv.tv_usec - (double)tobj2->tv.tv_usec)*1e-6;
01364
01365
01366 return rb_float_new(f);
01367 }
01368 return time_add(tobj, time2, -1);
01369 }
01370
01371
01372
01373
01374
01375
01376
01377
01378 static VALUE
01379 time_succ(time)
01380 VALUE time;
01381 {
01382 struct time_object *tobj;
01383
01384 GetTimeval(time, tobj);
01385 return rb_time_new(tobj->tv.tv_sec + 1, tobj->tv.tv_usec);
01386 }
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401 static VALUE
01402 time_sec(time)
01403 VALUE time;
01404 {
01405 struct time_object *tobj;
01406
01407 GetTimeval(time, tobj);
01408 if (tobj->tm_got == 0) {
01409 time_get_tm(time, tobj->gmt);
01410 }
01411 return INT2FIX(tobj->tm.tm_sec);
01412 }
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424 static VALUE
01425 time_min(time)
01426 VALUE time;
01427 {
01428 struct time_object *tobj;
01429
01430 GetTimeval(time, tobj);
01431 if (tobj->tm_got == 0) {
01432 time_get_tm(time, tobj->gmt);
01433 }
01434 return INT2FIX(tobj->tm.tm_min);
01435 }
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447 static VALUE
01448 time_hour(time)
01449 VALUE time;
01450 {
01451 struct time_object *tobj;
01452
01453 GetTimeval(time, tobj);
01454 if (tobj->tm_got == 0) {
01455 time_get_tm(time, tobj->gmt);
01456 }
01457 return INT2FIX(tobj->tm.tm_hour);
01458 }
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472 static VALUE
01473 time_mday(time)
01474 VALUE time;
01475 {
01476 struct time_object *tobj;
01477
01478 GetTimeval(time, tobj);
01479 if (tobj->tm_got == 0) {
01480 time_get_tm(time, tobj->gmt);
01481 }
01482 return INT2FIX(tobj->tm.tm_mday);
01483 }
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497 static VALUE
01498 time_mon(time)
01499 VALUE time;
01500 {
01501 struct time_object *tobj;
01502
01503 GetTimeval(time, tobj);
01504 if (tobj->tm_got == 0) {
01505 time_get_tm(time, tobj->gmt);
01506 }
01507 return INT2FIX(tobj->tm.tm_mon+1);
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520 static VALUE
01521 time_year(time)
01522 VALUE time;
01523 {
01524 struct time_object *tobj;
01525
01526 GetTimeval(time, tobj);
01527 if (tobj->tm_got == 0) {
01528 time_get_tm(time, tobj->gmt);
01529 }
01530 return LONG2NUM((long)tobj->tm.tm_year+1900);
01531 }
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544 static VALUE
01545 time_wday(time)
01546 VALUE time;
01547 {
01548 struct time_object *tobj;
01549
01550 GetTimeval(time, tobj);
01551 if (tobj->tm_got == 0) {
01552 time_get_tm(time, tobj->gmt);
01553 }
01554 return INT2FIX(tobj->tm.tm_wday);
01555 }
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567 static VALUE
01568 time_yday(time)
01569 VALUE time;
01570 {
01571 struct time_object *tobj;
01572
01573 GetTimeval(time, tobj);
01574 if (tobj->tm_got == 0) {
01575 time_get_tm(time, tobj->gmt);
01576 }
01577 return INT2FIX(tobj->tm.tm_yday+1);
01578 }
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594 static VALUE
01595 time_isdst(time)
01596 VALUE time;
01597 {
01598 struct time_object *tobj;
01599
01600 GetTimeval(time, tobj);
01601 if (tobj->tm_got == 0) {
01602 time_get_tm(time, tobj->gmt);
01603 }
01604 return tobj->tm.tm_isdst?Qtrue:Qfalse;
01605 }
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620 static VALUE
01621 time_zone(time)
01622 VALUE time;
01623 {
01624 struct time_object *tobj;
01625 #if !defined(HAVE_TM_ZONE) && (!defined(HAVE_TZNAME) || !defined(HAVE_DAYLIGHT))
01626 char buf[64];
01627 int len;
01628 #endif
01629
01630 GetTimeval(time, tobj);
01631 if (tobj->tm_got == 0) {
01632 time_get_tm(time, tobj->gmt);
01633 }
01634
01635 if (tobj->gmt == 1) {
01636 return rb_str_new2("UTC");
01637 }
01638 #if defined(HAVE_TM_ZONE)
01639 return rb_str_new2(tobj->tm.tm_zone);
01640 #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
01641 return rb_str_new2(tzname[daylight && tobj->tm.tm_isdst]);
01642 #else
01643 len = strftime(buf, 64, "%Z", &tobj->tm);
01644 return rb_str_new(buf, len);
01645 #endif
01646 }
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663 static VALUE
01664 time_utc_offset(time)
01665 VALUE time;
01666 {
01667 struct time_object *tobj;
01668
01669 GetTimeval(time, tobj);
01670 if (tobj->tm_got == 0) {
01671 time_get_tm(time, tobj->gmt);
01672 }
01673
01674 if (tobj->gmt == 1) {
01675 return INT2FIX(0);
01676 }
01677 else {
01678 #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
01679 return INT2NUM(tobj->tm.tm_gmtoff);
01680 #else
01681 struct tm *u, *l;
01682 time_t t;
01683 long off;
01684 l = &tobj->tm;
01685 t = tobj->tv.tv_sec;
01686 u = gmtime(&t);
01687 if (!u)
01688 rb_raise(rb_eArgError, "gmtime error");
01689 if (l->tm_year != u->tm_year)
01690 off = l->tm_year < u->tm_year ? -1 : 1;
01691 else if (l->tm_mon != u->tm_mon)
01692 off = l->tm_mon < u->tm_mon ? -1 : 1;
01693 else if (l->tm_mday != u->tm_mday)
01694 off = l->tm_mday < u->tm_mday ? -1 : 1;
01695 else
01696 off = 0;
01697 off = off * 24 + l->tm_hour - u->tm_hour;
01698 off = off * 60 + l->tm_min - u->tm_min;
01699 off = off * 60 + l->tm_sec - u->tm_sec;
01700 return LONG2FIX(off);
01701 #endif
01702 }
01703 }
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720 static VALUE
01721 time_to_a(time)
01722 VALUE time;
01723 {
01724 struct time_object *tobj;
01725
01726 GetTimeval(time, tobj);
01727 if (tobj->tm_got == 0) {
01728 time_get_tm(time, tobj->gmt);
01729 }
01730 return rb_ary_new3(10,
01731 INT2FIX(tobj->tm.tm_sec),
01732 INT2FIX(tobj->tm.tm_min),
01733 INT2FIX(tobj->tm.tm_hour),
01734 INT2FIX(tobj->tm.tm_mday),
01735 INT2FIX(tobj->tm.tm_mon+1),
01736 LONG2NUM((long)tobj->tm.tm_year+1900),
01737 INT2FIX(tobj->tm.tm_wday),
01738 INT2FIX(tobj->tm.tm_yday+1),
01739 tobj->tm.tm_isdst?Qtrue:Qfalse,
01740 time_zone(time));
01741 }
01742
01743 #define SMALLBUF 100
01744 static int
01745 rb_strftime(buf, format, time)
01746 char **buf;
01747 const char *format;
01748 struct tm *time;
01749 {
01750 int size, len, flen;
01751
01752 (*buf)[0] = '\0';
01753 flen = strlen(format);
01754 if (flen == 0) {
01755 return 0;
01756 }
01757 len = strftime(*buf, SMALLBUF, format, time);
01758 if (len != 0 || **buf == '\0') return len;
01759 for (size=1024; ; size*=2) {
01760 *buf = xmalloc(size);
01761 (*buf)[0] = '\0';
01762 len = strftime(*buf, size, format, time);
01763
01764
01765
01766
01767
01768
01769
01770 if (len > 0 || size >= 1024 * flen) return len;
01771 free(*buf);
01772 }
01773
01774 }
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816
01817 static VALUE
01818 time_strftime(time, format)
01819 VALUE time, format;
01820 {
01821 struct time_object *tobj;
01822 char buffer[SMALLBUF], *buf = buffer;
01823 const char *fmt;
01824 long len;
01825 VALUE str;
01826
01827 GetTimeval(time, tobj);
01828 if (tobj->tm_got == 0) {
01829 time_get_tm(time, tobj->gmt);
01830 }
01831 StringValue(format);
01832 format = rb_str_new4(format);
01833 fmt = RSTRING(format)->ptr;
01834 len = RSTRING(format)->len;
01835 if (len == 0) {
01836 rb_warning("strftime called with empty format string");
01837 }
01838 else if (strlen(fmt) < len) {
01839
01840 const char *p = fmt, *pe = fmt + len;
01841
01842 str = rb_str_new(0, 0);
01843 while (p < pe) {
01844 len = rb_strftime(&buf, p, &tobj->tm);
01845 rb_str_cat(str, buf, len);
01846 p += strlen(p) + 1;
01847 if (buf != buffer) {
01848 free(buf);
01849 buf = buffer;
01850 }
01851 for (fmt = p; p < pe && !*p; ++p);
01852 if (p > fmt) rb_str_cat(str, fmt, p - fmt);
01853 }
01854 return str;
01855 }
01856 else {
01857 len = rb_strftime(&buf, RSTRING(format)->ptr, &tobj->tm);
01858 }
01859 str = rb_str_new(buf, len);
01860 if (buf != buffer) free(buf);
01861 return str;
01862 }
01863
01864
01865
01866
01867
01868
01869
01870
01871 static VALUE
01872 time_s_times(obj)
01873 VALUE obj;
01874 {
01875 rb_warn("obsolete method Time::times; use Process::times");
01876 return rb_proc_times(obj);
01877 }
01878
01879
01880
01881
01882
01883 static VALUE
01884 time_mdump(time)
01885 VALUE time;
01886 {
01887 struct time_object *tobj;
01888 struct tm *tm;
01889 unsigned long p, s;
01890 char buf[8];
01891 time_t t;
01892 int i;
01893
01894 GetTimeval(time, tobj);
01895
01896 t = tobj->tv.tv_sec;
01897 tm = gmtime(&t);
01898
01899 if ((tm->tm_year & 0xffff) != tm->tm_year)
01900 rb_raise(rb_eArgError, "year too big to marshal");
01901
01902 p = 0x1 << 31 |
01903 tm->tm_year << 14 |
01904 tm->tm_mon << 10 |