Ronak Jain
Ronak Jain

Reputation: 1793

Rails ActiveRecord Timestamp in Epoch instead of DateTime Format

Need to store created_at and updated_at timestamps in Epoch instead of DateTime Format. Is there a way to alter the default behaviour, while having ORM to do it's job to maintain the timestamp.

When I use Rails Generator to generate my models

class CreateTenants < ActiveRecord::Migration[5.0]
  def change
    create_table :tenants do |t|
      t.string :tenant_name
      t.string :tenant_owner_name
      t.string :tenant_address
      t.string :tenant_email
      t.integer :pincode

      t.timestamps
    end
  end
end

Not the timestamp that translates to DateTime.

create_table "tenants", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
    t.string   "tenant_name"
    t.string   "tenant_owner_name"
    t.string   "tenant_address"
    t.string   "tenant_email"
    t.integer  "pincode"
    t.datetime "created_at",        null: false
    t.datetime "updated_at",        null: false
  end

I know that I can directly create two columns, and manually alter the created_at and updated_at fields everytime the record is added/changed, But that's going to be lots of bad code redundant code introduced in the application.

What I need is to somehow store the timestamps in epoch format (Time since 1970 in Long) instead of DateTime.

Thanks

Upvotes: 0

Views: 3148

Answers (1)

Matouš Bor&#225;k
Matouš Bor&#225;k

Reputation: 15954

You have not specified the DB used, so I assume MySQL here. It turns out Rails supports all variants of date/time columns for the timestamps: DATE, TIME, DATETIME, TIMESTAMP and even INTEGER. See the MySQL docs for more info about the differences between these types and this answer for info about how Rails understand them.

1) TIMESTAMP timestamp columns

If you want to store the timestamps in TIMESTAMP type columns, try the following trick in your migration (note the space in 'timestamp ', it is needed otherwise Rails will always create the column as datetime instead - timestamp is only an alias for datetime in Rails):

create_table :tenants do |t|
  # ...

  #t.timestamps (remove the default timestamps definition) 
  t.column :created_at, 'timestamp ', null: false
  t.column :updated_at, 'timestamp ', null: false
end

When working with the records, the timestamps will appear as a usual datetimes but will be stored as TIMESTAMPs in the DB, thus saving a few bytes per record:

Tenant.create!
# => SQL (0.1ms)  INSERT INTO `tenants` (`created_at`, `updated_at`) VALUES ('2016-06-08 08:45:20', '2016-06-08 08:45:20')
=> #<Tenant id: 1, tenant_name: nil, tenant_owner_name: nil, tenant_address: nil, tenant_email: nil, pincode: nil, created_at: "2016-06-08 08:45:20", updated_at: "2016-06-08 08:45:20">

Of course, you can always convert a datetime to seconds since the Epoch using the to_i method:

Tenant.last.created_at.to_i
# => 1465375595

2) INTEGER timestamp columns

If you want to store the timestamps indeed as seconds since the Epoch (1970), just define the timestamp columns as INTEGER type columns:

create_table :tenants do |t|
  # ...

  #t.timestamps (remove the default timestamps definition)
  t.integer :created_at, null: false
  t.integer :updated_at, null: false
end

Then, the timestamps in the records also appear as integers in Rails:

Tenant.create!
# => SQL (0.2ms)  INSERT INTO `tenants` (`created_at`, `updated_at`) VALUES (1465375595, 1465375595)
# => #<Tenant id: 1, tenant_name: nil, tenant_owner_name: nil, tenant_address: nil, tenant_email: nil, pincode: nil, created_at: 1465375595, updated_at: 1465375595>

Upvotes: 2

Related Questions