Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

time.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   time.c -
00004 
00005   $Author: nobu $
00006   $Date: 2005/10/22 04:27:48 $
00007   created at: Tue Dec 28 14:31:59 JST 1993
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
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  *  Document-method: now
00071  *
00072  *  Synonym for <code>Time.new</code>. Returns a +Time+ object
00073  *  initialized tot he current system time.
00074  *
00075  *  call-seq:
00076  *     Time.new -> time
00077  *  
00078  *  Returns a <code>Time</code> object initialized to the current system
00079  *  time. <b>Note:</b> The object created will be created using the
00080  *  resolution available on your system clock, and so may include
00081  *  fractional seconds.
00082  *     
00083  *     a = Time.new      #=> Wed Apr 09 08:56:03 CDT 2003
00084  *     b = Time.new      #=> Wed Apr 09 08:56:03 CDT 2003
00085  *     a == b            #=> false
00086  *     "%.6f" % a.to_f   #=> "1049896563.230740"
00087  *     "%.6f" % b.to_f   #=> "1049896563.231466"
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) {      /* usec positive overflow */
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) {             /* usec negative overflow */
00127         tmp = sec + NDIV(usec,1000000); /* negative div */
00128         usec = NMOD(usec,1000000);      /* negative mod */
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  *  call-seq:
00239  *     Time.at( aTime ) => time
00240  *     Time.at( seconds [, microseconds] ) => time
00241  *  
00242  *  Creates a new time object with the value given by <i>aTime</i>, or
00243  *  the given number of <i>seconds</i> (and optional
00244  *  <i>microseconds</i>) from epoch. A non-portable feature allows the
00245  *  offset to be negative on some systems.
00246  *     
00247  *     Time.at(0)            #=> Wed Dec 31 18:00:00 CST 1969
00248  *     Time.at(946702800)    #=> Fri Dec 31 23:00:00 CST 1999
00249  *     Time.at(-284061600)   #=> Sat Dec 31 00:00:00 CST 1960
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         /* v[6] may be usec or zone (parsedate) */
00321         /* v[7] is wday (parsedate; ignored) */
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             /* v[6] is timezone, but ignored */
00379         }
00380         else if (argc == 7) {
00381             *usec = obj2long(v[6]);
00382         }
00383     }
00384 
00385     /* value validation */
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           /* 1    2    3    4    5    6    7    8    9    10   11 */
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           /* 1    2    3    4    5    6    7    8    9    10   11 */
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      *  `Seconds Since the Epoch' in SUSv3:
00456      *  tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
00457      *  (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
00458      *  ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
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       /* there is a gap between guess_lo and guess_hi. */
00552       unsigned long range = 0;
00553       if (!have_guess) {
00554         int a, b;
00555         /*
00556           Try precious guess by a linear interpolation at first.
00557           `a' and `b' is a coefficient of guess_lo and guess_hi as:
00558 
00559             guess = (guess_lo * a + guess_hi * b) / (a + b)
00560 
00561           However this causes overflow in most cases, following assignment
00562           is used instead:
00563 
00564             guess = guess_lo / d * a + (guess_lo % d) * a / d
00565                   + guess_hi / d * b + (guess_hi % d) * b / d
00566               where d = a + b
00567 
00568           To avoid overflow in this assignment, `d' is restricted to less than
00569           sqrt(2**31).  By this restriction and other reasons, the guess is
00570           not accurate and some error is expected.  `range' approximates 
00571           the maximum error.
00572 
00573           When these parameters are not suitable, i.e. guess is not within
00574           guess_lo and guess_hi, simple guess by binary search is used.
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         /* 46000 is selected as `some big number less than sqrt(2**31)'. */
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           Although `/' and `%' may produce unexpected result with negative
00620           argument, it doesn't cause serious problem because there is a
00621           fail safe.
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         /* Precious guess is invalid. try binary search. */ 
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           /* If localtime is nonmonotonic, another result may exist. */
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     /* Given argument has no corresponding time_t. Let's outerpolation. */
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;                   /* not reached */
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  *  call-seq:
00806  *     Time.utc( year [, month, day, hour, min, sec, usec] ) => time
00807  *     Time.utc( sec, min, hour, day, month, year, wday, yday, isdst, tz
00808  *     ) => time
00809  *     Time.gm( year [, month, day, hour, min, sec, usec] ) => time
00810  *     Time.gm( sec, min, hour, day, month, year, wday, yday, isdst, tz
00811  *     ) => time
00812  *     
00813  *  Creates a time based on given values, interpreted as UTC (GMT). The
00814  *  year must be specified. Other values default to the minimum value
00815  *  for that field (and may be <code>nil</code> or omitted). Months may
00816  *  be specified by numbers from 1 to 12, or by the three-letter English
00817  *  month names. Hours are specified on a 24-hour clock (0..23). Raises
00818  *  an <code>ArgumentError</code> if any values are out of range. Will
00819  *  also accept ten arguments in the order output by
00820  *  <code>Time#to_a</code>.
00821  *
00822  *     Time.utc(2000,"jan",1,20,15,1)  #=> Sat Jan 01 20:15:01 UTC 2000
00823  *     Time.gm(2000,"jan",1,20,15,1)   #=> Sat Jan 01 20:15:01 UTC 2000
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  *  call-seq:
00836  *     Time.local( year [, month, day, hour, min, sec, usec] ) => time
00837  *     Time.local( sec, min, hour, day, month, year, wday, yday, isdst,
00838  *     tz ) => time
00839  *     Time.mktime( year, month, day, hour, min, sec, usec )   => time
00840  *  
00841  *  Same as <code>Time::gm</code>, but interprets the values in the
00842  *  local time zone.
00843  *     
00844  *     Time.local(2000,"jan",1,20,15,1)   #=> Sat Jan 01 20:15:01 CST 2000
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  *  call-seq:
00858  *     time.to_i   => int
00859  *     time.tv_sec => int
00860  *  
00861  *  Returns the value of <i>time</i> as an integer number of seconds
00862  *  since epoch.
00863  *     
00864  *     t = Time.now
00865  *     "%10.5f" % t.to_f   #=> "1049896564.17839"
00866  *     t.to_i              #=> 1049896564
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  *  call-seq:
00881  *     time.to_f => float
00882  *  
00883  *  Returns the value of <i>time</i> as a floating point number of
00884  *  seconds since epoch.
00885  *     
00886  *     t = Time.now
00887  *     "%10.5f" % t.to_f   #=> "1049896564.13654"
00888  *     t.to_i              #=> 1049896564
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  *  call-seq:
00903  *     time.usec    => int
00904  *     time.tv_usec => int
00905  *  
00906  *  Returns just the number of microseconds for <i>time</i>.
00907  *     
00908  *     t = Time.now        #=> Wed Apr 09 08:56:04 CDT 2003
00909  *     "%10.6f" % t.to_f   #=> "1049896564.259970"
00910  *     t.usec              #=> 259970
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  *  call-seq:
00925  *     time <=> other_time => -1, 0, +1 
00926  *     time <=> numeric    => -1, 0, +1
00927  *  
00928  *  Comparison---Compares <i>time</i> with <i>other_time</i> or with
00929  *  <i>numeric</i>, which is the number of seconds (possibly
00930  *  fractional) since epoch.
00931  *     
00932  *     t = Time.now       #=> Wed Apr 09 08:56:03 CDT 2003
00933  *     t2 = t + 2592000   #=> Fri May 09 08:56:03 CDT 2003
00934  *     t <=> t2           #=> -1
00935  *     t2 <=> t           #=> 1
00936  *     t <=> t            #=> 0
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  * call-seq:
00962  *  time.eql?(other_time)
00963  *
00964  * Return <code>true</code> if <i>time</i> and <i>other_time</i> are
00965  * both <code>Time</code> objects with the same seconds and fractional
00966  * seconds.
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  *  call-seq:
00987  *     time.utc? => true or false
00988  *     time.gmt? => true or false
00989  *  
00990  *  Returns <code>true</code> if <i>time</i> represents a time in UTC
00991  *  (GMT).
00992  *     
00993  *     t = Time.now                        #=> Wed Apr 09 08:56:04 CDT 2003
00994  *     t.utc?                              #=> false
00995  *     t = Time.gm(2000,"jan",1,20,15,1)   #=> Sat Jan 01 20:15:01 UTC 2000
00996  *     t.utc?                              #=> true
00997  *
00998  *     t = Time.now                        #=> Wed Apr 09 08:56:03 CDT 2003
00999  *     t.gmt?                              #=> false
01000  *     t = Time.gm(2000,1,1,20,15,1)       #=> Sat Jan 01 20:15:01 UTC 2000
01001  *     t.gmt?                              #=> true
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  * call-seq:
01017  *   time.hash   => fixnum
01018  *
01019  * Return a hash code for this time object.
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 /* :nodoc: */
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  *  call-seq:
01064  *     time.localtime => time
01065  *  
01066  *  Converts <i>time</i> to local time (using the local time zone in
01067  *  effect for this process) modifying the receiver.
01068  *     
01069  *     t = Time.gm(2000, "jan", 1, 20, 15, 1)
01070  *     t.gmt?        #=> true
01071  *     t.localtime   #=> Sat Jan 01 14:15:01 CST 2000
01072  *     t.gmt?        #=> false
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  *  call-seq:
01103  *     time.gmtime    => time
01104  *     time.utc       => time
01105  *  
01106  *  Converts <i>time</i> to UTC (GMT), modifying the receiver.
01107  *     
01108  *     t = Time.now   #=> Wed Apr 09 08:56:03 CDT 2003
01109  *     t.gmt?         #=> false
01110  *     t.gmtime       #=> Wed Apr 09 13:56:03 UTC 2003
01111  *     t.gmt?         #=> true
01112  *
01113  *     t = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01114  *     t.utc?         #=> false
01115  *     t.utc          #=> Wed Apr 09 13:56:04 UTC 2003
01116  *     t.utc?         #=> true
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  *  call-seq:
01147  *     time.getlocal => new_time
01148  *  
01149  *  Returns a new <code>new_time</code> object representing <i>time</i> in
01150  *  local time (using the local time zone in effect for this process).
01151  *     
01152  *     t = Time.gm(2000,1,1,20,15,1)   #=> Sat Jan 01 20:15:01 UTC 2000
01153  *     t.gmt?                          #=> true
01154  *     l = t.getlocal                  #=> Sat Jan 01 14:15:01 CST 2000
01155  *     l.gmt?                          #=> false
01156  *     t == l                          #=> true
01157  */
01158 
01159 static VALUE
01160 time_getlocaltime(time)
01161     VALUE time;
01162 {
01163     return time_localtime(time_dup(time));
01164 }
01165 
01166 /*
01167  *  call-seq:
01168  *     time.getgm  => new_time
01169  *     time.getutc => new_time
01170  *  
01171  *  Returns a new <code>new_time</code> object representing <i>time</i> in
01172  *  UTC.
01173  *     
01174  *     t = Time.local(2000,1,1,20,15,1)   #=> Sat Jan 01 20:15:01 CST 2000
01175  *     t.gmt?                             #=> false
01176  *     y = t.getgm                        #=> Sun Jan 02 02:15:01 UTC 2000
01177  *     y.gmt?                             #=> true
01178  *     t == y                             #=> true
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  *  call-seq:
01199  *     time.asctime => string
01200  *     time.ctime   => string
01201  *  
01202  *  Returns a canonical string representation of <i>time</i>.
01203  *     
01204  *     Time.now.asctime   #=> "Wed Apr  9 08:56:03 2003"
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  *  call-seq:
01226  *     time.inspect => string
01227  *     time.to_s    => string
01228  *  
01229  *  Returns a string representing <i>time</i>. Equivalent to calling
01230  *  <code>Time#strftime</code> with a format string of ``<code>%a</code>
01231  *  <code>%b</code> <code>%d</code> <code>%H:%M:%S</code>
01232  *  <code>%Z</code> <code>%Y</code>''.
01233  *     
01234  *     Time.now.to_s   #=> "Wed Apr 09 08:56:04 CDT 2003"
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  *  call-seq:
01313  *     time + numeric => time
01314  *  
01315  *  Addition---Adds some number of seconds (possibly fractional) to
01316  *  <i>time</i> and returns that value as a new time.
01317  *     
01318  *     t = Time.now         #=> Wed Apr 09 08:56:03 CDT 2003
01319  *     t + (60 * 60 * 24)   #=> Thu Apr 10 08:56:03 CDT 2003
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  *  call-seq:
01337  *     time - other_time => float
01338  *     time - numeric    => time
01339  *  
01340  *  Difference---Returns a new time that represents the difference
01341  *  between two times, or subtracts the given number of seconds in
01342  *  <i>numeric</i> from <i>time</i>.
01343  *     
01344  *     t = Time.now       #=> Wed Apr 09 08:56:03 CDT 2003
01345  *     t2 = t + 2592000   #=> Fri May 09 08:56:03 CDT 2003
01346  *     t2 - t             #=> 2592000.0
01347  *     t2 - 2592000       #=> Wed Apr 09 08:56:03 CDT 2003
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         /* XXX: should check float overflow on 64bit time_t platforms */
01365 
01366         return rb_float_new(f);
01367     }
01368     return time_add(tobj, time2, -1);
01369 }
01370 
01371 /*
01372  * call-seq:
01373  *   time.succ   => new_time
01374  *
01375  * Return a new time object, one second later than <code>time</code>.
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  *  call-seq:
01390  *     time.sec => fixnum
01391  *  
01392  *  Returns the second of the minute (0..60)<em>[Yes, seconds really can
01393  *  range from zero to 60. This allows the system to inject leap seconds
01394  *  every now and then to correct for the fact that years are not really
01395  *  a convenient number of hours long.]</em> for <i>time</i>.
01396  *     
01397  *     t = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01398  *     t.sec          #=> 4
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  *  call-seq:
01416  *     time.min => fixnum
01417  *  
01418  *  Returns the minute of the hour (0..59) for <i>time</i>.
01419  *     
01420  *     t = Time.now   #=> Wed Apr 09 08:56:03 CDT 2003
01421  *     t.min          #=> 56
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  *  call-seq:
01439  *     time.hour => fixnum
01440  *  
01441  *  Returns the hour of the day (0..23) for <i>time</i>.
01442  *     
01443  *     t = Time.now   #=> Wed Apr 09 08:56:03 CDT 2003
01444  *     t.hour         #=> 8
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  *  call-seq:
01462  *     time.day  => fixnum
01463  *     time.mday => fixnum
01464  *  
01465  *  Returns the day of the month (1..n) for <i>time</i>.
01466  *     
01467  *     t = Time.now   #=> Wed Apr 09 08:56:03 CDT 2003
01468  *     t.day          #=> 9
01469  *     t.mday         #=> 9
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  *  call-seq:
01487  *     time.mon   => fixnum
01488  *     time.month => fixnum
01489  *  
01490  *  Returns the month of the year (1..12) for <i>time</i>.
01491  *     
01492  *     t = Time.now   #=> Wed Apr 09 08:56:03 CDT 2003
01493  *     t.mon          #=> 4
01494  *     t.month        #=> 4
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  *  call-seq:
01512  *     time.year => fixnum
01513  *  
01514  *  Returns the year for <i>time</i> (including the century).
01515  *     
01516  *     t = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01517  *     t.year         #=> 2003
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  *  call-seq:
01535  *     time.wday => fixnum
01536  *  
01537  *  Returns an integer representing the day of the week, 0..6, with
01538  *  Sunday == 0.
01539  *     
01540  *     t = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01541  *     t.wday         #=> 3
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  *  call-seq:
01559  *     time.yday => fixnum
01560  *  
01561  *  Returns an integer representing the day of the year, 1..366.
01562  *     
01563  *     t = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01564  *     t.yday         #=> 99
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  *  call-seq:
01582  *     time.isdst => true or false
01583  *     time.dst?  => true or false
01584  *  
01585  *  Returns <code>true</code> if <i>time</i> occurs during Daylight
01586  *  Saving Time in its time zone.
01587  *     
01588  *     Time.local(2000, 7, 1).isdst   #=> true
01589  *     Time.local(2000, 1, 1).isdst   #=> false
01590  *     Time.local(2000, 7, 1).dst?    #=> true
01591  *     Time.local(2000, 1, 1).dst?    #=> false
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  *  call-seq:
01609  *     time.zone => string
01610  *  
01611  *  Returns the name of the time zone used for <i>time</i>. As of Ruby
01612  *  1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
01613  *     
01614  *     t = Time.gm(2000, "jan", 1, 20, 15, 1)
01615  *     t.zone   #=> "UTC"
01616  *     t = Time.local(2000, "jan", 1, 20, 15, 1)
01617  *     t.zone   #=> "CST"
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  *  call-seq:
01650  *     time.gmt_offset => fixnum
01651  *     time.gmtoff     => fixnum
01652  *     time.utc_offset => fixnum
01653  *  
01654  *  Returns the offset in seconds between the timezone of <i>time</i>
01655  *  and UTC.
01656  *     
01657  *     t = Time.gm(2000,1,1,20,15,1)   #=> Sat Jan 01 20:15:01 UTC 2000
01658  *     t.gmt_offset                    #=> 0
01659  *     l = t.getlocal                  #=> Sat Jan 01 14:15:01 CST 2000
01660  *     l.gmt_offset                    #=> -21600
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  *  call-seq:
01707  *     time.to_a => array
01708  *  
01709  *  Returns a ten-element <i>array</i> of values for <i>time</i>:
01710  *  {<code>[ sec, min, hour, day, month, year, wday, yday, isdst, zone
01711  *  ]</code>}. See the individual methods for an explanation of the
01712  *  valid ranges of each value. The ten elements can be passed directly
01713  *  to <code>Time::utc</code> or <code>Time::local</code> to create a
01714  *  new <code>Time</code>.
01715  *     
01716  *     now = Time.now   #=> Wed Apr 09 08:56:04 CDT 2003
01717  *     t = now.to_a     #=> [4, 56, 8, 9, 4, 2003, 3, 99, true, "CDT"]
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          * buflen can be zero EITHER because there's not enough
01765          * room in the string, or because the control command
01766          * goes to the empty string. Make a reasonable guess that
01767          * if the buffer is 1024 times bigger than the length of the
01768          * format string, it's not failing for lack of room.
01769          */
01770         if (len > 0 || size >= 1024 * flen) return len;
01771         free(*buf);
01772     }
01773     /* not reached */
01774 }
01775 
01776 /*
01777  *  call-seq:
01778  *     time.strftime( string ) => string
01779  *  
01780  *  Formats <i>time</i> according to the directives in the given format
01781  *  string. Any text not listed as a directive will be passed through
01782  *  to the output string.
01783  *
01784  *  Format meaning:
01785  *    %a - The abbreviated weekday name (``Sun'')
01786  *    %A - The  full  weekday  name (``Sunday'')
01787  *    %b - The abbreviated month name (``Jan'')
01788  *    %B - The  full  month  name (``January'')
01789  *    %c - The preferred local date and time representation
01790  *    %d - Day of the month (01..31)
01791  *    %H - Hour of the day, 24-hour clock (00..23)
01792  *    %I - Hour of the day, 12-hour clock (01..12)
01793  *    %j - Day of the year (001..366)
01794  *    %m - Month of the year (01..12)
01795  *    %M - Minute of the hour (00..59)
01796  *    %p - Meridian indicator (``AM''  or  ``PM'')
01797  *    %S - Second of the minute (00..60)
01798  *    %U - Week  number  of the current year,
01799  *            starting with the first Sunday as the first
01800  *            day of the first week (00..53)
01801  *    %W - Week  number  of the current year,
01802  *            starting with the first Monday as the first
01803  *            day of the first week (00..53)
01804  *    %w - Day of the week (Sunday is 0, 0..6)
01805  *    %x - Preferred representation for the date alone, no time
01806  *    %X - Preferred representation for the time alone, no date
01807  *    %y - Year without a century (00..99)
01808  *    %Y - Year with century
01809  *    %Z - Time zone name
01810  *    %% - Literal ``%'' character
01811  *     
01812  *     t = Time.now
01813  *     t.strftime("Printed on %m/%d/%Y")   #=> "Printed on 04/09/2003"
01814  *     t.strftime("at %I:%M%p")            #=> "at 08:56AM"
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         /* Ruby string may contain \0's. */
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  *  call-seq:
01866  *     Time.times => struct_tms
01867  *  
01868  *  Deprecated in favor of <code>Process::times</code>
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  * undocumented
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 | /*  1 */
01903         tm->tm_year  << 14 | /* 16 */
01904         tm->tm_mon   << 10 |