Bug #10135
closed
Added by thesmart (John Smart) over 10 years ago.
Updated about 10 years ago.
ruby -v:
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
[ruby-core:64369]
Description
I believe I have found an issue with Time.at. Many runtimes and DBs use milliseconds since epoch for recording time. Currently, the only way to generate a Time in ruby with milliseconds is:
Time.at(milliseconds / 1000.0)
However, this is inaccurate:
> Time.at(1381089302195 / 1000.0).to_f
=> 1381089302.1949997
> Time.at(1381089302195 / 1000.0).strftime('%3N')
=> "194"
This doesn't make much sense because you would expect:
> 1381089302195 / 1000.0
=> 1381089302.195
> (1381089302195 / 1000.0).to_f
=> 1381089302.195
It seems that somewhere in the MRI, someone is using floating-point math to represent a Time.
Is there any other way (workaround) to construct Time with millisecond accuracy?
Your way of presentation may not be clear. I suppose the division is irrelevant here. Your point seems to be that while to_f
is idempotent with:
1381089302.195.to_f
#=> 1381089302.195
the float stored by Time.at
is not the same float:
Time.at(1381089302.195).to_f
#=> 1381089302.1949997
I didn't know this before, but I investigated this and see Time.at
may take a second argument for microseconds. You may try:
Time.at(seconds, microseconds_with_frac) -> time
n = 1381089302195
p Time.at(n / 1000, (n % 1000) * 1_000).strftime('%3N')
- Related to Bug #10136: printf("%.60f\n", 0.1r) shows 0.100000000000000005551115123125782702118158340454101562500000 added
- Assignee changed from core to akr (Akira Tanaka)
- Priority changed from 5 to 3
1381089302.195 cannot be represented in binary format.
AFAIK, it should be a spec by akr that Time#strftime('%N')
truncates but doesn't round.
John Smart wrote:
I believe I have found an issue with Time.at. Many runtimes and DBs use milliseconds since epoch for recording time. Currently, the only way to generate a Time in ruby with milliseconds is:
Time.at(milliseconds / 1000.0)
Another (better) way is:
Time.at(milliseconds.to_r / 1000)
That passes the non-integer seconds as a Rational rather than a Float so precision is maintained:
>> Time.at(1381089302195.to_r / 1000).strftime('%N')
=> "195000000"
# Modern Ruby (since 2.x?) can use 'r' suffix for literal Rationals
>> Time.at(1381089302195r / 1000).strftime('%N')
=> "195000000"
It seems that somewhere in the MRI, someone is using floating-point math to represent a Time.
Actually, you were the one who started using floating point math to represent Time when you divided milliseconds
by 1000.0
! :-)
- Status changed from Open to Rejected
John Smart wrote:
It seems that somewhere in the MRI, someone is using floating-point math to represent a Time.
You use floating point math in 1381089302195 / 1000.0 which is
1381089302.1949999332427978515625.
The Time instance contains the value and strftime('%3N') truncates digits
after 3 digits, as documented (with a reason).
Floating point math is not used except conversion from the given argument to
rational.
Is there any other way (workaround) to construct Time with millisecond accuracy?
You can use the rational or the second argument of Time.at as others explained.
Tsuyoshi Sawada wrote:
the float stored by Time.at
is not the same float:
Time.at(1381089302.195).to_f
#=> 1381089302.1949997
This is another story.
Time#to_f is not accurate.
There are workaround, though:
Time.at(1381089302.195).to_r.to_f
#=> 1381089302.195
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0