Bagaimana waktu relatif Anda di Rails?

220

Saya sedang menulis aplikasi Rails, tetapi tampaknya tidak dapat menemukan cara melakukan waktu relatif, yaitu jika diberi kelas Waktu tertentu, ia dapat menghitung "30 detik yang lalu" atau "2 hari yang lalu" atau jika lebih dari sebulan "9/1/2008", dll.

John Topley
sumber
1
'menghitung' tampaknya merupakan kata yang salah, apakah maksud Anda 'keluaran'?
lulalala

Jawaban:

366

Kedengarannya seperti Anda sedang mencari time_ago_in_wordsmetode (atau distance_of_time_in_words), dari ActiveSupport. Sebut saja seperti ini:

<%= time_ago_in_words(timestamp) %>
Ben Scofield
sumber
4
Petunjuk untuk ruby ​​newbie tentang cara menjalankan ini di irb? Saya menjalankan: memerlukan 'active_support' dan kemudian coba 'time_ago_in_words (Time.now)' tetapi fungsinya tidak ditemukan.
cboettig
2
@cboettig Ini bukan bagian dari ActiveSupport, itu didefinisikan dalam ActionView::Helpers::DateHelper.
Michael Kohl
19
Anda tidak perlu memerlukan 'active_support' jika Anda berada di konsol rel. ada metode konsol yang disebut helperyang dapat Anda panggil dan akses metode ini. helper.time_ago_in_words(timestamp)
Matt Polito
2
Hanya fyi, jika Anda menginginkan ini di irb, atau Ruby biasa, lakukan saja: require 'active_support/core_ext' Pertama, dan kemudian Anda siap untuk menggunakan 7.days.agodan konstruksi serupa lainnya.
likethesky
1
Bagus! Saya baru saja datang ke sini mengharapkan beberapa kode sampel dan menemukan ini. Saya suka ruby ​​dan rails
Marcelo Biffara
53

Saya sudah menulis ini, tetapi harus memeriksa metode yang ada disebutkan untuk melihat apakah mereka lebih baik.

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
sumber
1
Hum, saya membaca ruby ​​pertama, dan ruby ​​tidak memiliki ActiveSupport di luar kotak. Jadi saya pikir posting ini lebih ruby. Namun dalam pertanyaan sebenarnya ada penyebutan rel.
Jonke
Rails adalah kerangka kerja web dan bahasa yang mendasarinya ruby. Jadi itu normal untuk mendapatkan beberapa kode ruby ​​pada pertanyaan rails. Sekalipun ruby ​​standar tidak menyertakan ActiveRecord, itu hanya didukung dengan perintah "gem install activerecord".
MickaelFM
7
Anda dapat meletakkan returnbaris terakhir dalam casepernyataan di bawah else, dan menghapus semua returns.
sawa
2
dapatkah seseorang memberi tahu mengapa ada +99 +800 +180000?
Gaurav Shah
+99 karena akhir "satu jam yang lalu" berakhir pada 7100, yang merupakan 100 detik dari dua jam. Demikian pula, +800, karena 172000 adalah 800 detik dari dua hari (172800 detik), dan sebagainya.
Fred
22

Hanya untuk mengklarifikasi solusi Andrew Marshall untuk menggunakan time_ago_in_words
(Untuk Rails 3.0 dan Rails 4.0)

Jika Anda dalam tampilan

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

Jika Anda berada di controller

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

Pengontrol tidak memiliki modul ActionView :: Helpers :: DateHelper diimpor secara default.

NB Bukan "cara rel" untuk mengimpor pembantu ke pengontrol Anda. Pembantu adalah untuk membantu pandangan. The time_ago_in_words metode diputuskan menjadi pandangan entitas dalam MVC triad. (Saya tidak setuju tetapi ketika di Roma ...)

seo
sumber
20

Bagaimana dengan

30.seconds.ago
2.days.ago

Atau sesuatu yang Anda tembak?

Honza
sumber
19
ini mundur dari apa yang pertanyaannya nyatakan.
xaxxon
12

Anda dapat menggunakan operator aritmatika untuk melakukan waktu relatif.

Time.now - 2.days 

Akan memberi Anda 2 hari yang lalu.

TonyLa
sumber
10
Apakah Anda tahu tentang 2.days.ago?
webmat
2
apakah ada metode singkatan untuk `Time.now + 2.days '?
Stefan
23
@NixNinja: 2.days.sinceatau2.days.from_now
Brian Donovan
5
ini mundur dari pertanyaan yang diajukan. time_ago_in_words adalah jawaban untuk pertanyaan itu.
xaxxon
Terima kasih banyak.
Jigar Bhatt
10

Sesuatu seperti ini akan berhasil.

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
sumber
11
Ini pada dasarnya adalah implementasi ulang dari distance_of_time_in_words helper: api.rubyonrails.com/classes/ActionView/Helpers/…
Grant Hutchins
2
yang berarti Anda tidak boleh menggunakannya dan Anda harus menggunakan built-in
xaxxon
Ini sepertinya baik-baik saja bagi saya. Ini memungkinkan Anda untuk menyesuaikan sisa string. yaitu "3 detik yang lalu" vs "3s yang lalu"
raidfive
#{diff_seconds/360}seharusnya #{diff_seconds/3600}. Saya sudah mengeditnya.
Femaref
7

Karena jawaban terbanyak di sini menyarankan time_ago_in_words .

Alih-alih menggunakan:

<%= time_ago_in_words(comment.created_at) %>

Di Rails, lebih suka:

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

bersama dengan perpustakaan jQuery http://timeago.yarp.com/ , dengan kode:

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

Keuntungan utama: caching

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

Rahul garg
sumber
1
sebenarnya, ini time_ago_in_wordsbukan waktu S
23tux
6

Lihatlah metode instance di sini:

http://apidock.com/rails/Time

Ini memiliki metode yang berguna seperti kemarin, besok, begin_of_week, lalu, dll.

Contoh:

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

Saya telah menulis permata yang melakukan ini untuk objek Rails ActiveRecord. Contoh ini menggunakan Created_at, tetapi itu juga akan bekerja pada updated_at atau apa pun dengan kelas ActiveSupport :: TimeWithZone.

Cukup instal dan panggil metode 'cantik' pada contoh TimeWithZone Anda.

https://github.com/brettshollenberger/hublot

Brett Shollenberger
sumber
1

Jika Anda sedang membangun aplikasi Rails, Anda harus menggunakan

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

Ini memberi Anda waktu atau tanggal di zona waktu yang Anda gunakan untuk mengkonfigurasi aplikasi Rails Anda.

Misalnya, jika Anda mengonfigurasi aplikasi Anda untuk menggunakan UTC, maka Time.zone.nowakan selalu dalam waktu UTC (itu tidak akan terpengaruh oleh perubahan Musim Panas Inggris misalnya).

Menghitung waktu relatif itu mudah, mis

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