summaryrefslogtreecommitdiff
path: root/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'time.c')
-rw-r--r--time.c490
1 files changed, 309 insertions, 181 deletions
diff --git a/time.c b/time.c
index fc14d8e5b6..f8296e6e20 100644
--- a/time.c
+++ b/time.c
@@ -6,26 +6,22 @@
$Date$
created at: Tue Dec 28 14:31:59 JST 1993
- Copyright (C) 1993-1998 Yukihiro Matsumoto
+ Copyright (C) 1993-1999 Yukihiro Matsumoto
************************************************/
#include "ruby.h"
#include <sys/types.h>
-#ifdef USE_CWGUSI
-int gettimeofday(struct timeval*, struct timezone*);
-int strcasecmp(char*, char*);
-#endif
-
#include <time.h>
#ifndef NT
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
+#define time_t long
struct timeval {
- long tv_sec; /* seconds */
- long tv_usec; /* and microseconds */
+ time_t tv_sec; /* seconds */
+ time_t tv_usec; /* and microseconds */
};
#endif
#endif /* NT */
@@ -33,7 +29,16 @@ struct timeval {
#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif
-#include <math.h>
+
+#ifdef USE_CWGUSI
+#define time_t long
+int gettimeofday(struct timeval*, struct timezone*);
+int strcasecmp(char*, char*);
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
VALUE rb_cTime;
#if defined(HAVE_TIMES) || defined(NT)
@@ -43,9 +48,7 @@ static VALUE S_Tms;
struct time_object {
struct timeval tv;
struct tm tm;
-#ifndef HAVE_TM_ZONE
int gmt;
-#endif
int tm_got;
};
@@ -63,10 +66,9 @@ time_s_now(klass)
obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj);
tobj->tm_got=0;
- if (gettimeofday(&(tobj->tv), 0) == -1) {
+ if (gettimeofday(&tobj->tv, 0) < 0) {
rb_sys_fail("gettimeofday");
}
- rb_obj_call_init(obj);
return obj;
}
@@ -74,13 +76,15 @@ time_s_now(klass)
static VALUE
time_new_internal(klass, sec, usec)
VALUE klass;
- int sec, usec;
+ time_t sec, usec;
{
VALUE obj;
struct time_object *tobj;
+#ifndef USE_CWGUSI
if (sec < 0 || (sec == 0 && usec < 0))
rb_raise(rb_eArgError, "time must be positive");
+#endif
obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj);
tobj->tm_got = 0;
tobj->tv.tv_sec = sec;
@@ -91,21 +95,20 @@ time_new_internal(klass, sec, usec)
VALUE
rb_time_new(sec, usec)
- int sec, usec;
+ time_t sec, usec;
{
return time_new_internal(rb_cTime, sec, usec);
}
struct timeval
-rb_time_timeval(time)
+rb_time_interval(time)
VALUE time;
{
- struct time_object *tobj;
struct timeval t;
switch (TYPE(time)) {
case T_FIXNUM:
- t.tv_sec = FIX2INT(time);
+ t.tv_sec = FIX2LONG(time);
if (t.tv_sec < 0)
rb_raise(rb_eArgError, "time must be positive");
t.tv_usec = 0;
@@ -114,37 +117,57 @@ rb_time_timeval(time)
case T_FLOAT:
if (RFLOAT(time)->value < 0.0)
rb_raise(rb_eArgError, "time must be positive");
- t.tv_sec = (long)floor(RFLOAT(time)->value);
- t.tv_usec = (long)((RFLOAT(time)->value - t.tv_sec) * 1000000.0);
+ t.tv_sec = (time_t)RFLOAT(time)->value;
+ t.tv_usec = (time_t)((RFLOAT(time)->value - (double)t.tv_sec)*1e6);
break;
case T_BIGNUM:
- t.tv_sec = NUM2INT(time);
+ t.tv_sec = NUM2LONG(time);
if (t.tv_sec < 0)
rb_raise(rb_eArgError, "time must be positive");
t.tv_usec = 0;
break;
default:
- if (!rb_obj_is_kind_of(time, rb_cTime)) {
- rb_raise(rb_eTypeError, "Can't convert %s into Time",
- rb_class2name(CLASS_OF(time)));
- }
- GetTimeval(time, tobj);
- t = tobj->tv;
+ rb_raise(rb_eTypeError, "can't convert %s into Time interval",
+ rb_class2name(CLASS_OF(time)));
break;
}
return t;
}
+struct timeval
+rb_time_timeval(time)
+ VALUE time;
+{
+ struct time_object *tobj;
+ struct timeval t;
+
+ if (rb_obj_is_kind_of(time, rb_cTime)) {
+ GetTimeval(time, tobj);
+ t = tobj->tv;
+ return t;
+ }
+ return rb_time_interval(time);
+}
+
static VALUE
time_s_at(klass, time)
VALUE klass, time;
{
struct timeval tv;
+ VALUE t;
tv = rb_time_timeval(time);
- return time_new_internal(klass, tv.tv_sec, tv.tv_usec);
+ t = time_new_internal(klass, tv.tv_sec, tv.tv_usec);
+ if (TYPE(time) == T_DATA) {
+ struct time_object *tobj, *tobj2;
+
+ GetTimeval(time, tobj);
+ GetTimeval(t, tobj2);
+ tobj2->gmt = tobj->gmt;
+ }
+ return t;
}
static char *months [12] = {
@@ -152,22 +175,22 @@ static char *months [12] = {
"jul", "aug", "sep", "oct", "nov", "dec",
};
-static int
-obj2int(obj)
+static long
+obj2long(obj)
VALUE obj;
{
if (TYPE(obj) == T_STRING) {
obj = rb_str2inum(RSTRING(obj)->ptr, 10);
}
- return NUM2INT(obj);
+ return NUM2LONG(obj);
}
static void
-time_arg(argc, argv, args)
+time_arg(argc, argv, tm)
int argc;
VALUE *argv;
- int *args;
+ struct tm *tm;
{
VALUE v[6];
int i;
@@ -184,102 +207,98 @@ time_arg(argc, argv, args)
rb_scan_args(argc, argv, "15", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5]);
}
- args[0] = obj2int(v[0]);
- if (args[0] < 70) args[0] += 100;
- if (args[0] > 1900) args[0] -= 1900;
+ tm->tm_year = obj2long(v[0]);
+ if (tm->tm_year < 69) tm->tm_year += 100;
+ if (tm->tm_year >= 1000) tm->tm_year -= 1900;
if (NIL_P(v[1])) {
- args[1] = 0;
+ tm->tm_mon = 0;
}
else if (TYPE(v[1]) == T_STRING) {
- args[1] = -1;
+ tm->tm_mon = -1;
for (i=0; i<12; i++) {
- if (strcasecmp(months[i], RSTRING(v[1])->ptr) == 0) {
- args[1] = i;
+ if (RSTRING(v[1])->len == 3 &&
+ strcasecmp(months[i], RSTRING(v[1])->ptr) == 0) {
+ tm->tm_mon = i;
break;
}
}
- if (args[1] == -1) {
+ if (tm->tm_mon == -1) {
char c = RSTRING(v[1])->ptr[0];
if ('0' <= c && c <= '9') {
- args[1] = obj2int(v[1])-1;
+ tm->tm_mon = obj2long(v[1])-1;
}
}
}
else {
- args[1] = obj2int(v[1]) - 1;
+ tm->tm_mon = obj2long(v[1]) - 1;
}
if (NIL_P(v[2])) {
- args[2] = 1;
+ tm->tm_mday = 1;
}
else {
- args[2] = obj2int(v[2]);
- }
- for (i=3;i<6;i++) {
- if (NIL_P(v[i])) {
- args[i] = 0;
- }
- else {
- args[i] = obj2int(v[i]);
- }
+ tm->tm_mday = obj2long(v[2]);
}
+ tm->tm_hour = NIL_P(v[3])?0:obj2long(v[3]);
+ tm->tm_min = NIL_P(v[4])?0:obj2long(v[4]);
+ tm->tm_sec = NIL_P(v[5])?0:obj2long(v[5]);
/* value validation */
- if ( args[0] < 70|| args[0] > 137
- || args[1] < 0 || args[1] > 11
- || args[2] < 1 || args[2] > 31
- || args[3] < 0 || args[3] > 23
- || args[4] < 0 || args[4] > 59
- || args[5] < 0 || args[5] > 60)
+ if ( tm->tm_year < 69
+ || tm->tm_mon < 0 || tm->tm_mon > 11
+ || tm->tm_mday < 1 || tm->tm_mday > 31
+ || tm->tm_hour < 0 || tm->tm_hour > 23
+ || tm->tm_min < 0 || tm->tm_min > 59
+ || tm->tm_sec < 0 || tm->tm_sec > 60)
rb_raise(rb_eArgError, "argument out of range");
}
static VALUE time_gmtime _((VALUE));
static VALUE time_localtime _((VALUE));
-static VALUE
-time_gm_or_local(argc, argv, gm_or_local, klass)
- int argc;
- VALUE *argv;
- int gm_or_local;
- VALUE klass;
+static VALUE time_get_tm _((VALUE, int));
+
+static time_t
+make_time_t(tptr, fn)
+ struct tm *tptr;
+ struct tm *(*fn)();
{
- int args[6];
struct timeval tv;
- struct tm *tm;
time_t guess, t;
- int diff;
- struct tm *(*fn)();
- VALUE time;
-
- fn = (gm_or_local) ? gmtime : localtime;
- time_arg(argc, argv, args);
+ struct tm *tm;
+ long diff;
- gettimeofday(&tv, 0);
+ if (gettimeofday(&tv, 0) < 0) {
+ rb_sys_fail("gettimeofday");
+ }
guess = tv.tv_sec;
tm = (*fn)(&guess);
if (!tm) goto error;
- t = args[0];
+ t = tptr->tm_year;
+ if (t < 69) goto out_of_range;
while (diff = t - (tm->tm_year)) {
guess += diff * 364 * 24 * 3600;
- if (guess < 0) rb_raise(rb_eArgError, "too far future");
+ if (diff > 0 && guess < 0) goto out_of_range;
tm = (*fn)(&guess);
if (!tm) goto error;
}
- t = args[1];
+ t = tptr->tm_mon;
while (diff = t - tm->tm_mon) {
guess += diff * 27 * 24 * 3600;
tm = (*fn)(&guess);
if (!tm) goto error;
+ if (tptr->tm_year != tm->tm_year) goto out_of_range;
}
- guess += (args[2] - tm->tm_mday) * 3600 * 24;
- guess += (args[3] - tm->tm_hour) * 3600;
- guess += (args[4] - tm->tm_min) * 60;
- guess += args[5] - tm->tm_sec;
+ guess += (tptr->tm_mday - tm->tm_mday) * 3600 * 24;
+ guess += (tptr->tm_hour - tm->tm_hour) * 3600;
+ guess += (tptr->tm_min - tm->tm_min) * 60;
+ guess += tptr->tm_sec - tm->tm_sec;
+ if (guess < 0) goto out_of_range;
- time = time_new_internal(klass, guess, 0);
- if (gm_or_local) return time_gmtime(time);
- return time_localtime(time);
+ return guess;
+
+ out_of_range:
+ rb_raise(rb_eArgError, "time out of range");
error:
rb_raise(rb_eArgError, "gmtime/localtime error");
@@ -287,6 +306,25 @@ time_gm_or_local(argc, argv, gm_or_local, klass)
}
static VALUE
+time_gm_or_local(argc, argv, gm_or_local, klass)
+ int argc;
+ VALUE *argv;
+ int gm_or_local;
+ VALUE klass;
+{
+ struct tm tm;
+ struct tm *(*fn)();
+ VALUE time;
+
+ fn = (gm_or_local) ? gmtime : localtime;
+ time_arg(argc, argv, &tm);
+
+ time = time_new_internal(klass, make_time_t(&tm, fn), 0);
+ if (gm_or_local) return time_gmtime(time);
+ return time_localtime(time);
+}
+
+static VALUE
time_s_timegm(argc, argv, klass)
int argc;
VALUE *argv;
@@ -311,7 +349,7 @@ time_to_i(time)
struct time_object *tobj;
GetTimeval(time, tobj);
- return rb_int2inum(tobj->tv.tv_sec);
+ return INT2NUM(tobj->tv.tv_sec);
}
static VALUE
@@ -331,7 +369,7 @@ time_usec(time)
struct time_object *tobj;
GetTimeval(time, tobj);
- return INT2FIX(tobj->tv.tv_usec);
+ return INT2NUM(tobj->tv.tv_usec);
}
static VALUE
@@ -339,12 +377,12 @@ time_cmp(time1, time2)
VALUE time1, time2;
{
struct time_object *tobj1, *tobj2;
- int i;
+ long i;
GetTimeval(time1, tobj1);
switch (TYPE(time2)) {
case T_FIXNUM:
- i = FIX2INT(time2);
+ i = FIX2LONG(time2);
if (tobj1->tv.tv_sec == i) return INT2FIX(0);
if (tobj1->tv.tv_sec > i) return INT2FIX(1);
return FIX2INT(-1);
@@ -353,10 +391,13 @@ time_cmp(time1, time2)
{
double t;
- if (tobj1->tv.tv_sec == (int)RFLOAT(time2)->value) return INT2FIX(0);
+ if (tobj1->tv.tv_sec == (time_t)RFLOAT(time2)->value)
+ return INT2FIX(0);
t = (double)tobj1->tv.tv_sec + (double)tobj1->tv.tv_usec*1e-6;
- if (tobj1->tv.tv_sec == RFLOAT(time2)->value) return INT2FIX(0);
- if (tobj1->tv.tv_sec > RFLOAT(time2)->value) return INT2FIX(1);
+ if (tobj1->tv.tv_sec == (time_t)RFLOAT(time2)->value)
+ return INT2FIX(0);
+ if (tobj1->tv.tv_sec > (time_t)RFLOAT(time2)->value)
+ return INT2FIX(1);
return FIX2INT(-1);
}
}
@@ -371,7 +412,7 @@ time_cmp(time1, time2)
if (tobj1->tv.tv_sec > tobj2->tv.tv_sec) return INT2FIX(1);
return FIX2INT(-1);
}
- i = NUM2INT(time2);
+ i = NUM2LONG(time2);
if (tobj1->tv.tv_sec == i) return INT2FIX(0);
if (tobj1->tv.tv_sec > i) return INT2FIX(1);
return FIX2INT(-1);
@@ -394,11 +435,22 @@ time_eql(time1, time2)
}
static VALUE
+time_gmt_p(time)
+ VALUE time;
+{
+ struct time_object *tobj;
+
+ GetTimeval(time, tobj);
+ if (tobj->gmt) return Qtrue;
+ return Qfalse;
+}
+
+static VALUE
time_hash(time)
VALUE time;
{
struct time_object *tobj;
- int hash;
+ long hash;
GetTimeval(time, tobj);
hash = tobj->tv.tv_sec ^ tobj->tv.tv_usec;
@@ -406,19 +458,34 @@ time_hash(time)
}
static VALUE
+time_clone(time)
+ VALUE time;
+{
+ VALUE obj;
+ struct time_object *tobj, *newtobj;
+
+ GetTimeval(time, tobj);
+ obj = Data_Make_Struct(0, struct time_object, 0, free, newtobj);
+ CLONESETUP(obj, time);
+ MEMCPY(newtobj, tobj, struct time_object, 1);
+
+ return obj;
+}
+
+static VALUE
time_localtime(time)
VALUE time;
{
struct time_object *tobj;
struct tm *tm_tmp;
+ time_t t;
GetTimeval(time, tobj);
- tm_tmp = localtime((const time_t*)&tobj->tv.tv_sec);
+ t = tobj->tv.tv_sec;
+ tm_tmp = localtime(&t);
tobj->tm = *tm_tmp;
tobj->tm_got = 1;
-#ifndef HAVE_TM_ZONE
tobj->gmt = 0;
-#endif
return time;
}
@@ -428,18 +495,27 @@ time_gmtime(time)
{
struct time_object *tobj;
struct tm *tm_tmp;
+ time_t t;
GetTimeval(time, tobj);
- tm_tmp = gmtime((const time_t*)&tobj->tv.tv_sec);
+ t = tobj->tv.tv_sec;
+ tm_tmp = gmtime(&t);
tobj->tm = *tm_tmp;
tobj->tm_got = 1;
-#ifndef HAVE_TM_ZONE
tobj->gmt = 1;
-#endif
return time;
}
static VALUE
+time_get_tm(time, gmt)
+ VALUE time;
+ int gmt;
+{
+ if (gmt) return time_gmtime(time);
+ return time_localtime(time);
+}
+
+static VALUE
time_asctime(time)
VALUE time;
{
@@ -448,9 +524,9 @@ time_asctime(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
- s = asctime(&(tobj->tm));
+ s = asctime(&tobj->tm);
if (s[24] == '\n') s[24] = '\0';
return rb_str_new2(s);
@@ -461,21 +537,21 @@ time_to_s(time)
VALUE time;
{
struct time_object *tobj;
- char buf[64];
+ char buf[128];
int len;
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
#ifndef HAVE_TM_ZONE
if (tobj->gmt == 1) {
- len = strftime(buf, 64, "%a %b %d %H:%M:%S GMT %Y", &(tobj->tm));
+ len = strftime(buf, 128, "%a %b %d %H:%M:%S GMT %Y", &tobj->tm);
}
else
#endif
{
- len = strftime(buf, 64, "%a %b %d %H:%M:%S %Z %Y", &(tobj->tm));
+ len = strftime(buf, 128, "%a %b %d %H:%M:%S %Z %Y", &tobj->tm);
}
return rb_str_new(buf, len);
}
@@ -484,64 +560,67 @@ static VALUE
time_plus(time1, time2)
VALUE time1, time2;
{
- struct time_object *tobj1, *tobj2;
- long sec, usec;
+ struct time_object *tobj;
+ time_t sec, usec;
+ double f;
- GetTimeval(time1, tobj1);
- if (TYPE(time2) == T_FLOAT) {
- unsigned int nsec = (unsigned int)RFLOAT(time2)->value;
- sec = tobj1->tv.tv_sec + nsec;
- usec = tobj1->tv.tv_usec + (long)(RFLOAT(time2)->value-(double)nsec)*1e6;
- }
- else if (rb_obj_is_instance_of(time2, rb_cTime)) {
- GetTimeval(time2, tobj2);
- sec = tobj1->tv.tv_sec + tobj2->tv.tv_sec;
- usec = tobj1->tv.tv_usec + tobj2->tv.tv_usec;
- }
- else {
- sec = tobj1->tv.tv_sec + NUM2INT(time2);
- usec = tobj1->tv.tv_usec;
+ GetTimeval(time1, tobj);
+
+ if (rb_obj_is_kind_of(time2, rb_cTime)) {
+ rb_raise(rb_eTypeError, "time + time?");
}
+ f = NUM2DBL(time2);
+ sec = (time_t)f;
+ usec = tobj->tv.tv_usec + (time_t)((f - (double)sec)*1e6);
+ sec = tobj->tv.tv_sec + sec;
if (usec >= 1000000) { /* usec overflow */
sec++;
usec -= 1000000;
}
- return rb_time_new(sec, usec);
+ time2 = rb_time_new(sec, usec);
+ if (tobj->gmt) {
+ GetTimeval(time2, tobj);
+ tobj->gmt = 1;
+ }
+ return time2;
}
static VALUE
time_minus(time1, time2)
VALUE time1, time2;
{
- struct time_object *tobj1, *tobj2;
- int sec, usec;
+ struct time_object *tobj;
+ time_t sec, usec;
+ double f;
- GetTimeval(time1, tobj1);
+ GetTimeval(time1, tobj);
if (rb_obj_is_instance_of(time2, rb_cTime)) {
- double f;
+ struct time_object *tobj2;
GetTimeval(time2, tobj2);
- f = tobj1->tv.tv_sec - tobj2->tv.tv_sec;
-
- f += (tobj1->tv.tv_usec - tobj2->tv.tv_usec)*1e-6;
+ f = tobj->tv.tv_sec - tobj2->tv.tv_sec;
+ f += (tobj->tv.tv_usec - tobj2->tv.tv_usec)*1e-6;
return rb_float_new(f);
}
- else if (TYPE(time2) == T_FLOAT) {
- sec = tobj1->tv.tv_sec - (int)RFLOAT(time2)->value;
- usec = tobj1->tv.tv_usec - (RFLOAT(time2)->value - (double)sec)*1e6;
- }
else {
- sec = tobj1->tv.tv_sec - NUM2INT(time2);
- usec = tobj1->tv.tv_usec;
+ f = NUM2DBL(time2);
+ sec = (time_t)f;
+ usec = tobj->tv.tv_usec - (time_t)((f - (double)sec)*1e6);
+ sec = tobj->tv.tv_sec - sec;
}
if (usec < 0) { /* usec underflow */
sec--;
usec += 1000000;
}
- return rb_time_new(sec, usec);
+ time2 = rb_time_new(sec, usec);
+ if (tobj->gmt) {
+ GetTimeval(time2, tobj);
+ tobj->gmt = 1;
+ }
+ return time2;
}
static VALUE
@@ -552,7 +631,7 @@ time_sec(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_sec);
}
@@ -565,7 +644,7 @@ time_min(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_min);
}
@@ -578,7 +657,7 @@ time_hour(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_hour);
}
@@ -591,7 +670,7 @@ time_mday(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_mday);
}
@@ -604,7 +683,7 @@ time_mon(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_mon+1);
}
@@ -617,7 +696,7 @@ time_year(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_year+1900);
}
@@ -630,7 +709,7 @@ time_wday(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return INT2FIX(tobj->tm.tm_wday);
}
@@ -643,9 +722,9 @@ time_yday(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
- return INT2FIX(tobj->tm.tm_yday);
+ return INT2FIX(tobj->tm.tm_yday+1);
}
static VALUE
@@ -656,7 +735,7 @@ time_isdst(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return tobj->tm.tm_isdst?Qtrue:Qfalse;
}
@@ -666,15 +745,15 @@ time_zone(time)
VALUE time;
{
struct time_object *tobj;
- char buf[10];
+ char buf[64];
int len;
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
- len = strftime(buf, 10, "%Z", &(tobj->tm));
+ len = strftime(buf, 64, "%Z", &tobj->tm);
return rb_str_new(buf, len);
}
@@ -686,7 +765,7 @@ time_to_a(time)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
return rb_ary_new3(10,
INT2FIX(tobj->tm.tm_sec),
@@ -696,7 +775,7 @@ time_to_a(time)
INT2FIX(tobj->tm.tm_mon+1),
INT2FIX(tobj->tm.tm_year+1900),
INT2FIX(tobj->tm.tm_wday),
- INT2FIX(tobj->tm.tm_yday),
+ INT2FIX(tobj->tm.tm_yday+1),
tobj->tm.tm_isdst?Qtrue:Qfalse,
time_zone(time));
}
@@ -708,23 +787,31 @@ rb_strftime(buf, format, time)
char * volatile format;
struct tm * volatile time;
{
- volatile int i;
- int len;
+ volatile int size;
+ int len, flen;
+ (*buf)[0] = '\0';
+ flen = strlen(format);
+ if (flen == 0) {
+ return 0;
+ }
len = strftime(*buf, SMALLBUF, format, time);
if (len != 0) return len;
- for (i=1024; i<8192; i+=1024) {
- *buf = xmalloc(i);
- len = strftime(*buf, i-1, format, time);
- if (len == 0) {
- free(*buf);
- continue;
- }
- return len;
+ for (size=1024; ; size*=2) {
+ *buf = xmalloc(size);
+ (*buf)[0] = '\0';
+ len = strftime(*buf, size, format, time);
+ /*
+ * buflen can be zero EITHER because there's not enough
+ * room in the string, or because the control command
+ * goes to the empty string. Make a reasonable guess that
+ * if the buffer is 1024 times bigger than the length of the
+ * format string, it's not failing for lack of room.
+ */
+ if (len > 0 || len >= 1024 * flen) return len;
+ free(*buf);
}
-
- rb_raise(rb_eArgError, "bad strftime format or result too long");
- return Qnil; /* not reached */
+ /* not reached */
}
static VALUE
@@ -740,23 +827,28 @@ time_strftime(time, format)
GetTimeval(time, tobj);
if (tobj->tm_got == 0) {
- time_localtime(time);
+ time_get_tm(time, tobj->gmt);
}
fmt = str2cstr(format, &len);
+ if (len == 0) {
+ rb_warning("strftime called with empty format string");
+ }
if (strlen(fmt) < len) {
/* Ruby string may contain \0's. */
char *p = fmt, *pe = fmt + len;
str = rb_str_new(0, 0);
while (p < pe) {
- len = rb_strftime(&buf, p, &(tobj->tm));
+ len = rb_strftime(&buf, p, &tobj->tm);
rb_str_cat(str, buf, len);
p += strlen(p) + 1;
+ if (p <= pe)
+ rb_str_cat(str, "\0", 1);
if (len > SMALLBUF) free(buf);
}
return str;
}
- len = rb_strftime(&buf, RSTRING(format)->ptr, &(tobj->tm));
+ len = rb_strftime(&buf, RSTRING(format)->ptr, &tobj->tm);
str = rb_str_new(buf, len);
if (buf != buffer) free(buf);
return str;
@@ -797,26 +889,43 @@ time_s_times(obj)
}
static VALUE
-time_dump(time, limit)
- VALUE time, limit;
+time_dump(argc, argv, time)
+ int argc;
+ VALUE *argv;
+ VALUE time;
{
+ VALUE dummy;
struct time_object *tobj;
- int sec, usec;
+ struct tm *tm;
+ unsigned long p, s;
unsigned char buf[8];
+ time_t t;
int i;
+ rb_scan_args(argc, argv, "01", &dummy);
GetTimeval(time, tobj);
- sec = tobj->tv.tv_sec;
- usec = tobj->tv.tv_usec;
+
+ t = tobj->tv.tv_sec;
+ tm = gmtime(&t);
+
+ p = 0x1 << 31 | /* 1 */
+ tm->tm_year << 14 | /* 17 */
+ tm->tm_mon << 10 | /* 4 */
+ tm->tm_mday << 5 | /* 5 */
+ tm->tm_hour; /* 5 */
+ s = tm->tm_min << 26 | /* 6 */
+ tm->tm_sec << 20 | /* 6 */
+ tobj->tv.tv_usec; /* 20 */
for (i=0; i<4; i++) {
- buf[i] = sec & 0xff;
- sec = RSHIFT(sec, 8);
+ buf[i] = p & 0xff;
+ p = RSHIFT(p, 8);
}
for (i=4; i<8; i++) {
- buf[i] = usec & 0xff;
- usec = RSHIFT(usec, 8);
+ buf[i] = s & 0xff;
+ s = RSHIFT(s, 8);
}
+
return rb_str_new(buf, 8);
}
@@ -824,8 +933,10 @@ static VALUE
time_load(klass, str)
VALUE klass, str;
{
- int sec, usec;
+ unsigned long p, s;
+ time_t sec, usec;
unsigned char *buf;
+ struct tm tm;
int i;
buf = str2cstr(str, &i);
@@ -833,14 +944,28 @@ time_load(klass, str)
rb_raise(rb_eTypeError, "marshaled time format differ");
}
- sec = usec = 0;
+ p = s = 0;
for (i=0; i<4; i++) {
- sec |= buf[i]<<(8*i);
+ p |= buf[i]<<(8*i);
}
for (i=4; i<8; i++) {
- usec |= buf[i]<<(8*(i-4));
+ s |= buf[i]<<(8*(i-4));
}
+ if ((p & (1<<31)) == 0) {
+ return time_new_internal(klass, p, s);
+ }
+ p &= ~(1<<31);
+ tm.tm_year = (p >> 14) & 0x1ffff;
+ tm.tm_mon = (p >> 10) & 0xf;
+ tm.tm_mday = (p >> 5) & 0x1f;
+ tm.tm_hour = p & 0x1f;
+ tm.tm_min = (s >> 26) & 0x3f;
+ tm.tm_sec = (s >> 20) & 0x3f;
+
+ sec = make_time_t(&tm, gmtime);
+ usec = (time_t) s & 0xfffff;
+
return time_new_internal(klass, sec, usec);
}
@@ -864,6 +989,7 @@ Init_Time()
rb_define_method(rb_cTime, "<=>", time_cmp, 1);
rb_define_method(rb_cTime, "eql?", time_eql, 1);
rb_define_method(rb_cTime, "hash", time_hash, 0);
+ rb_define_method(rb_cTime, "clone", time_clone, 0);
rb_define_method(rb_cTime, "localtime", time_localtime, 0);
rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
@@ -889,6 +1015,8 @@ Init_Time()
rb_define_method(rb_cTime, "isdst", time_isdst, 0);
rb_define_method(rb_cTime, "zone", time_zone, 0);
+ rb_define_method(rb_cTime, "gmt?", time_gmt_p, 0);
+
rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
rb_define_method(rb_cTime, "usec", time_usec, 0);
@@ -900,6 +1028,6 @@ Init_Time()
#endif
/* methods for marshaling */
+ rb_define_method(rb_cTime, "_dump", time_dump, -1);
rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
- rb_define_method(rb_cTime, "_dump", time_dump, 1);
}