From fbc42054e8375a532b2e0a3b82dded952c8992f7 Mon Sep 17 00:00:00 2001 From: akr Date: Wed, 31 Mar 2010 12:34:31 +0000 Subject: * time.c: less bignum allocations. * strftime.c (rb_strftime_timespec): defined to avoid rational for nano second resolution time. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 + strftime.c | 56 +++++-- test/ruby/test_time.rb | 29 ++++ time.c | 407 ++++++++++++++++++++++++++++++++----------------- 4 files changed, 347 insertions(+), 152 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1a6213322e..fa39c0fd9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Mar 31 21:30:38 2010 Tanaka Akira + + * time.c: less bignum allocations. + + * strftime.c (rb_strftime_timespec): defined to avoid rational for + nano second resolution time. + Wed Mar 31 16:05:13 2010 Nobuyoshi Nakada * test/rake/test_{package_task,rules,task_manager}.rb: use diff --git a/strftime.c b/strftime.c index f03d546669..2b98e29148 100644 --- a/strftime.c +++ b/strftime.c @@ -189,8 +189,8 @@ max(int a, int b) /* strftime --- produce formatted time */ -size_t -rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, int gmt) +static size_t +rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, struct timespec *ts, int gmt) { char *endp = s + maxsize; char *start = s; @@ -306,7 +306,7 @@ rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, } while (0) #define STRFTIME(fmt) \ do { \ - i = rb_strftime(s, endp - s, fmt, vtm, timev, gmt); \ + i = rb_strftime_with_timespec(s, endp - s, fmt, vtm, timev, ts, gmt); \ if (!i) return 0; \ if (precision > i) {\ memmove(s + precision - i, s, i);\ @@ -459,11 +459,18 @@ rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, break; case 's': - { + if (ts) { + time_t sec = ts->tv_sec; + if (~(time_t)0 <= 0) + FMT('0', 1, PRI_TIMET_PREFIX"d", sec); + else + FMT('0', 1, PRI_TIMET_PREFIX"u", sec); + } + else { VALUE sec = div(timev, INT2FIX(1)); FMTV('0', 1, "d", sec); - continue; } + continue; case 'S': /* second, 00 - 60 */ i = range(0, vtm->sec, 60); @@ -753,16 +760,31 @@ rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, */ w = 9; subsec: - { + if (precision <= 0) { + precision = w; + } + NEEDS(precision); + + if (ts) { + long subsec = ts->tv_nsec; + if (9 < precision) { + snprintf(s, endp - s, "%09ld", subsec); + memset(s+9, '0', precision-9); + s += precision; + } + else { + int i; + for (i = 0; i < 9-precision; i++) + subsec /= 10; + snprintf(s, endp - s, "%0*ld", precision, subsec); + s += precision; + } + } + else { VALUE subsec = mod(timev, INT2FIX(1)); int ww; long n; - if (precision <= 0) { - precision = w; - } - NEEDS(precision); - ww = precision; while (9 <= ww) { subsec = mul(subsec, INT2FIX(1000000000)); @@ -867,6 +889,18 @@ rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, return 0; } +size_t +rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, int gmt) +{ + return rb_strftime_with_timespec(s, maxsize, format, vtm, timev, NULL, gmt); +} + +size_t +rb_strftime_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, struct timespec *ts, int gmt) +{ + return rb_strftime_with_timespec(s, maxsize, format, vtm, Qnil, ts, gmt); +} + /* isleap --- is a year a leap year? */ #ifndef __STDC__ diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index 5543951778..108fcdbc20 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -172,6 +172,15 @@ class TestTime < Test::Unit::TestCase t = Time.at(2**40 + "1/3".to_r, 9999999999999).utc assert_equal(36812, t.year) + + t = Time.at(-0x3fff_ffff_ffff_ffff) + assert_equal(-146138510344, t.year) + t = Time.at(-0x4000_0000_0000_0000) + assert_equal(-146138510344, t.year) + t = Time.at(-0x4000_0000_0000_0001) + assert_equal(-146138510344, t.year) + t = Time.at(-0x5000_0000_0000_0001) + assert_equal(-182673138422, t.year) end def test_at2 @@ -579,6 +588,26 @@ class TestTime < Test::Unit::TestCase assert_equal("JANUARY", T2000.strftime("%#B")) assert_equal("JAN", T2000.strftime("%#h")) assert_equal("FRIDAY", Time.local(2008,1,4).strftime("%#A")) + + t = Time.utc(2000,3,14, 6,53,"58.979323846".to_r) # Pi Day + assert_equal("03/14/2000 6:53:58.97932384600000000000000000000", + t.strftime("%m/%d/%Y %l:%M:%S.%29N")) + assert_equal("03/14/2000 6:53:58.9793238460", + t.strftime("%m/%d/%Y %l:%M:%S.%10N")) + assert_equal("03/14/2000 6:53:58.979323846", + t.strftime("%m/%d/%Y %l:%M:%S.%9N")) + assert_equal("03/14/2000 6:53:58.97932384", + t.strftime("%m/%d/%Y %l:%M:%S.%8N")) + + t = Time.utc(1592,3,14, 6,53,"58.97932384626433832795028841971".to_r) # Pi Day + assert_equal("03/14/1592 6:53:58.97932384626433832795028841971", + t.strftime("%m/%d/%Y %l:%M:%S.%29N")) + assert_equal("03/14/1592 6:53:58.9793238462", + t.strftime("%m/%d/%Y %l:%M:%S.%10N")) + assert_equal("03/14/1592 6:53:58.979323846", + t.strftime("%m/%d/%Y %l:%M:%S.%9N")) + assert_equal("03/14/1592 6:53:58.97932384", + t.strftime("%m/%d/%Y %l:%M:%S.%8N")) end def test_delegate diff --git a/time.c b/time.c index 7217951fa3..c67f99c314 100644 --- a/time.c +++ b/time.c @@ -31,134 +31,6 @@ static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift; #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) -#if SIZEOF_LONG == 8 -# define INT64toNUM(x) LONG2NUM(x) -# define UINT64toNUM(x) ULONG2NUM(x) -#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 -# define INT64toNUM(x) LL2NUM(x) -# define UINT64toNUM(x) ULL2NUM(x) -#endif - -#if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T - typedef uint64_t uwideint_t; - typedef int64_t wideint_t; - typedef uint64_t WIDEVALUE; - typedef int64_t SIGNED_WIDEVALUE; -# define WIDEVALUE_IS_WIDER 1 -# define FIXWINT_P(tv) ((tv) & 1) -# define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1) -# define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG)) -# define FIXWV_MAX (((int64_t)1 << 62) - 1) -# define FIXWV_MIN (-((int64_t)1 << 62)) -# define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1) -# define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN) -# define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi)) -# define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i)) -# define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w)) -#else - typedef unsigned long uwideint_t; - typedef long wideint_t; - typedef VALUE WIDEVALUE; - typedef SIGNED_VALUE SIGNED_WIDEVALUE; -# define WIDEVALUE_IS_WIDER 0 -# define FIXWINT_P(v) FIXNUM_P(v) -# define FIXWVABLE(i) FIXABLE(i) -# define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i)) -# define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w)) -#endif - -#define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w)) - -#define STRUCT_WIDEVAL -/* #define STRUCT_WIDEVAL */ -#ifdef STRUCT_WIDEVAL - /* for type checking */ - typedef struct { - WIDEVALUE value; - } wideval_t; - static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; } -# define WIDEVAL_GET(w) ((w).value) -#else - typedef WIDEVALUE wideval_t; -# define WIDEVAL_WRAP(v) (v) -# define WIDEVAL_GET(w) (w) -#endif - -#if WIDEVALUE_IS_WIDER - static inline wideval_t - wint2wv(wideint_t wi) - { - if (FIXWVABLE(wi)) - return WINT2FIXWV(wi); - else - return WIDEVAL_WRAP(INT64toNUM(wi)); - } -# define WINT2WV(wi) wint2wv(wi) -#else -# define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi)) -#endif - -static inline VALUE -w2v(wideval_t w) -{ -#if WIDEVALUE_IS_WIDER - if (FIXWV_P(w)) - return INT64toNUM(FIXWV2WINT(w)); - return (VALUE)WIDEVAL_GET(w); -#else - return WIDEVAL_GET(w); -#endif -} - -#if WIDEVALUE_IS_WIDER -# if SIZEOF_UINT64_T % SIZEOF_BDIGITS != 0 -# error SIZEOF_UINT64 is not multiple of SIZEOF_BDIGITS -# endif -static wideval_t -xv2w_bignum(VALUE xv) -{ - long len = RBIGNUM_LEN(xv); - BDIGIT *ds; - wideval_t w; - ds = RBIGNUM_DIGITS(xv); - w = WIDEVAL_WRAP(xv); - if (RBIGNUM_POSITIVE_P(xv)) { - if (ds[len-1] < ((BDIGIT)1 << (sizeof(BDIGIT)*CHAR_BIT-2))) { - wideint_t i = 0; - while (len) - i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len]; - if (FIXWVABLE(i)) - w = WINT2FIXWV(i); - } - } - else { - if (ds[len-1] < ((BDIGIT)1 << (sizeof(BDIGIT)*CHAR_BIT-2))) { - wideint_t i = 0; - while (len) - i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len]; - i = -i; - w = WINT2FIXWV(i); - } - } - return w; -} -#endif - -static inline wideval_t -v2w(VALUE xv) -{ -#if WIDEVALUE_IS_WIDER - if (FIXNUM_P(xv)) { - return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(long)xv); - } - else if (TYPE(xv) == T_BIGNUM && - RBIGNUM_LEN(xv) * sizeof(BDIGIT) <= sizeof(WIDEVALUE)) { - return xv2w_bignum(xv); - } -#endif - return WIDEVAL_WRAP(xv); -} - static int eq(VALUE x, VALUE y) { @@ -285,6 +157,192 @@ divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r) *r = rb_ary_entry(ary, 1); } +#if SIZEOF_LONG == 8 +# define INT64toNUM(x) LONG2NUM(x) +# define UINT64toNUM(x) ULONG2NUM(x) +#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8 +# define INT64toNUM(x) LL2NUM(x) +# define UINT64toNUM(x) ULL2NUM(x) +#endif + +#if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T + typedef uint64_t uwideint_t; + typedef int64_t wideint_t; + typedef uint64_t WIDEVALUE; + typedef int64_t SIGNED_WIDEVALUE; +# define WIDEVALUE_IS_WIDER 1 +# define FIXWINT_P(tv) ((tv) & 1) +# define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1) +# define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG)) +# define FIXWV_MAX (((int64_t)1 << 62) - 1) +# define FIXWV_MIN (-((int64_t)1 << 62)) +# define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1) +# define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN) +# define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi)) +# define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i)) +# define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w)) +#else + typedef unsigned long uwideint_t; + typedef long wideint_t; + typedef VALUE WIDEVALUE; + typedef SIGNED_VALUE SIGNED_WIDEVALUE; +# define WIDEVALUE_IS_WIDER 0 +# define FIXWINT_P(v) FIXNUM_P(v) +# define FIXWVABLE(i) FIXABLE(i) +# define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i)) +# define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w)) +#endif + +#define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w)) + +/* #define STRUCT_WIDEVAL */ +#ifdef STRUCT_WIDEVAL + /* for type checking */ + typedef struct { + WIDEVALUE value; + } wideval_t; + static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; } +# define WIDEVAL_GET(w) ((w).value) +#else + typedef WIDEVALUE wideval_t; +# define WIDEVAL_WRAP(v) (v) +# define WIDEVAL_GET(w) (w) +#endif + +#if WIDEVALUE_IS_WIDER + static inline wideval_t + wint2wv(wideint_t wi) + { + if (FIXWVABLE(wi)) + return WINT2FIXWV(wi); + else + return WIDEVAL_WRAP(INT64toNUM(wi)); + } +# define WINT2WV(wi) wint2wv(wi) +#else +# define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi)) +#endif + +static inline VALUE +w2v(wideval_t w) +{ +#if WIDEVALUE_IS_WIDER + if (FIXWV_P(w)) + return INT64toNUM(FIXWV2WINT(w)); + return (VALUE)WIDEVAL_GET(w); +#else + return WIDEVAL_GET(w); +#endif +} + +#if WIDEVALUE_IS_WIDER +static int +bdigit_find_maxbit(BDIGIT d) +{ + int res = 0; + if (d & ~(BDIGIT)0xffff) { + d >>= 16; + res += 16; + } + if (d & ~(BDIGIT)0xff) { + d >>= 8; + res += 8; + } + if (d & ~(BDIGIT)0xf) { + d >>= 4; + res += 4; + } + if (d & ~(BDIGIT)0x3) { + d >>= 2; + res += 2; + } + if (d & ~(BDIGIT)0x1) { + d >>= 1; + res += 1; + } + return res; +} + +static VALUE +rb_big_abs_find_maxbit(VALUE big) +{ + BDIGIT *ds = RBIGNUM_DIGITS(big); + BDIGIT d; + long len = RBIGNUM_LEN(big); + VALUE res; + while (0 < len && ds[len-1] == 0) + len--; + if (len == 0) + return Qnil; + res = mul(LONG2NUM(len-1), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT)); + d = ds[len-1]; + res = add(res, LONG2FIX(bdigit_find_maxbit(d))); + return res; +} + +static VALUE +rb_big_abs_find_minbit(VALUE big) +{ + BDIGIT *ds = RBIGNUM_DIGITS(big); + BDIGIT d; + long len = RBIGNUM_LEN(big); + long i; + VALUE res; + for (i = 0; i < len; i++) + if (ds[i]) + break; + if (i == len) + return Qnil; + res = mul(LONG2NUM(i), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT)); + d = ds[i]; + res = add(res, LONG2FIX(bdigit_find_maxbit(d))); + return res; +} + +static wideval_t +v2w_bignum(VALUE v) +{ + long len = RBIGNUM_LEN(v); + BDIGIT *ds; + wideval_t w; + VALUE maxbit; + ds = RBIGNUM_DIGITS(v); + w = WIDEVAL_WRAP(v); + maxbit = rb_big_abs_find_maxbit(v); + if (NIL_P(maxbit)) + return WINT2FIXWV(0); + if (lt(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) || + (eq(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) && + RBIGNUM_NEGATIVE_P(v) && + eq(rb_big_abs_find_minbit(v), INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)))) { + wideint_t i; + i = 0; + while (len) + i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len]; + if (RBIGNUM_NEGATIVE_P(v)) { + i = -i; + } + w = WINT2FIXWV(i); + } + return w; +} +#endif + +static inline wideval_t +v2w(VALUE v) +{ +#if WIDEVALUE_IS_WIDER + if (FIXNUM_P(v)) { + return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(long)v); + } + else if (TYPE(v) == T_BIGNUM && + RBIGNUM_LEN(v) * sizeof(BDIGIT) <= sizeof(WIDEVALUE)) { + return v2w_bignum(v); + } +#endif + return WIDEVAL_WRAP(v); +} + static inline int weq(wideval_t wx, wideval_t wy) { @@ -351,7 +409,7 @@ wsub(wideval_t wx, wideval_t wy) static wideval_t wmul(wideval_t wx, wideval_t wy) { - VALUE x; + VALUE x, z; #if WIDEVALUE_IS_WIDER if (FIXWV_P(wx) && FIXWV_P(wy)) { wideint_t a, b, c; @@ -366,7 +424,11 @@ wmul(wideval_t wx, wideval_t wy) #endif x = w2v(wx); if (TYPE(x) == T_BIGNUM) return v2w(rb_big_mul(x, w2v(wy))); - return v2w(rb_funcall(x, '*', 1, w2v(wy))); + z = rb_funcall(x, '*', 1, w2v(wy)); + if (TYPE(z) == T_RATIONAL && RRATIONAL(z)->den == INT2FIX(1)) { + z = RRATIONAL(z)->num; + } + return v2w(z); } static int @@ -488,6 +550,33 @@ wdivmod(wideval_t wn, wideval_t wd, wideval_t *wq, wideval_t *wr) *wr = v2w(rb_ary_entry(ary, 1)); } +static void +wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr) +{ + if (WIDEVAL_GET(wy) == WIDEVAL_GET(wz)) { + *wq = wx; + *wr = WINT2FIXWV(0); + return; + } + wdivmod(wmul(wx,wy), wz, wq, wr); +} + +static wideval_t +wdiv(wideval_t wx, wideval_t wy) +{ + wideval_t q, r; + wdivmod(wx, wy, &q, &r); + return q; +} + +static wideval_t +wmod(wideval_t wx, wideval_t wy) +{ + wideval_t q, r; + wdivmod(wx, wy, &q, &r); + return r; +} + static VALUE num_exact(VALUE v) { @@ -1086,7 +1175,7 @@ init_leap_second_info() timew = timegmw_noleapsecond(&vtm); - number_of_leap_seconds_known = NUM2INT(sub(TIMET2NUM(known_leap_seconds_limit), w2v(rb_time_unmagnify(timew)))); + number_of_leap_seconds_known = NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew)))); } } @@ -1633,13 +1722,31 @@ timew2timespec(wideval_t timew) wideval_t timew2; if (timew_out_of_timet_range(timew)) - rb_raise(rb_eArgError, "time out of system range"); + rb_raise(rb_eArgError, "time out of system range"); split_second(timew, &timew2, &subsecx); ts.tv_sec = WV2TIMET(timew2); ts.tv_nsec = NUM2LONG(mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE))); return ts; } +static struct timespec * +timew2timespec_exact(wideval_t timew, struct timespec *ts) +{ + VALUE subsecx; + wideval_t timew2; + VALUE nsecv; + + if (timew_out_of_timet_range(timew)) + return NULL; + split_second(timew, &timew2, &subsecx); + ts->tv_sec = WV2TIMET(timew2); + nsecv = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE)); + if (!FIXNUM_P(nsecv)) + return NULL; + ts->tv_nsec = NUM2LONG(nsecv); + return ts; +} + /* * Document-method: now * @@ -2862,7 +2969,7 @@ time_to_i(VALUE time) struct time_object *tobj; GetTimeval(time, tobj); - return div(w2v(tobj->timew), INT2FIX(TIME_SCALE)); + return w2v(wdiv(tobj->timew, WINT2FIXWV(TIME_SCALE))); } /* @@ -2934,9 +3041,13 @@ static VALUE time_usec(VALUE time) { struct time_object *tobj; + wideval_t w, q, r; GetTimeval(time, tobj); - return rb_to_int(mulquo(mod(w2v(tobj->timew), INT2FIX(TIME_SCALE)), INT2FIX(1000000), INT2FIX(TIME_SCALE))); + + w = wmod(tobj->timew, WINT2WV(TIME_SCALE)); + wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r); + return rb_to_int(w2v(q)); } /* @@ -2962,7 +3073,7 @@ time_nsec(VALUE time) struct time_object *tobj; GetTimeval(time, tobj); - return rb_to_int(mulquo(mod(w2v(tobj->timew), INT2FIX(TIME_SCALE)), INT2FIX(1000000000), INT2FIX(TIME_SCALE))); + return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE))); } /* @@ -3983,12 +4094,20 @@ rb_strftime(char *s, size_t maxsize, const char *format, const struct vtm *vtm, VALUE timev, int gmt); +size_t +rb_strftime_timespec(char *s, size_t maxsize, const char *format, const struct vtm *vtm, struct timespec *ts, int gmt); + #define SMALLBUF 100 static size_t rb_strftime_alloc(char **buf, const char *format, - struct vtm *vtm, VALUE timev, int gmt) + struct vtm *vtm, wideval_t timew, int gmt) { size_t size, len, flen; + VALUE timev = Qnil; + struct timespec ts; + + if (!timew2timespec_exact(timew, &ts)) + timev = w2v(rb_time_unmagnify(timew)); (*buf)[0] = '\0'; flen = strlen(format); @@ -3996,12 +4115,18 @@ rb_strftime_alloc(char **buf, const char *format, return 0; } errno = 0; - len = rb_strftime(*buf, SMALLBUF, format, vtm, timev, gmt); + if (timev == Qnil) + len = rb_strftime_timespec(*buf, SMALLBUF, format, vtm, &ts, gmt); + else + len = rb_strftime(*buf, SMALLBUF, format, vtm, timev, gmt); if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len; for (size=1024; ; size*=2) { *buf = xmalloc(size); (*buf)[0] = '\0'; - len = rb_strftime(*buf, size, format, vtm, timev, gmt); + if (timev == Qnil) + len = rb_strftime_timespec(*buf, size, format, vtm, &ts, gmt); + else + len = rb_strftime(*buf, size, format, vtm, timev, gmt); /* * buflen can be zero EITHER because there's not enough * room in the string, or because the control command @@ -4025,7 +4150,7 @@ strftimev(const char *fmt, VALUE time) GetTimeval(time, tobj); MAKE_TM(time, tobj); - len = rb_strftime_alloc(&buf, fmt, &tobj->vtm, w2v(rb_time_unmagnify(tobj->timew)), TIME_UTC_P(tobj)); + len = rb_strftime_alloc(&buf, fmt, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj)); str = rb_str_new(buf, len); if (buf != buffer) xfree(buf); return str; @@ -4123,7 +4248,7 @@ time_strftime(VALUE time, VALUE format) str = rb_str_new(0, 0); while (p < pe) { - len = rb_strftime_alloc(&buf, p, &tobj->vtm, w2v(rb_time_unmagnify(tobj->timew)), TIME_UTC_P(tobj)); + len = rb_strftime_alloc(&buf, p, &tobj->vtm, tobj->timew, TIME_UTC_P(tobj)); rb_str_cat(str, buf, len); p += strlen(p); if (buf != buffer) { @@ -4137,7 +4262,7 @@ time_strftime(VALUE time, VALUE format) } else { len = rb_strftime_alloc(&buf, RSTRING_PTR(format), - &tobj->vtm, w2v(rb_time_unmagnify(tobj->timew)), TIME_UTC_P(tobj)); + &tobj->vtm, tobj->timew, TIME_UTC_P(tobj)); } str = rb_str_new(buf, len); if (buf != buffer) xfree(buf); -- cgit v1.2.3