แปลงระยะเวลาเป็นชั่วโมงนาที: วินาที (หรือใกล้เคียงกัน) ใน Rails 3 หรือ Ruby


115

ฉันรู้สึกว่ามีวิธีง่ายๆ / มีอยู่แล้วในตัวในการทำสิ่งนี้ แต่หาไม่เจอ

ฉันมีระยะเวลา (เป็นวินาที) เป็นจำนวนเต็มและฉันต้องการแสดงในรูปแบบที่เป็นมิตร

เช่น 3600 จะแสดงเป็น "01:00:00" หรือ "1 ชั่วโมง" หรือบางอย่าง

ฉันทำได้time_ago_in_words(Time.zone.now+3600)แต่รู้สึกเหมือนแฮ็คนิดหน่อยไม่มีเหตุผลที่จะบวก / ลบจากเวลาปัจจุบันเพื่อจัดรูปแบบค่านี้ มีduration_in_words()หรืออะไร?

ขอบคุณ

คำตอบ:


83

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

distance_of_time_in_words(3600)
 => "about 1 hour"

1
ขอบคุณฉันดู แต่คิดว่าฉันต้องให้สองครั้ง .. ช่างเป็นอะไร!
cydonia

1
ใช่ตัวอย่างเหล่านั้นเป็นคนโง่
allan

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

1
นอกจากนี้ถ้าคุณอยากให้เรื่องนี้เป็นอย่างเฉพาะเจาะจงและไม่ได้ "รอบ" ระยะเวลาในการตรวจสอบอัญมณีเรดาร์ของ: github.com/radar/distance_of_time_in_words การแทนที่แบบดรอปอินdistance_of_time_in_wordsและคุณจะได้รับตัวเลขที่ปัดเศษโดยส่งvague: trueเป็นตัวเลือก
Joshua Pinter

194

สรุป:

สมมติว่า total_seconds = 3600

ตัวเลือกที่ 1:

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

ทางเลือกที่ 2:

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

ทางเลือกที่ 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"

ใช้Option1ถ้าคุณต้องการคำOption2ถ้าคุณต้องการ H: M: รูปแบบ S, Option3ถ้าคุณต้องการ H: M: รูปแบบ S และสามารถมีได้มากกว่า 24 ชั่วโมง


1
เมธอด distance_of_time_in_words เป็น ActionView Helper จึงจำเป็นต้องเรียกใช้จาก View (ไม่ใช่คอนโทรลเลอร์) api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
msdundar

13
โปรดทราบว่าตัวเลือก strftime จะล้นใน 24 ชั่วโมง หากระยะเวลาของคุณคือ 25 01:00:00ชั่วโมงก็จะแสดง
Gabe Martin-Dempesy

2
สิ่งนี้ใช้ไม่ได้กับเวลาที่เป็นลบเช่น -1800 ส่งกลับ -1h 30m แทนที่จะเป็น -30m
Arnold Roa

45

%ตัวดำเนินการสายของ Ruby ไม่ได้รับการชื่นชมและมักจะถูกลืม

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

กำหนดให้tเป็นช่วงเวลาเป็นวินาทีซึ่งจะปล่อยสตริงที่คั่นด้วยโคลอนเป็นศูนย์รวมทั้งวัน ตัวอย่าง:

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

น่ารัก.


24
นั่นเป็นคำจำกัดความแปลก ๆ ของคำว่า "น่ารัก"
Marc Bollinger

10
ข้อความ%ระบุว่า "นำอาร์เรย์ของพารามิเตอร์จากด้านขวาของฉันและใส่ลงในสตริงรูปแบบทางด้านซ้ายของฉัน" ในแง่นั้นมันคล้ายกับprintfใน C \ C ++ เท่านั้นที่กระชับและสามารถใช้ในการมอบหมายงานได้ ใช่ฉันเรียกว่าน่ารัก และทรงพลัง. มีตัวอย่างที่จะแสดงให้เห็นถึงความคมคายนี้ได้ดีขึ้น แต่พวกเขาจะไม่ตอบคำถาม พวกคุณไม่ได้รับการชื่นชม btw
IAmNaN

26

ฉันเดาว่าคุณสามารถทำสิ่งต่างๆเช่น:

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

เพื่อจัดรูปแบบตามที่คุณต้องการ

BTW เดิมทีฉันคิดว่าจะใช้ Time.at () แต่ดูเหมือนว่าเวลา EPOCH บน Ubuntu ของฉันคือพฤ. 01 ม.ค. 01:00:00 +0100 1970 ไม่ใช่ 00:00:00 ชั่วโมงตามที่ฉันคาดไว้ดังนั้นถ้าฉันทำ:

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

ให้เวลาฉันมากกว่าที่ต้องการ 1 ชั่วโมง


อ่าอาจจะทำอะไรสักอย่างเพราะเป็นช่วงฤดูร้อน?
Cristobal Viedma

7
สิ่งเดียวที่จับได้คือถ้าคุณต้องรับมือกับเวลามากกว่า 24 ชั่วโมง ในกรณีนี้ชั่วโมงจะย้อนกลับไปเป็นตัวเลขที่ต่ำ
metavida

สำหรับเวลาที่มากกว่า 24 ชั่วโมง% j จะให้จำนวนวัน (ตราบเท่าที่น้อยกว่า 365)
BananaNeil

18

ฉันใช้สิ่งนี้เพื่อแสดงระยะเวลาในโครงการ Rails ของฉัน:

  1. เพิ่มวิธีการที่กำหนดเองในIntegerชั้นเรียน คุณสามารถสร้างไฟล์ใหม่ที่เรียกว่าpretty_duration.rbในinitializersโฟลเดอร์:

    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. โทรseconds.pretty_durationได้ทุกที่ในโครงการของคุณ:

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

คำตอบนี้สร้างขึ้นจากรหัสของ Lev Lukomsky


ทำงานได้ดีมาก ขอบคุณสำหรับสิ่งนี้.
Donn Felker

13

อันนี้ใช้divmodวิธีการปิดบังเพื่อแบ่งและโมดูโลในเวลาเดียวกันดังนั้นจึงจัดการFloatวินาทีได้อย่างเหมาะสม:

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

การใช้Time.utc.strftimeงานจะใช้ได้เฉพาะกับค่าเมื่อจำนวนชั่วโมงทั้งหมดน้อยกว่า 24 :

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

สำหรับค่าที่มากกว่าจะส่งกลับผลลัพธ์ที่ไม่ถูกต้อง:

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

ฉันขอแนะนำให้ใช้วิธีที่ง่ายที่สุดที่ฉันพบสำหรับปัญหานี้:

  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

คุณสามารถปรับมูลค่าที่ส่งคืนตามความต้องการของคุณได้ตลอดเวลา


5

ระวังด้วยระยะเวลานานกว่าหนึ่งวัน

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

ยกตัวอย่างอินพุต / เอาต์พุตที่เน้นว่าวิธีนี้แก้ปัญหามุม
Cyril Duchon-Doris

4

คำตอบที่ได้รับแรงบันดาลใจจาก Lev Lukomsky ที่ใช้ประโยชน์จาก ActiveSupport :: Duration และการจัดการมิลลิวินาที (มีประโยชน์กับโค้ด Benchmark)

# 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"

แน่นอนว่าคุณสามารถขยายสิ่งนี้ได้อย่างง่ายดายด้วยวันเดือนปีและอื่น ๆ โดยใช้วิธีการ ActiveSupport ที่เกี่ยวข้องและทำซ้ำโครงสร้างเดียวกัน

โปรดทราบว่าระยะเวลาที่นานเกินไปอาจไม่ถูกต้องเนื่องจากระยะเวลา 1 เดือนไม่ได้รับการกำหนดจำนวนวันและฉันไม่แน่ใจว่า AS: Duration เกี่ยวข้องกับสิ่งนั้นอย่างไร


2

เพียงแค่โยน 2 เซ็นต์ของฉัน:

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

สร้างขึ้นจากคำตอบของ Xiao Bin


2

ตะโกนถึง@joshuapinterที่ให้คำตอบที่ดีที่สุด (ในรูปแบบของความคิดเห็น )

ใช้dotiwอัญมณีทดแทนแบบดรอปอินเพื่อควบคุมความแม่นยำของเอาต์พุตได้มากขึ้นเพื่อให้เหมาะกับความต้องการที่แตกต่างกัน:

https://github.com/radar/distance_of_time_in_words

รหัสมุมมองตัวอย่าง:

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

ส่งผลให้เกิดสิ่งนี้:

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

2

ActiveSupport::Duration.build+ inspectให้ผลลัพธ์ที่ถูกต้อง

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.