I have a string like 2012-01-01T01:02:03.456
that I am storing in a Postgres database TIMESTAMP using ActiveRecord.
Unfortunately, Ruby seems to chop off the milliseconds:
ruby-1.9.3-rc1 :078 > '2012-12-31T01:01:01.232323+3'.to_datetime => Mon, 31 Dec 2012 01:01:01 +0300
Postgrs supports microsecond resolution. How can I get my timestamp to be saved accordingly? I need at least millisecond resolution.
(PS Yes I could hack in a milliseconds integer column in postgres; that kind of defeats the whole purpose of ActiveRecord.)
UPDATE:
The very helpful responses showed that Ruby's DateTime
is not chopping off milliseconds; using #to_f
shows it. But, doing:
m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime m.save! m.reload m.happened_at.to_f
Does drop the milliseconds.
Now, the interesting thing is that created_at
does show milliseconds, both in Rails and Postgres. But other timestamps fields (like happened_at
above) don't. (Perhaps Rails uses a NOW()
function for created_at
as opposed to passing in a DateTime).
Which leads to my ultimate question:
How can I get ActiveRecord to preserve millisecond resolution on timestamp fields?
ActiveRecord should preserve the full precision from the database, you're just not looking at it properly. Use strftime
and the %N
format to see the fractional seconds. For example, psql
says this:
=> select created_at from models where id = 1; created_at ---------------------------- 2012-02-07 07:36:20.949641 (1 row)
and ActiveRecord says this:
> Model.find(1).created_at.strftime('%Y-%m-%d %H:%M:%S.%N') => "2012-02-07 07:36:20.949641000"
So everything is there, you just need to know how to see it.
Also note that ActiveRecord will probably give you ActiveSupport::TimeWithZone
objects rather than DateTime
objects but DateTime
preserves everything too:
> '2012-12-31T01:01:01.232323+3'.to_datetime.strftime('%Y-%m-%d %H:%M:%S.%N') => "2012-12-31 01:01:01.232323000"
Have a look at connection_adapters/column.rb
in the ActiveRecord source and check what the string_to_time
method does. Your string would go down the fallback_string_to_time
path and that preserves fractional seconds as near as I can tell. Something strange could be going on elsewhere, I wouldn't be surprised given the strange things I've seen in the Rails source, especially the database side of things. I'd try converting the strings to objects by hand so that ActiveRecord will keeps its hands off them.
Changing m.happened_at = '2012-01-01T00:00:00.32323'.to_datetime
in the code above to m.happened_at = '2012-01-01T00:00:00.32323'
solves the problem, though I have no idea why.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With