Chuyển đổi thời lượng thành giờ: phút: giây (hoặc tương tự) trong Rails 3 hoặc Ruby


114

Tôi có cảm giác có một cách đơn giản / tích hợp để làm điều này nhưng tôi không thể tìm thấy nó.

Tôi có thời lượng (tính bằng giây) ở dạng số nguyên và tôi muốn hiển thị thời lượng đó ở định dạng thân thiện.

ví dụ: 3600 sẽ được hiển thị là "01:00:00" hoặc "1 giờ" hoặc một cái gì đó.

Tôi có thể làm điều đó với time_ago_in_words(Time.zone.now+3600)nhưng điều đó giống như một chút hack, không có lý do gì để thêm / trừ vào thời điểm hiện tại chỉ để định dạng giá trị này. Có mộtduration_in_words() hoặc một cái gì đó?

Cảm ơn

Câu trả lời:


82

Xem: http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html

distance_of_time_in_words(3600)
 => "about 1 hour"

1
cảm ơn tôi đã nhìn vào đó nhưng nghĩ rằng tôi phải cung cấp hai lần .. thật là một nub!
cydonia

1
vâng, những ví dụ đó thật tuyệt
allan

1
distance_of_time_in_words (from_time, to_time, ...)
boulder_ruby

1
Ngoài ra, nếu bạn muốn điều này thật cụ thể và không "làm tròn" thời lượng, hãy xem gem của Radar: github.com/radar/distance_of_time_in_words . Drop-in thay thế cho distance_of_time_in_wordsvà bạn có thể nhận được số làm tròn bằng cách chuyển vague: truenhư một tùy chọn.
Joshua Pinter

194

Tổng hợp:

giả sử rằng total_seconds = 3600

Lựa chọn 1:

distance_of_time_in_words(total_seconds) #=> "about 1 hour"

Lựa chọn 2:

Time.at(total_seconds).utc.strftime("%H:%M:%S") #=> "01:00:00"

Tùy chọn 3:

seconds = total_seconds % 60
minutes = (total_seconds / 60) % 60
hours = total_seconds / (60 * 60)

format("%02d:%02d:%02d", hours, minutes, seconds) #=> "01:00:00"

sử dụng Option1 nếu bạn muốn các từ, Option2 nếu bạn muốn định dạng H: M: S, Option3 nếu bạn muốn định dạng H: M: S và có thể có hơn 24 giờ


1
Phương thức distance_of_time_in_words là Trình trợ giúp ActionView, do đó cần được gọi từ Chế độ xem (không phải trình điều khiển). api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
msdundar

13
Lưu ý rằng tùy chọn strftime sẽ tràn sau 24 giờ. Nếu thời lượng của bạn là 25 giờ, nó sẽ hiển thị 01:00:00.
Gabe Martin-Dempesy

2
điều này không hoạt động đối với thời gian âm, ví dụ: -1800 trả về -1 giờ 30 phút thay vì -30 phút
Arnold Roa

43

%Toán tử chuỗi của Ruby quá không được đánh giá cao và bị lãng quên.

"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]

Với t là khoảng thời gian tính bằng giây, điều này tạo ra một chuỗi được phân tách bằng dấu hai chấm không có đệm bao gồm ngày. Thí dụ:

t = 123456
"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]
=> "01:10:17:36"

Đáng yêu.


24
Đó là một định nghĩa kỳ quặc về "đáng yêu".
Marc Bollinger

10
Câu %nói "Lấy mảng tham số từ bên phải của tôi và chèn chúng vào chuỗi định dạng ở bên trái của tôi." Về mặt đó, nó tương tự như printftrong C \ C ++ chỉ ngắn gọn hơn và có thể được sử dụng trong một bài tập. Vâng, tôi gọi đó là đáng yêu. Và mạnh mẽ. Có những ví dụ sẽ chứng minh khả năng hùng biện này tốt hơn, nhưng chúng sẽ không trả lời được câu hỏi. Snark của bạn không được đánh giá cao, btw.
IAmNaN

26

Tôi đoán bạn cũng có thể làm điều gì đó như:

(Time.mktime(0)+3600).strftime("%H:%M:%S")

Để định dạng nó như bạn muốn.

BTW, ban đầu tôi nghĩ đến việc sử dụng Time.at () nhưng có vẻ như thời gian EPOCH trên Ubuntu của tôi là 01:00:00 +0100 vào Thứ Năm 1970 chứ không phải 00:00:00 giờ như tôi mong đợi, và do đó nếu tôi làm như vậy:

Time.at(3600).strftime("%H:%M:%S")

Cho tôi 1 giờ nhiều hơn mong muốn.


à, có thể làm gì đó vì thời gian mùa hè?
Cristobal Viedma

7
Cách duy nhất là nếu bạn đang xử lý với thời gian hơn 24 giờ. Trong trường hợp đó, giờ sẽ quay trở lại một con số thấp.
metavida

Đối với lần lớn hơn 24 giờ,% j sẽ cung cấp cho bạn số ngày (miễn là nó ít hơn 365)
BananaNeil

17

Tôi sử dụng cái này để hiển thị khoảng thời gian trong Dự án Rails của mình:

  1. Thêm một phương thức tùy chỉnh vào Integerlớp. Bạn có thể tạo một tệp mới có tên pretty_duration.rbtrong initializersthư mục:

    class Integer
        def pretty_duration
            parse_string = 
                if self < 3600
                    '%M:%S'
                else
                    '%H:%M:%S'
                end
    
            Time.at(self).utc.strftime(parse_string)
        end
    end
  2. Gọi seconds.pretty_durationbất cứ nơi nào trong dự án của bạn:

    275.pretty_duration     # => "04:35"
    9823.pretty_duration    # => "02:43:43"

Câu trả lời này được xây dựng dựa trên Mã của Lev Lukomsky


Làm việc rất tốt. Cảm ơn vì điều này.
Donn Felker

13

Phương pháp này sử dụng divmodphương pháp tối nghĩa để phân chia và mô-đun cùng một lúc, vì vậy nó xử lý Floatgiây đúng cách:

def duration(seconds)
  minutes, seconds = seconds.divmod(60)
  hours, minutes = minutes.divmod(60)
  days, hours = hours.divmod(24)

  "#{days.to_s.rjust(3)}d #{hours.to_s.rjust(2)}h #{minutes.to_s.rjust(2)}m #{seconds}s"
end

6

Sử dụng Time.utc.strftimechỉ hoạt động cho các giá trị khi tổng số giờ ít hơn 24 :

2.2.2 :004 > Time.at(60 * 60).utc.strftime('%H h %M m')
=> "01 h 00 m"

Đối với các giá trị lớn hơn, nó trả về kết quả không chính xác:

2.2.2 :006 > Time.at(60 * 60 * 24).utc.strftime('%H h %M m')
 => "00 h 00 m"

Tôi khuyên bạn nên sử dụng phương pháp đơn giản nhất mà tôi tìm thấy cho vấn đề này:

  def formatted_duration total_seconds
    hours = total_seconds / (60 * 60)
    minutes = (total_seconds / 60) % 60
    seconds = total_seconds % 60
    "#{ hours } h #{ minutes } m #{ seconds } s"
  end

Bạn luôn có thể điều chỉnh giá trị trả về theo nhu cầu của mình.


5

Hãy cẩn thận với thời gian dài hơn một ngày.

(timing/3600).to_i.to_s.rjust(2,'0') + ":"+Time.at(timing).utc.strftime("%M:%S")

Đưa ra một ví dụ về đầu vào / đầu ra làm nổi bật cách giải quyết điều này các trường hợp góc
Cyril Duchon-Doris

4

Một câu trả lời lấy cảm hứng từ câu trả lời của Lev Lukomsky tận dụng ActiveSupport :: Thời lượng và xử lý mili giây (hữu ích cho mã điểm chuẩn)

# duration in ms modulus number of ms in one second
milliseconds = duration.in_milliseconds % 1.second.in_milliseconds

# duration in seconds modulus number of seconds in one minute
seconds = (duration / 1.second) % (1.minute / 1.second)

# duration in minutes modulus number of minutes in one hour
minutes = (duration / 1.minute) % (1.hour / 1.minute)

# duration in hours modulus number of hours in one day
hours = (duration / 1.hour) % (1.day / 1.hour)

format("%02d:%02d:%02d:%03d", hours, minutes, seconds, milliseconds) #=> "12:05:00:001"

Tất nhiên, bạn có thể mở rộng điều này dễ dàng với ngày, tháng, năm, v.v. bằng cách sử dụng các phương thức ActiveSupport có liên quan và lặp lại cùng một cấu trúc.

Hãy nhớ rằng trong khoảng thời gian quá dài, điều này có thể không chính xác vì thời hạn 1 tháng không cố định về số ngày và tôi không chắc AS: Duration giải quyết vấn đề đó như thế nào.


2

Chỉ để ném vào 2 xu của tôi:

Time.at(i).utc.strftime((i < 3600) ? '%-M minutes and %-S seconds' : '%-H hours, %-M minutes, and %-S seconds')

Dựa trên câu trả lời của Xiao Bin.


2

Hãy gửi lời cảm ơn tới @joshuapinter , người đã đưa ra câu trả lời hay nhất (dưới dạng nhận xét ).

Sử dụng thay thế thả vào dotiw đá quý để kiểm soát nhiều hơn độ chính xác của đầu ra cho phù hợp với các nhu cầu khác nhau:

https://github.com/radar/distance_of_time_in_words

Mã xem mẫu:

%label
  Logoff after:
  - expire_in = distance_of_time_in_words(Time.now, Time.now + user.custom_timeout.minutes, :only => [:minutes, :hours, :days])
  = expire_in

Dẫn đến một cái gì đó như thế này:

Logoff after: 1 day, 13 hours, and 20 minutes

2

ActiveSupport::Duration.build+ inspectcung cấp cho bạn kết quả hợp lệ

 >> ActiveSupport::Duration.build(125557).inspect
 => "1 day, 10 hours, 52 minutes, and 37 seconds"

1
    hours = 3.5456
    value = (hours*60).divmod(60).map{ |a| "%02d"%[a.floor] }.join(":")
    => "03:32"

5
Vui lòng thêm một số ngữ cảnh vào câu trả lời.
Paul Dawson
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.