Làm thế nào để bạn làm thời gian tương đối trong Rails?


220

Tôi đang viết một ứng dụng Rails, nhưng dường như không thể tìm ra cách thực hiện thời gian tương đối, tức là nếu được cung cấp một lớp Thời gian nhất định, nó có thể tính toán "30 giây trước" hoặc "2 ngày trước" hoặc nếu nó dài hơn một tháng "9/1/2008", v.v.


1
'tính toán' dường như là từ sai, ý bạn là 'đầu ra'?
lulalala

Câu trả lời:


366

Âm thanh như bạn đang tìm kiếm time_ago_in_wordsphương thức (hoặc distance_of_time_in_words), từ ActiveSupport. Gọi nó như thế này:

<%= time_ago_in_words(timestamp) %>

4
Gợi ý cho một người mới chơi ruby ​​về cách chạy cái này trong irb? Tôi chạy: yêu cầu 'active_support' và sau đó thử 'time_ago_in_words (Time.now)' nhưng chức năng không được tìm thấy.
cboettig

2
@cboettig Nó không phải là một phần của ActiveSupport, nó được định nghĩa trong ActionView::Helpers::DateHelper.
Michael Kohl

19
bạn không cần phải yêu cầu 'active_support' nếu bạn đang ở trong bảng điều khiển đường ray. có một phương thức console được gọi là helperbạn có thể gọi và truy cập các phương thức này. helper.time_ago_in_words(timestamp)
Matt Polito

2
Chỉ cần fyi, nếu bạn muốn điều này trong irb hoặc Ruby đơn giản, chỉ cần thực hiện: require 'active_support/core_ext' Đầu tiên, sau đó bạn đã sẵn sàng sử dụng 7.days.agovà các cấu trúc tương tự khác.
likeethesky

1
tuyệt quá! Tôi vừa mới đến đây để mong đợi một số mã mẫu và tìm thấy cái này. Tôi yêu ruby ​​và đường ray
Marcelo Biffara

53

Tôi đã viết cái này, nhưng phải kiểm tra các phương thức hiện có được đề cập để xem chúng có tốt hơn không.

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
Hum, tôi đã đọc ruby ​​đầu tiên và ruby ​​không có ActiveSupport ngoài hộp. Vì vậy, tôi nghĩ rằng bài viết này là nhiều ruby. Tuy nhiên trong câu hỏi thực tế có đề cập đến đường ray.
Jonke

Rails là một khung web và ngôn ngữ cơ bản là ruby. Vì vậy, nó là bình thường để có được một số mã ruby ​​trên một câu hỏi đường ray. Ngay cả khi ruby ​​tiêu chuẩn không bao gồm ActiveRecord, nó vẫn được hỗ trợ chỉ bằng lệnh "gem install activerecord".
MickaelFM

7
Bạn có thể đặt returndòng cuối cùng trong casecâu lệnh bên dưới elsevà xóa tất cả các returns.
sawa

2
ai đó có thể cho biết tại sao có +99 +800 +180000?
Gaurav Shah

+99 vì kết thúc "một giờ trước" kết thúc ở 7100, tức là 100 giây ngắn hai giờ. Tương tự, +800, kể từ 172000 ngắn 800 giây trong hai ngày (172800 giây), v.v.
Fred

22

Chỉ cần làm rõ giải pháp của Andrew Marshall để sử dụng time_ago_in_words
(Dành cho Rails 3.0 và Rails 4.0)

Nếu bạn đang ở trong một cái nhìn

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

Nếu bạn đang ở trong một bộ điều khiển

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

Bộ điều khiển không có mô-đun ActionView :: Helpers :: DateHelper được nhập theo mặc định.

NB Không phải là "đường ray" để nhập người trợ giúp vào bộ điều khiển của bạn. Người trợ giúp là để giúp quan điểm. Các time_ago_in_words phương pháp đã quyết định trở thành một quan điểm thực thể trong MVC bộ ba. (Tôi không đồng ý nhưng khi ở rome ...)


20

Thế còn

30.seconds.ago
2.days.ago

Hoặc một cái gì đó khác mà bạn đang chụp?


19
điều này ngược với những gì câu hỏi được nêu.
xaxxon

12

Bạn có thể sử dụng các toán tử số học để làm thời gian tương đối.

Time.now - 2.days 

Sẽ cho bạn 2 ngày trước.


10
Bạn có biết về 2.days.ago?
webmat

2
có phương pháp tốc ký nào cho 'Time.now + 2.days' không?
Stefan

23
@NixNinja: 2.days.sincehoặc2.days.from_now
Brian Donovan

5
điều này ngược với những gì câu hỏi đang hỏi time_ago_in_words là câu trả lời cho câu hỏi.
xaxxon

Cảm ơn bạn rất nhiều.
Jigar Bhatt

10

Một cái gì đó như thế này sẽ làm việc.

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
Đây thực chất là một sự tái hiện của trình trợ giúp distance_of_time_in_words: api.rubyonrails.com/groupes/ActionView/Helpers/ (
Hutchins Grant

2
có nghĩa là bạn không nên sử dụng nó và bạn nên sử dụng tích hợp
xaxxon

Điều này có vẻ hoàn toàn tốt với tôi. Nó cho phép bạn tùy chỉnh phần còn lại của chuỗi. tức là "3 giây trước" so với "3 giây trước"
raidfive

#{diff_seconds/360}nên #{diff_seconds/3600}. Tôi đã chỉnh sửa nó.
Femaref

7

Vì câu trả lời nhiều nhất ở đây gợi ý time_ago_in_words .

Thay vì sử dụng :

<%= time_ago_in_words(comment.created_at) %>

Trong Rails, thích:

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

cùng với thư viện jQuery http://timeago.yarp.com/ , với mã:

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

Ưu điểm chính: lưu trữ

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


1
thực ra, time_ago_in_wordschưa đến lúc S
23tux

6

Hãy xem các phương thức ví dụ ở đây:

http://apidock.com/rails/Time

Điều này có các phương thức hữu ích như ngày hôm qua, ngày mai, start_of_week, trước, v.v.

Ví dụ:

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

1

Tôi đã viết một viên ngọc làm điều này cho các đối tượng Rails ActiveRecord. Ví dụ này sử dụng created_at, nhưng nó cũng sẽ hoạt động trên update_at hoặc bất cứ thứ gì có lớp ActiveSupport :: TimeWithZone.

Chỉ cần cài đặt gem và gọi phương thức 'khá' trên ví dụ TimeWithZone của bạn.

https://github.com/brettshollenberger/hublot


1

Nếu bạn đang xây dựng một ứng dụng Rails, bạn nên sử dụng

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

Điều này cung cấp cho bạn thời gian hoặc ngày trong múi giờ mà bạn đã định cấu hình ứng dụng Rails của mình.

Ví dụ: nếu bạn định cấu hình ứng dụng của mình để sử dụng UTC, thì Time.zone.nowsẽ luôn ở trong thời gian UTC (ví dụ: nó sẽ không bị ảnh hưởng bởi sự thay đổi của Summertime của Anh).

Tính thời gian tương đối dễ dàng, vd

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.