lol_wut
lol_wut

Reputation:

How do you do relative time in Rails?

I'm writing a Rails application, but can't seem to find how to do relative time, i.e. if given a certain Time class, it can calculate "30 seconds ago" or "2 days ago" or if it's longer than a month "9/1/2008", etc.

Upvotes: 225

Views: 133564

Answers (11)

Rahul garg
Rahul garg

Reputation: 9362

Since the most answer here suggests time_ago_in_words.

Instead of using :

<%= time_ago_in_words(comment.created_at) %>

In Rails, prefer:

<abbr class="timeago" title="<%= comment.created_at.getutc.iso8601 %>">
  <%= comment.created_at.to_s %>
</abbr>

along with a jQuery library http://timeago.yarp.com/, with code:

$("abbr.timeago").timeago();

Main advantage: caching

http://rails-bestpractices.com/posts/2012/02/10/not-use-time_ago_in_words/

Upvotes: 7

Jon Snow
Jon Snow

Reputation: 11882

If you're building a Rails application, you should use

Time.zone.now
Time.zone.today
Time.zone.yesterday

This gives you time or date in the timezone with which you've configured your Rails application.

For example, if you configure your application to use UTC, then Time.zone.now will always be in UTC time (it won't be impacted by the change of British Summertime for example).

Calculating relative time is easy, eg

Time.zone.now - 10.minute
Time.zone.today.days_ago(5)

Upvotes: 2

The Whiz of Oz
The Whiz of Oz

Reputation: 7043

Another approach is to unload some logic from the backend and maek the browser do the job by using Javascript plugins such as:

jQuery time ago or its Rails Gem adaptation

Upvotes: 0

seo
seo

Reputation: 1967

Just to clarify Andrew Marshall's solution for using time_ago_in_words
(For Rails 3.0 and Rails 4.0)

If you are in a view

<%= time_ago_in_words(Date.today - 1) %>

If you are in a controller

include ActionView::Helpers::DateHelper
def index
  @sexy_date = time_ago_in_words(Date.today - 1)
end

Controllers do not have the module ActionView::Helpers::DateHelper imported by default.

N.B. It is not "the rails way" to import helpers into your controllers. Helpers are for helping views. The time_ago_in_words method was decided to be a view entity in the MVC triad. (I don't agree but when in rome...)

Upvotes: 25

Brett Shollenberger
Brett Shollenberger

Reputation: 225

I've written a gem that does this for Rails ActiveRecord objects. The example uses created_at, but it will also work on updated_at or anything with the class ActiveSupport::TimeWithZone.

Just gem install and call the 'pretty' method on your TimeWithZone instance.

https://github.com/brettshollenberger/hublot

Upvotes: 1

davogones
davogones

Reputation: 7399

Take a look at the instance methods here:

http://apidock.com/rails/Time

This has useful methods such as yesterday, tomorrow, beginning_of_week, ago, etc.

Examples:

Time.now.yesterday
Time.now.ago(2.days).end_of_day
Time.now.next_month.beginning_of_month

Upvotes: 6

Gordon Wilson
Gordon Wilson

Reputation: 26384

Something like this would work.

def relative_time(start_time)
  diff_seconds = Time.now - start_time
  case diff_seconds
    when 0 .. 59
      puts "#{diff_seconds} seconds ago"
    when 60 .. (3600-1)
      puts "#{diff_seconds/60} minutes ago"
    when 3600 .. (3600*24-1)
      puts "#{diff_seconds/3600} hours ago"
    when (3600*24) .. (3600*24*30) 
      puts "#{diff_seconds/(3600*24)} days ago"
    else
      puts start_time.strftime("%m/%d/%Y")
  end
end

Upvotes: 10

Matthias Winkelmann
Matthias Winkelmann

Reputation: 16384

I've written this, but have to check the existing methods mentioned to see if they are better.

module PrettyDate
  def to_pretty
    a = (Time.now-self).to_i

    case a
      when 0 then 'just now'
      when 1 then 'a second ago'
      when 2..59 then a.to_s+' seconds ago' 
      when 60..119 then 'a minute ago' #120 = 2 minutes
      when 120..3540 then (a/60).to_i.to_s+' minutes ago'
      when 3541..7100 then 'an hour ago' # 3600 = 1 hour
      when 7101..82800 then ((a+99)/3600).to_i.to_s+' hours ago' 
      when 82801..172000 then 'a day ago' # 86400 = 1 day
      when 172001..518400 then ((a+800)/(60*60*24)).to_i.to_s+' days ago'
      when 518400..1036800 then 'a week ago'
      else ((a+180000)/(60*60*24*7)).to_i.to_s+' weeks ago'
    end
  end
end

Time.send :include, PrettyDate

Upvotes: 52

Ben Scofield
Ben Scofield

Reputation: 6418

Sounds like you're looking for the time_ago_in_words method (or distance_of_time_in_words), from ActiveSupport. Call it like this:

<%= time_ago_in_words(timestamp) %>

Upvotes: 377

Honza
Honza

Reputation: 4409

What about

30.seconds.ago
2.days.ago

Or something else you were shooting for?

Upvotes: 20

TonyLa
TonyLa

Reputation: 734

You can use the arithmetic operators to do relative time.

Time.now - 2.days 

Will give you 2 days ago.

Upvotes: 12

Related Questions