¿Cómo haces el tiempo relativo en Rails?

220

Estoy escribiendo una aplicación Rails, pero parece que no puedo encontrar cómo hacer el tiempo relativo, es decir, si se le da una cierta clase de tiempo, puede calcular "hace 30 segundos" o "hace 2 días" o si es más de un mes "1/9/2008", etc.

John Topley
fuente
1
"calcular" parece ser la palabra incorrecta, ¿quiso decir "salida"?
lulalala

Respuestas:

366

Parece que está buscando el time_ago_in_wordsmétodo (o distance_of_time_in_words), de ActiveSupport. Llámalo así:

<%= time_ago_in_words(timestamp) %>
Ben Scofield
fuente
44
¿Sugerencias para un novato rubí sobre cómo ejecutar esto en irb? Ejecuto: requiero 'active_support' y luego intento 'time_ago_in_words (Time.now)' pero no se encuentra la función.
cboettig
2
@cboettig No es parte de ActiveSupport, está definido en ActionView::Helpers::DateHelper.
Michael Kohl
19
no necesita requerir 'active_support' si está en una consola de rails. Hay un método de consola llamado al helperque puede llamar y acceder a estos métodos. helper.time_ago_in_words(timestamp)
Matt Polito
2
Solo para tu información, si quieres esto en irb o Ruby simple, solo haz un: require 'active_support/core_ext' Primero, y luego estarás listo para usar 7.days.agoy otras construcciones similares.
likethesky
1
¡Excelente! Acabo de llegar aquí esperando un código de muestra y encontré esto. Me encanta el rubí y los rieles
Marcelo Biffara
53

He escrito esto, pero tengo que verificar los métodos existentes mencionados para ver si son mejores.

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
Matthias Winkelmann
fuente
1
Hum, leí primero ruby, y ruby ​​no tiene ActiveSupport listo para usar. Así que creo que esta publicación es más rubí. Sin embargo, en la pregunta real hay una mención de rieles.
Jonke
Rails es un marco web y el lenguaje subyacente es ruby. Por lo tanto, es normal obtener un código ruby ​​en una pregunta sobre rieles. Incluso si el ruby ​​estándar no incluye ActiveRecord, solo es compatible con el comando "gem install activerecord".
MickaelFM
77
Puede colocar la última línea returndentro del caseenunciado debajo elsey eliminar todos los returns.
Sawa
2
¿Alguien puede decir por qué hay +99 +800 +180000?
Gaurav Shah
+99 porque el final de "hace una hora" termina en 7100, que es 100 segundos menos de dos horas. Del mismo modo, +800, ya que 172000 es 800 segundos menos de dos días (172800 segundos), y así sucesivamente.
Fred
22

Solo para aclarar la solución de Andrew Marshall para usar time_ago_in_words
(Para Rails 3.0 y Rails 4.0)

Si estás en una vista

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

Si estás en un controlador

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

Los controladores no tienen el módulo ActionView :: Helpers :: DateHelper importado por defecto.

NB No es "el camino de los rieles" importar ayudantes a sus controladores. Los ayudantes son para ayudar a las vistas. Se decidió que el método time_ago_in_words era una entidad de vista en la tríada MVC . (No estoy de acuerdo, pero cuando en Roma ...)

seo
fuente
20

Qué pasa

30.seconds.ago
2.days.ago

¿O algo más para lo que estabas disparando?

Honza
fuente
19
Esto es al revés de lo que dice la pregunta.
xaxxon
12

Puede usar los operadores aritméticos para hacer un tiempo relativo.

Time.now - 2.days 

Te lo daré hace 2 días.

TonyLa
fuente
10
¿Sabías sobre 2.days.ago?
webmat
2
¿Hay algún método abreviado para `Time.now + 2.days '?
Stefan
23
@NixNinja: 2.days.sinceo2.days.from_now
Brian Donovan
55
Esto es al revés de lo que estaba haciendo la pregunta. time_ago_in_words es la respuesta a la pregunta.
xaxxon
Muchas gracias.
Jigar Bhatt
10

Algo como esto funcionaría.

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
Gordon Wilson
fuente
11
Esto es esencialmente una reimplementación del ayudante distance_of_time_in_words: api.rubyonrails.com/classes/ActionView/Helpers/…
Grant Hutchins
2
lo que significa que no debes usarlo y debes usar el incorporado
xaxxon
Esto me parece perfectamente bien. Le permite personalizar el resto de las cadenas. es decir, "hace 3 segundos" frente a "hace 3 segundos"
incursión el
#{diff_seconds/360}debería ser #{diff_seconds/3600}. Lo he editado
Femaref
7

Como la mayor respuesta aquí sugiere time_ago_in_words .

En lugar de usar :

<%= time_ago_in_words(comment.created_at) %>

En Rails, prefiere:

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

junto con una biblioteca jQuery http://timeago.yarp.com/ , con el código:

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

Ventaja principal: almacenamiento en caché

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

Rahul garg
fuente
1
en realidad, no es time_ago_in_wordshora S
23tux
6

Eche un vistazo a los métodos de instancia aquí:

http://apidock.com/rails/Time

Esto tiene métodos útiles como ayer, mañana, comienzo_de_semana, ago, etc.

Ejemplos:

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

He escrito una gema que hace esto para los objetos ActiveRecord de Rails. El ejemplo usa created_at, pero también funcionará en updated_at o cualquier cosa con la clase ActiveSupport :: TimeWithZone.

Simplemente instale gem y llame al método 'bonito' en su instancia de TimeWithZone.

https://github.com/brettshollenberger/hublot

Brett Shollenberger
fuente
1

Si está creando una aplicación Rails, debe usar

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

Esto le da la hora o fecha en la zona horaria con la que ha configurado su aplicación Rails.

Por ejemplo, si configura su aplicación para usar UTC, Time.zone.nowsiempre estará en hora UTC (por ejemplo, no se verá afectado por el cambio de horario de verano británico).

Calcular el tiempo relativo es fácil, p. Ej.

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