Como você passa o tempo relativo no Rails?

220

Estou escrevendo um aplicativo Rails, mas parece que não consigo encontrar um tempo relativo, ou seja, se receber uma determinada classe Time, ele pode calcular "30 segundos atrás" ou "2 dias atrás" ou se for mais de um mês "1/9/2008" etc.

John Topley
fonte
1
'calcular' parece ser a palavra errada, você quis dizer 'saída'?
Lulalala 25/11

Respostas:

366

Parece que você está procurando o time_ago_in_wordsmétodo (ou distance_of_time_in_words), do ActiveSupport. Chame assim:

<%= time_ago_in_words(timestamp) %>
Ben Scofield
fonte
4
Dicas para um novato em ruby ​​sobre como executar isso no irb? Eu corro: exigir 'active_support' e tente 'time_ago_in_words (Time.now)', mas a função não foi encontrada.
precisa saber é o seguinte
2
@cboettig Não faz parte ActiveSupport, está definido em ActionView::Helpers::DateHelper.
Michael Kohl
19
você não precisa exigir 'active_support' se estiver em um console de rails. existe um método de console chamado helperque você pode chamar e acessar esses métodos. helper.time_ago_in_words(timestamp)
quer
2
Apenas fyi, se você quiser isso no irb, ou no Ruby simples, faça o seguinte: require 'active_support/core_ext' Primeiro, e então você estará pronto para usar 7.days.agoe outras construções semelhantes.
likethesky
1
ótimo! eu só vim aqui esperando algum código de exemplo e encontrou this.I Ruby e Rails amor
Marcelo Biffara
53

Eu escrevi isso, mas tenho que verificar os métodos existentes mencionados para ver se eles são melhores.

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
fonte
1
Hum, li o primeiro ruby, e o ruby ​​não tem o ActiveSupport pronto para uso. Então eu acho que este post é mais rubi. No entanto, na questão real, há uma menção de trilhos.
911 Jonke
O Rails é uma estrutura da Web e a linguagem subjacente é ruby. Portanto, é normal obter algum código ruby ​​em uma pergunta sobre trilhos. Mesmo que o ruby ​​padrão não inclua o ActiveRecord, ele é suportado apenas com o comando "gem install activerecord".
MickaelFM
7
Você pode colocar a última returnlinha na caseinstrução em elsee remover todos os returns.
27611
2
alguém pode dizer por que existe +99 +800 +180000?
Gaurav Shah
+99 porque o final de "uma hora atrás" termina em 7100, ou seja, 100 segundos em menos de duas horas. Da mesma forma, +800, desde 172000, é 800 segundos com menos de dois dias (172800 segundos) e assim por diante.
Fred
22

Apenas para esclarecer a solução de Andrew Marshall para usar time_ago_in_words
(For Rails 3.0 e Rails 4.0)

Se você está em uma visão

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

Se você estiver em um controlador

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

Os controladores não possuem o módulo ActionView :: Helpers :: DateHelper importado por padrão.

NB Não é "o caminho dos trilhos" importar importadores para seus controladores. Os ajudantes são para ajudar as visualizações. O método time_ago_in_words foi decidido como uma entidade de exibição na tríade MVC . (Eu não concordo, mas quando em Roma ...)

seo
fonte
20

A respeito

30.seconds.ago
2.days.ago

Ou algo mais para o qual você estava filmando?

Honza
fonte
19
isso é inverso do que a pergunta está afirmando.
xaxxon 15/10/11
12

Você pode usar os operadores aritméticos para fazer um tempo relativo.

Time.now - 2.days 

Vai lhe dar 2 dias atrás.

TonyLa
fonte
10
Você sabia sobre 2.days.ago?
Webmat
2
existe um método abreviado para `Time.now + 2.days '?
28511 Stefan
23
@NixNinja: 2.days.sinceor2.days.from_now
Brian Donovan
5
isso está ao contrário do que a pergunta estava fazendo. time_ago_in_words é a resposta para a pergunta.
xaxxon 15/10/11
Muito obrigado.
Jigar Bhatt
10

Algo assim iria funcionar.

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
fonte
11
Esta é essencialmente uma reimplementação do ajudante distance_of_time_in_words: api.rubyonrails.com/classes/ActionView/Helpers/...
Grant Hutchins
2
que significa que você não deve usá-lo e você deve usar o built-in
xaxxon
Isso parece perfeitamente bem para mim. Ele permite que você personalize o restante das strings. ie "3 segundos atrás" vs "3s atrás"
raidfive 12/09
#{diff_seconds/360}deveria ser #{diff_seconds/3600}. Eu editei.
Femaref
7

Como a maioria das respostas aqui sugere time_ago_in_words .

Ao invés de usar :

<%= time_ago_in_words(comment.created_at) %>

No Rails, prefira:

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

junto com uma biblioteca jQuery http://timeago.yarp.com/ , com o código:

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

Principal vantagem: armazenamento em cache

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

Rahul garg
fonte
1
na verdade, não é time_ago_in_wordshora S
23tux 22/08
6

Dê uma olhada nos métodos da instância aqui:

http://apidock.com/rails/Time

Isso tem métodos úteis, como ontem, amanhã, início de semana, atrás etc.

Exemplos:

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

Eu escrevi uma jóia que faz isso para objetos Rails ActiveRecord. O exemplo usa created_at, mas também funcionará em updated_at ou qualquer coisa com a classe ActiveSupport :: TimeWithZone.

Basta instalar o gem e chamar o método 'pretty' na sua instância do TimeWithZone.

https://github.com/brettshollenberger/hublot

Brett Shollenberger
fonte
1

Se você estiver criando um aplicativo Rails, use

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

Isso indica a hora ou a data no fuso horário com o qual você configurou seu aplicativo Rails.

Por exemplo, se você configurar seu aplicativo para usar o UTC, Time.zone.nowsempre estará no horário UTC (não será afetado pela mudança do horário de verão britânico, por exemplo).

Calcular o tempo relativo é fácil, por exemplo

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