Làm cách nào để chuyển đổi dấu thời gian unix (giây kể từ epoch) sang Ruby DateTime?


369

Làm thế nào để bạn chuyển đổi dấu thời gian Unix (giây kể từ epoch) sang Ruby DateTime?

Câu trả lời:


354

DateTime.strptimecó thể xử lý giây kể từ kỷ nguyên. Số phải được chuyển đổi thành một chuỗi:

require 'date'
DateTime.strptime("1318996912",'%s')

4
Điều này không xử lý giây phân đoạn
Dan Sandberg

45
Nó xử lý miliseconds với ' %Qtho.
Mini John

3
Để theo dõi câu trả lời của @ TheMiniJohn. Có vẻ như Timelà cần thiết thay vì DateTime. Vì vậy, sử dụng Time.strptime("1318996912345",'%Q').to_fvà bạn sẽ thấy một phần nghìn giây được bảo tồn, trong khi DateTime.strptime("1318996912345",'%Q').to_fkhông bảo tồn nó.
skensell

625

Xin lỗi, khoảnh khắc ngắn gọn của sự thất bại synapse. Đây là câu trả lời thực sự.

require 'date'

Time.at(seconds_since_epoch_integer).to_datetime

Ví dụ ngắn gọn (điều này tính đến múi giờ hệ thống hiện tại):

$ date +%s
1318996912

$ irb

ruby-1.9.2-p180 :001 > require 'date'
 => true 

ruby-1.9.2-p180 :002 > Time.at(1318996912).to_datetime
 => #<DateTime: 2011-10-18T23:01:52-05:00 (13261609807/5400,-5/24,2299161)> 

Cập nhật thêm (cho UTC):

ruby-1.9.2-p180 :003 > Time.at(1318996912).utc.to_datetime
 => #<DateTime: 2011-10-19T04:01:52+00:00 (13261609807/5400,0/1,2299161)>

Cập nhật gần đây : Tôi đã điểm chuẩn các giải pháp hàng đầu trong chuỗi này khi làm việc trên dịch vụ HA một hoặc hai tuần trước và rất ngạc nhiên khi thấy rằng nó Time.at(..)vượt trội hơn DateTime.strptime(..)(cập nhật: thêm nhiều điểm chuẩn).

# ~ % ruby -v
#  => ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin13.0]

irb(main):038:0> Benchmark.measure do
irb(main):039:1*   ["1318996912", "1318496912"].each do |s|
irb(main):040:2*     DateTime.strptime(s, '%s')
irb(main):041:2>   end
irb(main):042:1> end

=> #<Benchmark ... @real=2.9e-05 ... @total=0.0>

irb(main):044:0> Benchmark.measure do
irb(main):045:1>   [1318996912, 1318496912].each do |i|
irb(main):046:2>     DateTime.strptime(i.to_s, '%s')
irb(main):047:2>   end
irb(main):048:1> end

=> #<Benchmark ... @real=2.0e-05 ... @total=0.0>

irb(main):050:0* Benchmark.measure do
irb(main):051:1*   ["1318996912", "1318496912"].each do |s|
irb(main):052:2*     Time.at(s.to_i).to_datetime
irb(main):053:2>   end
irb(main):054:1> end

=> #<Benchmark ... @real=1.5e-05 ... @total=0.0>

irb(main):056:0* Benchmark.measure do
irb(main):057:1*   [1318996912, 1318496912].each do |i|
irb(main):058:2*     Time.at(i).to_datetime
irb(main):059:2>   end
irb(main):060:1> end

=> #<Benchmark ... @real=2.0e-05 ... @total=0.0>

1
Cảm ơn bạn ... Câu trả lời sau đây ngắn gọn hơn một chút, tôi đã tìm thấy Time.at nhưng đang cố gắng tìm một DateTime tương đương.
Tronathan

27
Thật buồn cười nhưng Time.at (). To_datetime có vẻ dễ chịu hơn DateTime.strptime () đơn giản chỉ vì khả năng đọc ... Ít nhất là với tôi dù thế nào
tybro0103

34
Điều này không giống với anser ở trên, Time.at giả định múi giờ hiện tại, trong đó DateTime.strptime sử dụng UTC.
Vitaly Babiy

5
Nó không quá ngạc nhiên khi Time.atvượt trội hơn DateTime.strptime. Cái sau phải phân tích một chuỗi, thường chậm hơn nhiều so với lấy trực tiếp một số.
Móng vuốt

2
Điểm chuẩn của bạn không chính xác kiểm tra DateTime.strptimevì nó tạo ra hai Chuỗi mới mỗi lần lặp rất tốn kém. Đó không chỉ là phân tích cú pháp chuỗi như @claw đã nói
WattsInABox

67

Xử lý múi giờ

Tôi chỉ muốn làm rõ, mặc dù điều này đã được bình luận để mọi người trong tương lai không bỏ lỡ sự khác biệt rất quan trọng này.

DateTime.strptime("1318996912",'%s') # => Wed, 19 Oct 2011 04:01:52 +0000

hiển thị giá trị trả về trong UTC và yêu cầu giây phải là Chuỗi và xuất ra đối tượng Thời gian UTC, trong khi

Time.at(1318996912) # => 2011-10-19 00:01:52 -0400

hiển thị giá trị trả về trong múi giờ ĐỊA PHƯƠNG, thông thường yêu cầu đối số FixNum, nhưng bản thân đối tượng Thời gian vẫn ở trong UTC mặc dù màn hình không hiển thị.

Vì vậy, mặc dù tôi đã truyền cùng một số nguyên cho cả hai phương thức, tôi dường như có hai kết quả khác nhau do cách #to_sthức hoạt động của phương thức lớp . Tuy nhiên, như @Eero đã phải nhắc tôi hai lần:

Time.at(1318996912) == DateTime.strptime("1318996912",'%s') # => true

Một so sánh bằng giữa hai giá trị trả về vẫn trả về true. Một lần nữa, điều này là do các giá trị về cơ bản là giống nhau (mặc dù các lớp khác nhau, #==phương thức này đảm nhận việc này cho bạn), nhưng #to_sphương thức in các chuỗi khác nhau mạnh mẽ. Mặc dù, nếu chúng ta nhìn vào các chuỗi, chúng ta có thể thấy chúng thực sự giống nhau, chỉ được in ở các múi giờ khác nhau.

Phương pháp làm rõ đối số

Các tài liệu cũng nói "Nếu một đối số số được đưa ra, kết quả là theo giờ địa phương." điều này có ý nghĩa, nhưng hơi khó hiểu với tôi vì họ không đưa ra bất kỳ ví dụ nào về các đối số không nguyên trong tài liệu. Vì vậy, đối với một số ví dụ đối số không nguyên:

Time.at("1318996912")
TypeError: can't convert String into an exact number

bạn không thể sử dụng đối số Chuỗi, nhưng bạn có thể sử dụng đối số Thời gian Time.atvà nó sẽ trả về kết quả trong múi giờ của đối số:

Time.at(Time.new(2007,11,1,15,25,0, "+09:00"))
=> 2007-11-01 15:25:00 +0900

Điểm chuẩn

Sau một cuộc thảo luận với @AdamEberlin về câu trả lời của anh ấy, tôi quyết định công bố điểm chuẩn thay đổi một chút để mọi thứ đều bình đẳng nhất có thể. Ngoài ra, tôi không bao giờ muốn phải xây dựng lại những thứ này vì vậy đây là nơi tốt nhất để cứu chúng.

Time.at (int) .to_datetime ~ 2.8x nhanh hơn

09:10:58-watsw018:~$ ruby -v
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]
09:11:00-watsw018:~$ irb
irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> require 'date'
=> true
irb(main):003:0>
irb(main):004:0* format = '%s'
=> "%s"
irb(main):005:0> times = ['1318996912', '1318496913']
=> ["1318996912", "1318496913"]
irb(main):006:0> int_times = times.map(&:to_i)
=> [1318996912, 1318496913]
irb(main):007:0>
irb(main):008:0* datetime_from_strptime = DateTime.strptime(times.first, format)
=> #<DateTime: 2011-10-19T04:01:52+00:00 ((2455854j,14512s,0n),+0s,2299161j)>
irb(main):009:0> datetime_from_time = Time.at(int_times.first).to_datetime
=> #<DateTime: 2011-10-19T00:01:52-04:00 ((2455854j,14512s,0n),-14400s,2299161j)>
irb(main):010:0>
irb(main):011:0* datetime_from_strptime === datetime_from_time
=> true
irb(main):012:0>
irb(main):013:0* Benchmark.measure do
irb(main):014:1*   100_000.times {
irb(main):015:2*     times.each do |i|
irb(main):016:3*       DateTime.strptime(i, format)
irb(main):017:3>     end
irb(main):018:2>   }
irb(main):019:1> end
=> #<Benchmark::Tms:0x00007fbdc18f0d28 @label="", @real=0.8680500000045868, @cstime=0.0, @cutime=0.0, @stime=0.009999999999999998, @utime=0.86, @total=0.87>
irb(main):020:0>
irb(main):021:0* Benchmark.measure do
irb(main):022:1*   100_000.times {
irb(main):023:2*     int_times.each do |i|
irb(main):024:3*       Time.at(i).to_datetime
irb(main):025:3>     end
irb(main):026:2>   }
irb(main):027:1> end
=> #<Benchmark::Tms:0x00007fbdc3108be0 @label="", @real=0.33059399999910966, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.32000000000000006, @total=0.32000000000000006>

**** được chỉnh sửa để không hoàn toàn và hoàn toàn không chính xác theo mọi cách ****

**** thêm điểm chuẩn ****


3
Có vẻ hợp lý và tôi đã nâng cấp lên (không thể hủy bỏ ngay bây giờ), nhưng khi kiểm tra thêm yêu cầu của bạn về UTC là không đúng sự thật. Đối tượng DateTime / Time kết quả sẽ ở UTC so với cục bộ, vâng, nhưng dấu thời gian ban đầu được hiểu là ở trong UTC trong cả hai trường hợp! Vì vậy, thời điểm trong thời gian là bằng nhau bất kể phương pháp. Hãy thử Time.at(1318996912) == DateTime.strptime("1318996912",'%s')trong múi giờ không thuộc UTC và bạn sẽ thấy!
Eero

4
Tôi xin lỗi, nhưng những gì bạn sửa vẫn sai! :-) Chạy Time.use_zone "Samoa" do Time.at(1318996912) == DateTime.strptime("1318996912",'%s') endđể xác minh rằng thời gian bằng nhau, không có dấu thời gian ĐỊA PHƯƠNG và trong cả hai trường hợp, dấu thời gian Unix được hiểu là ở trong UTC. Time.at trình bày đối tượng Thời gian kết quả theo múi giờ địa phương và DateTime.strptime trình bày đối tượng DateTime kết quả trong UTC, nhưng bất kể trình bày chúng có bằng nhau, vì chúng là thời điểm tương đương theo thời gian.
Eero

Câu lệnh trong khi Time.at(1318996912) # => 2011-10-19 00:01:52 -0400hiển thị giá trị trả về trong múi giờ ĐỊA PHƯƠNG có vẻ không chính xác ... Bạn có thể xác minh không? Tôi tin rằng tuyên bố của bạn sẽ chỉ đúng nếu bạn sử dụngTime.zone.at(1318996912)
BigRon

Vâng, điều đó dường như là chính xác. Máy cục bộ của tôi được đặt thành EST và thời gian hiển thị ở EST.
WattsInABox

Bạn có thể cung cấp một ví dụ trong trường hợp này không phải là trường hợp @BigRon? Múi giờ, phiên bản ruby, vv không hoạt động theo cách này?
WattsInABox

10

Một lệnh để chuyển đổi thời gian ngày sang định dạng Unix và sau đó thành chuỗi

    DateTime.strptime(Time.now.utc.to_i.to_s,'%s').strftime("%d %m %y")

    Time.now.utc.to_i #Converts time from Unix format
    DateTime.strptime(Time.now.utc.to_i.to_s,'%s') #Converts date and time from unix format to DateTime

cuối cùng strftime được sử dụng để định dạng ngày

Thí dụ:

    irb(main):034:0> DateTime.strptime("1410321600",'%s').strftime("%d %m %y")
    "10 09 14"

Một điều cần lưu ý là định dạng epoch không có múi giờ nên việc sử dụng utc trước khi xâu chuỗi to_i là không cần thiết Time.now.utc.to_i.
Trevor McCasland

1

Điều này cho bạn biết ngày của số giây trong tương lai kể từ thời điểm bạn thực thi mã.

time = Time.new + 1000000000 #date in 1 billion seconds

đặt (thời gian)

theo thời điểm hiện tại tôi đang trả lời câu hỏi mà nó in ra 047-05-14 05:16:16 +0000(1 tỷ giây trong tương lai)

hoặc nếu bạn muốn đếm hàng tỷ giây từ một thời điểm cụ thể, thì đó là định dạng Time.mktime(year, month,date,hours,minutes)

time = Time.mktime(1987,8,18,6,45) + 1000000000

đặt ("Tôi sẽ là 1 tỷ giây tuổi:" + thời gian)


0

Nếu bạn chỉ muốn một Ngày, bạn có thể thực hiện Date.strptime(invoice.date.to_s, '%s')ở đâu invoice.datedưới dạng một Fixnumvà sau đó được chuyển đổi thành một String.


3
Time.at(1500923406).to_date.to_s=>"2017-07-24"
Chloe
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.