You may be surprised to hear that MySQL datetime column type only store timestamps with second accuracy. Even tho Ruby Time class supports microsecond representation, this is lost when persisting as timestamp.

If you need greater precision for your timestamp, you can't rely on the automated Rails support. Fortunately, there is an easy workaround. You can store time representation in the database as seconds, with decimal support, and convert back and worth.

Here is an example of how to store milliseconds precision. First, define a column in your schema:

class CreateLogEntries < ActiveRecord::Migration
  def change
    create_table :log_entries do |t|
      ...
      t.decimal :occured_at_in_seconds, :precision => 17, :scale => 3
      ...
    end
  end
end

The occured_at_in_seconds column can now contain decimal representation of time in seconds, with 3 decimal precision which is needed for milliseconds. If you need to go down to the microseconds level, you can increase this to 6.

Now all we need is to map this field in our model. We could override attribute accessors, but there is a much more elegant way to deal with this in Rails. We're going to use composed_of macro.

class LogEntry < ActiveRecord::Base
  composed_of :occured_at,
              :class_name => "Time",
              :mapping => %w(occured_at_in_seconds to_r),
              :constructor => Proc.new { |t| Time.at(t) },
              :converter => Proc.new { |t| t.is_a?(Time) ? t : Time.at(t/1000.0) }

... end

Because Time.at(...) supports fractional seconds, we can simply retrieve the value from the database and create a Time object from it.

Conversely, we can assign a time object or map some other value. In my case, I wanted to be able to assign milliseconds time directly. So the following will be supported:

# Milliseconds since Epoch as returned by new Date().getTime() in Javascript
log_entry = LogEntry.new({:occured_at => 1317052347588})

# Time object with millisecond precision log_entry = LogEntry.new({:occured_at => Time.now})

That's all there is to it.