Как вы относитесь к относительному времени в Rails?

220

Я пишу приложение на Rails, но, похоже, не могу найти, как сделать относительное время, то есть, если задан определенный класс времени, оно может вычислять «30 секунд назад» или «2 дня назад» или если оно длиннее месяца «01.09.2008» и др.

Джон Топли
источник
1
«Рассчитать» кажется неправильным словом, вы имели в виду «вывод»?
Лулалала

Ответы:

366

Похоже, вы ищете time_ago_in_wordsметод (или distance_of_time_in_words), из ActiveSupport. Назовите это так:

<%= time_ago_in_words(timestamp) %>
Бен Скофилд
источник
4
Советы рубиновому новичку о том, как запустить это в IRB? Я запускаю: требуют 'active_support' и затем пытаюсь 'time_ago_in_words (Time.now)', но функция не найдена.
cboettig
2
@cboettig Это не часть ActiveSupport, это определено в ActionView::Helpers::DateHelper.
Майкл Коль
19
вам не нужно требовать 'active_support', если вы находитесь в консоли rails. есть консольный метод, helperкоторый вы можете вызвать и получить доступ к этим методам. helper.time_ago_in_words(timestamp)
Мэтт Полито
2
Просто к вашему сведению, если вы хотите это в irb или обычном Ruby, просто выполните a: require 'active_support/core_ext' сначала, а затем все готово для использования 7.days.agoи других подобных конструкций.
ликетический
1
здорово! Я только что пришел сюда, ожидая некоторый пример кода и нашел это. Я люблю рубин и рельсы
Марсело Биффара
53

Я написал это, но должен проверить существующие методы, упомянутые, чтобы видеть, лучше ли они.

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
Матиас Винкельманн
источник
1
Хм, я прочитал первый ruby, а у ruby ​​нет ActiveSupport из коробки. Поэтому я думаю, что этот пост более рубиновый. Однако в актуальном вопросе есть упоминание о рельсах.
Jonke
Rails - это веб-фреймворк, а основным языком является ruby. Так что нормально получить какой-нибудь рубиновый код по рельсам. Даже если стандартный ruby ​​не включает ActiveRecord, он поддерживается только командой «gem install activerecord».
MickaelFM
7
Вы можете поместить последнюю returnстроку внутри caseоператора elseи удалить все returns.
Пила
2
может кто-нибудь сказать, почему есть +99 +800 +180000?
Гаурав Шах
+99, потому что конец «часа назад» заканчивается в 7100, что на 100 секунд меньше двух часов. Аналогично, +800, так как 172000 - это 800 секунд, не хватает двух дней (172800 секунд) и так далее.
Фред
22

Просто чтобы прояснить решение Эндрю Маршалла об использовании time_ago_in_words
(для Rails 3.0 и Rails 4.0)

Если вы в представлении

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

Если вы находитесь в контроллере

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

Контроллеры не имеют модуль ActionView :: Helpers :: DateHelper, импортированный по умолчанию.

NB Это не "путь рельсов", чтобы импортировать помощников в ваши контроллеры. Помощники для того, чтобы помочь взглядам. Time_ago_in_words метод решил быть вид объект в MVC триаде. (Я не согласен, но когда в Риме ...)

поисковая оптимизация
источник
20

Что о

30.seconds.ago
2.days.ago

Или что-то еще, за что вы стреляли?

Хонза
источник
19
это отстает от того, что ставит вопрос.
xaxxon
12

Вы можете использовать арифметические операторы, чтобы сделать относительное время.

Time.now - 2.days 

Даст вам 2 дня назад.

TonyLa
источник
10
Знаете ли вы о 2.days.ago?
вебмат
2
есть ли сокращенный метод для `Time.now + 2.days '?
Stefan
23
@NixNinja: 2.days.sinceили2.days.from_now
Брайан Донован
5
это назад от того, что задавал вопрос. time_ago_in_words - это ответ на вопрос.
xaxxon
Большое спасибо.
Джигар Бхатт
10

Нечто подобное будет работать.

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
Гордон Уилсон
источник
11
По сути это повторная реализация помощника distance_of_time_in_words: api.rubyonrails.com/classes/ActionView/Helpers/…
Грант Хатчинс
2
это означает, что вы не должны использовать его, и вы должны использовать встроенный
xaxxon
Мне кажется, это прекрасно. Это позволяет вам настроить остальные строки. то есть "3 секунды назад" против "3s назад"
raidfive
#{diff_seconds/360}должно быть #{diff_seconds/3600}. Я редактировал это.
Femaref
7

Поскольку большинство ответов здесь предлагает time_ago_in_words .

Вместо того, чтобы использовать :

<%= time_ago_in_words(comment.created_at) %>

В Rails предпочитаю:

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

вместе с библиотекой jQuery http://timeago.yarp.com/ , с кодом:

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

Основное преимущество: кеширование

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

Рахул Гарг
источник
1
на самом деле, это time_ago_in_wordsне время S
23tux
6

Взгляните на методы экземпляра здесь:

http://apidock.com/rails/Time

Это имеет полезные методы, такие как вчера, завтра, begin_of_week, назад и т. Д.

Примеры:

Time.now.yesterday
Time.now.ago(2.days).end_of_day
Time.now.next_month.beginning_of_month
davogones
источник
1

Я написал гем, который делает это для объектов Rails ActiveRecord. В этом примере используется create_at, но он также будет работать с updated_at или чем-то еще с классом ActiveSupport :: TimeWithZone.

Просто установите gem и вызовите метод pretty в вашем экземпляре TimeWithZone.

https://github.com/brettshollenberger/hublot

Бретт Шолленбергер
источник
1

Если вы создаете приложение Rails, вы должны использовать

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

Это дает вам время или дату в часовом поясе, с которым вы настроили приложение Rails.

Например, если вы сконфигурируете свое приложение для использования UTC, тогда Time.zone.nowвсегда будет время по UTC (например, изменение British Summertime не повлияет на это).

Рассчитать относительное время легко, например

Time.zone.now - 10.minute
Time.zone.today.days_ago(5)
Зак Сюй
источник
0

Другой подход заключается в том, чтобы выгрузить некоторую логику из серверной части и заставить браузер выполнять эту работу с помощью плагинов Javascript, таких как:

JQuery время назад или его адаптация Rails Gem

Призрак Оз
источник