Reputation: 6961
While testing some Ruby code, I ran into some strange behavior. Can someone please explain why Time.now
doesn't match the same time created from either Time.at
or parsed from Time.parse
?
[1] pry(main)> require 'time'
=> true
[2] pry(main)> t = Time.now
=> 2013-04-04 19:46:49 -0400
[3] pry(main)> i = Time.at t.to_i
=> 2013-04-04 19:46:49 -0400
[4] pry(main)> t == i
=> false
[5] pry(main)> t.to_i == i.to_i
=> true
[6] pry(main)> p = Time.parse t.to_s
=> 2013-04-04 19:46:49 -0400
[7] pry(main)> t == p
=> false
[8] pry(main)> t.to_i == p.to_i
=> true
[8] pry(main)> t.class
=> Time
[9] pry(main)> i.class
=> Time
[10] pry(main)> p.class
=> Time
[11] pry(main)> t.inspect
=> "2013-04-04 19:46:49 -0400"
[12] pry(main)> i.inspect
=> "2013-04-04 19:46:49 -0400"
[13] pry(main)> p.inspect
=> "2013-04-04 19:46:49 -0400"
It seems even trying to get sub-second precision shows the same behavior:
[1] pry(main)> t = Time.now
=> 2013-04-04 20:04:47 -0400
[2] pry(main)> f = Time.at t.to_f
=> 2013-04-04 20:04:47 -0400
[3] pry(main)> t == f
=> false
[4] pry(main)> t.to_f
=> 1365120287.902954
[5] pry(main)> f.to_f
=> 1365120287.902954
Upvotes: 3
Views: 129
Reputation: 160551
I'll take a shot at 'splaining what you're seeing. Here are several comparisons of a Time value, and what happens when converting between different formats. I'm not going to do any equality checks, because you'll be able to see whether a value should match simply by looking at it:
require 'time'
t_now = Time.now # => 2013-04-04 20:10:17 -0700
That's the inspect
output, which throws away a lot of information and precision. It's good enough for use by mortals.
t_now.to_f # => 1365131417.613106
That's the value the computer sees usually, with microseconds.
t_now.to_i # => 1365131417
That's the same time with microseconds all gone.
Time.at(t_now) # => 2013-04-04 20:10:17 -0700
Time.at(t_now.to_f) # => 2013-04-04 20:10:17 -0700
Time.at(t_now.to_i) # => 2013-04-04 20:10:17 -0700
t_now.to_s # => "2013-04-04 20:10:17 -0700"
Normal inspect
and to_s
output won't show any difference in the precision as long as the integer portion of the value is intact.
Time.parse(t_now.to_s) # => 2013-04-04 20:10:17 -0700
Time.parse(t_now.to_s).to_f # => 1365131417.0
Parsing loses the resolution, unless you present a value that contains the fractional time and define the parsing format so strptime
knows what to do with it. The default parser formats are designed for general-use, not high-precision, so we have to use strftime
instead of allowing to_s
to have its way with the value, and strptime
to know what all those numbers mean:
T_FORMAT = '%Y/%m/%d-%H:%M:%S.%N' # => "%Y/%m/%d-%H:%M:%S.%N"
t_now.strftime(T_FORMAT) # => "2013/04/04-20:10:17.613106000"
Time.strptime(t_now.strftime(T_FORMAT), T_FORMAT).to_f # => 1365131417.613106
Upvotes: 3
Reputation: 1599
The fractional seconds are different:
>> t = Time.now
=> 2013-04-04 17:34:34 -0700
>> f = Time.at(t.to_f)
=> 2013-04-04 17:34:34 -0700
>> t.usec
=> 571153
>> f.usec
=> 571152
>> t.nsec
=> 571153000
>> f.nsec
=> 571152925
Upvotes: 2
Reputation: 211560
It's probable that the two times are actually different but you're not seeing the differences with the representations you've chosen.
Try:
t.to_f == i.to_f
I think you'll see that t
has more precision than i
does.
Internally Time
is represented as a floating point value, with sub-second accuracy. Typically you can depend on it being accurate to within one millionth of a second, and sometimes even more depending on your OS.
Upvotes: 1