Bug #9951
closedDateTime.strftime and Time.strftime differ in how they treat "%L"
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.