Как вы относитесь к относительному времени в 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 дня назад.


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

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)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.