Project

General

Profile

Actions

Bug #9951

closed

DateTime.strftime and Time.strftime differ in how they treat "%L"

Added by dchelimsky (David Chelimsky) almost 10 years ago. Updated almost 10 years ago.

Status:
Rejected
Target version:
-
ruby -v:
1.9.3 - 2.1.1
[ruby-core:63211]

Description

DateTime.new(2014,1,2,3,4,5.678).strftime("%L")
# => "678"
Time.new(2014,1,2,3,4,5.678).strftime("%L")
# => "677"

I think these should both produce "678", but at the very least they should produce the same number so users don't have to special case one or the other. I realize there is floating point math under the hood here, but that's an implementation detail I don't think users should care about in this case.

Updated by nobu (Nobuyoshi Nakada) almost 10 years ago

  • Description updated (diff)
  • Status changed from Open to Assigned
  • Assignee set to akr (Akira Tanaka)

DateTime seems to round the fraction of second in nanoseconds at initialization.

Updated by phasis68 (Heesob Park) almost 10 years ago

Time seems to truncate the fraction of second in strftime.

Here is a patch

diff --git a/strftime.c b/strftime.c
index 83550e9..a0a7de5 100644
--- a/strftime.c
+++ b/strftime.c
@@ -705,7 +705,7 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, rb_encodi
                                 else {
                                         int i;
                                         for (i = 0; i < 9-precision; i++)
-                                                subsec /= 10;
+                                                subsec = (int)(subsec/10.0+0.5);
                                         snprintf(s, endp - s, "%0*ld", precision, subsec);
                                         s += precision;
                                 }
@@ -725,7 +725,7 @@ rb_strftime_with_timespec(char *s, size_t maxsize, const char *format, rb_encodi
                                         n *= 10;
                                 if (n != 1)
                                         subsec = mul(subsec, INT2FIX(n));
-                                subsec = div(subsec, INT2FIX(1));
+                                subsec = div(add(subsec,DBL2NUM(0.5)), INT2FIX(1));
 
                                 if (FIXNUM_P(subsec)) {
                                         (void)snprintf(s, endp - s, "%0*ld", precision, FIX2LONG(subsec));

Updated by akr (Akira Tanaka) almost 10 years ago

  • Status changed from Assigned to Rejected

The problem of float is ruby can not know what user want to
specify 5.678 or 5.67799999999999993605115378159098327159881591796875.

DateTime's rounding to nanosecond means DateTime suppose
users don't want to specify under-nanosecond time.
I don't want to such assumption for Time.

%L uses floor because 0.9999 should be shown as 999, not 1000.

So, I don't have idea to solve this issue in Ruby side.

Please use rational, such as 5.678r.

% ruby -e 'p Time.new(2014,1,2,3,4,5.678r).strftime("%L")' 
"678"

Updated by dchelimsky (David Chelimsky) almost 10 years ago

Akira, thanks for the "rational" suggestion. That appears to solve the problem for me.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0