Jak robisz względny czas w Railsach?

220

Piszę aplikację Railsową, ale nie mogę znaleźć sposobu na obliczenie czasu względnego, tzn. Jeśli otrzyma określoną klasę Time, może obliczyć „30 sekund temu” lub „2 dni temu” lub jeśli jest ona dłuższa niż miesiąc „9/1/2008” itp.

John Topley
źródło
1
„obliczyć” wydaje się być niewłaściwym słowem, miałeś na myśli „wynik”?
lulalala,

Odpowiedzi:

366

Wygląda na to, że szukasz time_ago_in_wordsmetody (lub distance_of_time_in_words) z ActiveSupport. Nazwij to tak:

<%= time_ago_in_words(timestamp) %>
Ben Scofield
źródło
4
Wskazówki dla początkującego ruby, jak uruchomić to w IRB? Uruchamiam: wymagam „active_support”, a następnie próbuję „time_ago_in_words (Time.now)”, ale funkcja nie została znaleziona.
cboettig
2
@cboettig To nie jest część ActiveSupport, jest zdefiniowane w ActionView::Helpers::DateHelper.
Michael Kohl,
19
nie musisz wymagać „active_support”, jeśli jesteś w konsoli railsowej. istnieje metoda konsoli o nazwie helper, którą można wywoływać i uzyskiwać dostęp do tych metod. helper.time_ago_in_words(timestamp)
Matt Polito
2
Po prostu fyi, jeśli chcesz tego w irb lub zwykłego Ruby, po prostu wykonaj: require 'active_support/core_ext' Najpierw, a potem wszystko gotowe do użycia 7.days.agoi innych podobnych konstrukcji.
likethesky
1
świetny! Właśnie przyszedłem tutaj, spodziewając się jakiegoś przykładowego kodu i znalazłem to. Uwielbiam rubin i szyny
Marcelo Biffara
53

Napisałem to, ale muszę sprawdzić wymienione metody, aby sprawdzić, czy są lepsze.

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
źródło
1
Hum, czytam pierwszy rubin i ruby ​​nie mają ActiveSupport po wyjęciu z pudełka. Myślę więc, że ten post jest bardziej rubinowy. Jednak w rzeczywistym pytaniu jest mowa o szynach.
Jonke,
Railsy to framework internetowy, a podstawowym językiem jest ruby. Więc normalne jest otrzymywanie kodu ruby ​​na pytanie dotyczące szyn. Nawet jeśli standardowy ruby ​​nie zawiera ActiveRecord, jest obsługiwany tylko poleceniem „gem install activerecord”.
MickaelFM
7
Możesz umieścić ostatnią returnlinię w caseinstrukcji elsei usunąć wszystkie returnlitery.
sawa
2
czy ktoś może powiedzieć, dlaczego tak jest +99 +800 +180000?
Gaurav Shah
+99, ponieważ koniec „godziny temu” kończy się na 7100, czyli o 100 sekund mniej niż dwie godziny. Podobnie, +800, ponieważ 172000 to 800 sekund mniej niż dwa dni (172800 sekund) i tak dalej.
Fred
22

Żeby wyjaśnić rozwiązanie Andrew Marshalla dotyczące używania time_ago_in_words
(dla Rails 3.0 i Rails 4.0)

Jeśli jesteś w widoku

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

Jeśli jesteś kontrolerem

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

Kontrolery nie mają modułu domyślnie importowanego ActionView :: Helpers :: DateHelper .

Uwaga: Importowanie pomocników do kontrolerów nie jest „drogą szynową”. Pomocnicy służą do pomocy w wyświetlaniu. Metoda time_ago_in_words została uznana za encję widoku w triadzie MVC . (Nie zgadzam się, ale kiedy jestem w Rzymie ...)

seo
źródło
20

Co powiesz na

30.seconds.ago
2.days.ago

A może coś innego, do czego strzelałeś?

Honza
źródło
19
jest to odwrócone od tego, co mówi pytanie.
xaxxon
12

Możesz użyć operatorów arytmetycznych do wykonania czasu względnego.

Time.now - 2.days 

Dam ci 2 dni temu.

TonyLa
źródło
10
Czy wiesz o 2.days.ago?
webmat
2
czy istnieje metoda skrócona dla „Time.now + 2.days”?
Stefan
23
@NixNinja: 2.days.sincelub2.days.from_now
Brian Donovan
5
jest to odwrócone od tego, o co pytało pytanie. time_ago_in_words jest odpowiedzią na pytanie.
xaxxon
Bardzo Ci dziękuję.
Jigar Bhatt
10

Coś takiego działałoby.

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
źródło
11
Jest to zasadniczo reimplementacja pomocnika distance_of_time_in_words: api.rubyonrails.com/classes/ActionView/Helpers/...
Grant Hutchins
2
co oznacza, że ​​nie powinieneś go używać i powinieneś użyć wbudowanego
xaxxon
Wydaje mi się to zupełnie w porządku. Pozwala dostosować pozostałe ciągi. tzn. „3 sekundy temu” vs „3s temu”
raidfive
#{diff_seconds/360}powinno być #{diff_seconds/3600}. Zredagowałem to.
Femaref
7

Ponieważ większość odpowiedzi tutaj sugeruje time_ago_in_words .

Zamiast używać :

<%= time_ago_in_words(comment.created_at) %>

W Railsach preferuj:

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

wraz z biblioteką jQuery http://timeago.yarp.com/ , z kodem:

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

Główna zaleta: buforowanie

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

Rahul Garg
źródło
1
w rzeczywistości nie jest time_ago_in_wordsto czas S
23tux
6

Spójrz na metody instancji tutaj:

http://apidock.com/rails/Time

Ma to przydatne metody, takie jak wczoraj, jutro, początek tygodnia, temu itd.

Przykłady:

Time.now.yesterday
Time.now.ago(2.days).end_of_day
Time.now.next_month.beginning_of_month
davogones
źródło
1

Napisałem klejnot, który robi to dla obiektów Rails ActiveRecord. W przykładzie użyto create_at, ale będzie również działał na updated_at lub cokolwiek innego z klasą ActiveSupport :: TimeWithZone.

Wystarczy zainstalować klejnot i wywołać metodę „ładną” w instancji TimeWithZone.

https://github.com/brettshollenberger/hublot

Brett Shollenberger
źródło
1

Jeśli budujesz aplikację Railsową, powinieneś jej użyć

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

Podaje godzinę lub datę w strefie czasowej, w której skonfigurowano aplikację Rails.

Na przykład jeśli skonfigurujesz aplikację do korzystania z UTC, to Time.zone.now zawsze będzie ona w czasie UTC (na przykład zmiana brytyjskiego czasu letniego nie będzie miała na nią wpływu).

Obliczanie czasu względnego jest łatwe, np

Time.zone.now - 10.minute
Time.zone.today.days_ago(5)
Zack Xu
źródło
0

Innym podejściem jest rozładowanie logiki z backendu i sprawdzenie, czy przeglądarka wykonuje zadanie za pomocą wtyczek JavaScript, takich jak:

jQuery czas temu lub jego adaptacja Rails Gem

The Whiz of Oz
źródło