time.c


DEFINITIONS

This source file includes following functions.
  1. time_free
  2. time_s_alloc
  3. time_s_now
  4. time_new_internal
  5. rb_time_new
  6. time_timeval
  7. rb_time_interval
  8. rb_time_timeval
  9. time_s_at
  10. obj2long
  11. time_arg
  12. tmcmp
  13. search_time_t
  14. make_time_t
  15. time_utc_or_local
  16. time_s_mkutc
  17. time_s_mktime
  18. time_to_i
  19. time_to_f
  20. time_usec
  21. time_cmp
  22. time_eql
  23. time_utc_p
  24. time_hash
  25. time_modify
  26. time_become
  27. time_dup
  28. time_localtime
  29. time_gmtime
  30. time_getlocaltime
  31. time_getgmtime
  32. time_get_tm
  33. time_asctime
  34. time_to_s
  35. time_plus
  36. time_minus
  37. time_sec
  38. time_min
  39. time_hour
  40. time_mday
  41. time_mon
  42. time_year
  43. time_wday
  44. time_yday
  45. time_isdst
  46. time_zone
  47. time_utc_offset
  48. time_to_a
  49. rb_strftime
  50. time_strftime
  51. time_s_times
  52. time_dump
  53. time_load
  54. Init_Time


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