views:

37

answers:

5

Hi,

I would like to modify updated_at attribute so that every time record is updated it would only show date and hours while hours and minutes being zeros. Instead of 2010-08-13 11:04:12, there would be 2010-08-13 11:00:00. What is the most rational way to do this in Rails 2.3?

Update

The reason why I want to do what I have asked is because I would like to sort data, by date with hours and seconds omitted.

Thanks!

+1  A: 

It's a time stamp object so your probably best off just to use a helper function to truncate the min/sec info.

+3  A: 

Don't try to change the value stored in the database; change how you are outputting it:

timestamp = @model.updated_at # where @model is your model object

# output it in a format that overrides the values for minute and second
puts timestamp.strftime "%Y-%m-%d %H:00:00"

See the strftime ruby doc for other format specifiers you can use.


Based on your update, I would still not change how updated_at is stored, but instead format the date within the ORDER BY of your query. For instance, you could

ORDER BY DATE(updated_at), HOUR(updated_at), ...

I did a very quick profiling test on a live table in my application, which has about 22,000 records. ORDER BY updated_at took between 2.94 and 3.19s to complete, with a mean time of 3.00s. ORDER BY DATE(updated_at), HOUR(updated_at) took between 2.93 and 3.06s to complete, with a mean time of 2.99s. Here's the profiling data:

+----------+------------+-----------------------------------------------------------------+
| Query_ID | Duration   | Query                                                           |
+----------+------------+-----------------------------------------------------------------+
|        1 | 2.94530500 | SELECT * FROM posts ORDER BY updated_at                         |
|        2 | 2.94583800 | SELECT * FROM posts ORDER BY updated_at                         |
|        3 | 3.18711700 | SELECT * FROM posts ORDER BY updated_at                         |
|        4 | 2.96923700 | SELECT * FROM posts ORDER BY updated_at                         |
|        5 | 2.97255400 | SELECT * FROM posts ORDER BY updated_at                         |
|        6 | 3.06706800 | SELECT * FROM posts ORDER BY DATE(updated_at), HOUR(updated_at) |
|        7 | 3.00414400 | SELECT * FROM posts ORDER BY DATE(updated_at), HOUR(updated_at) |
|        8 | 2.95551500 | SELECT * FROM posts ORDER BY DATE(updated_at), HOUR(updated_at) |
|        9 | 3.02181900 | SELECT * FROM posts ORDER BY DATE(updated_at), HOUR(updated_at) |
|       10 | 2.93130000 | SELECT * FROM posts ORDER BY DATE(updated_at), HOUR(updated_at) |
+----------+------------+-----------------------------------------------------------------+
Daniel Vandersluis
I haven't mentioned it, but the reason why I want to do what I have asked is because I would like to sort data, by date with hours and seconds omitted. Of course I could format date in my select, but I don't think it would be a good performance decision.
spacemonkey
@Daniel, but what about performance, when using sql functions when querying data? Because that data will be really frequently queried, while very less frequently updated
spacemonkey
You're going to have to go through a bit of a runaround to change how `updated_at` is stored because even if you try to set it manually, Rails will automatically set the value to what it wants when it goes to save the record.
Daniel Vandersluis
+1  A: 

whatever.created_at.strftime("%Y-%m-%d %H:00:00")

rspeicher
A: 

This isn't something you should do with active record. It's something that a view helper could accomplish and you don't need to alter the way things are getting saved which will probably just be more work in the future.

Think about strftime and how you can alter that instead.

In a helper file:

def format_date_for_rounded_hour(date)
    date.striftime("%Y-%m-%d %H:00")
end
Sam
A: 

I would recommend Daniel's solution. However, if you're 100% positive that you want to save the record with your modified "updated_at" field, you'll have to re-implement rails' auto-timestamping for the given model.

So, in your model, you can do the following:

self.record_timestamps = false # disables rails' auto-timestamping
before_create :set_created_at
before_save :set_updated_at  

def set_created_at
  self.created_at = Time.now
end
def set_updated_at
  self.updated_at = Time.now.change({:min => 0, :sec => 0}) # clears minutes and seconds
end
vegetables