Як перетворити часову позначку unix (секунди з епохи) в Ruby DateTime?


Відповіді:


354

DateTime.strptimeможе обробляти секунди з епохи. Номер повинен бути перетворений у рядок:

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

4
Це не справляється з дробовими секундами
— Ден Сандберг

45
Він обробляє мілісекунди з ' %Qtho.
— Міні Джон

3
Продовжити відповідь на відповідь @ TheMiniJohn. Схоже, Timeце потрібно замість цього DateTime. Тож використовуйте, Time.strptime("1318996912345",'%Q').to_fі ви побачите збережені мілісекунди, а DateTime.strptime("1318996912345",'%Q').to_fне збережете їх.
— skensell

625

Вибачте, короткий момент помилки синапсу. Ось справжня відповідь.

require 'date'

Time.at(seconds_since_epoch_integer).to_datetime

Короткий приклад (тут враховується поточний часовий пояс системи):

$ 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)> 

Подальше оновлення (для 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)>

Нещодавнє оновлення : під час роботи над сервісом HA, я порівняв основні рішення в цій темі, і здивовано виявив, що це Time.at(..)перевершує DateTime.strptime(..)(оновлення: додано більше орієнтирів).

# ~ % 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
Дякую ... Наступна відповідь є трохи більш короткою, я знайшов Time.at, але намагався знайти еквівалент DateTime.
— Тронатан

27
Це смішно, але Time.at (). To_datetime здається приємнішим ніж DateTime.strptime () просто через читабельність ... Принаймні для мене все одно
— tybro0103

34
Це не те саме, що вищезгаданий anser, Time.at передбачає поточний часовий пояс, де DateTime.strptime використовує UTC.
— Віталій Бабій

5
Це не надто дивно, що Time.atперевершує DateTime.strptime. Останній повинен розбирати рядок, який, як правило, набагато повільніше, ніж безпосередньо приймати число.
— Кліп

2
Ваш базовий показник не є точно тестуючим, DateTime.strptimeоскільки він створює дві нові рядки, кожна ітерація, що дуже дорого. Це не просто розбір рядків, як сказав
— @claw

67

Обробка часового поясу

Я просто хочу уточнити, хоча це було прокоментовано, щоб майбутні люди не пропустили цієї дуже важливої ​​відзнаки.

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

відображає значення повернення в UTC і вимагає, щоб секунди були рядком і виводили об'єкт часу UTC, тоді як

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

відображає повернене значення у часовому поясі LOCAL, як правило, потрібен аргумент FixNum, але сам об’єкт Time все ще знаходиться в UTC, хоча дисплей це не так.

Отже, хоча я передав однакове ціле число обом методам, я, мабуть, два різні результати через те, як #to_sпрацює метод класу . Однак, як @Eero довелося мені двічі нагадувати про:

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

Порівняння рівності між двома поверненими значеннями все ще повертає істину. Знову ж таки, це тому, що значення в основному однакові (хоча різні класи, #==метод це забезпечує для вас), але #to_sметод друкує різко різні рядки. Хоча, якщо ми подивимось на рядки, ми можемо побачити, що вони справді є одним і тим же часом, просто надрукованими в різних часових поясах.

Роз'яснення аргументу методу

Документи також кажуть "Якщо наведено числовий аргумент, результат знаходиться в локальному часі". що має сенс, але мене трохи бентежить, оскільки вони не наводять жодних прикладів не цілих аргументів у документах. Отже, для деяких нецілих прикладів аргументів:

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

ви не можете використовувати аргумент String, але ви можете використовувати аргумент Time в Time.atі він поверне результат у часовий пояс аргументу:

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

Орієнтири

Після дискусії з @AdamEberlin щодо його відповіді я вирішив опублікувати трохи змінені орієнтири, щоб зробити все максимально рівним. Крім того, мені ніколи не хочеться знову будувати їх, щоб це було гарне місце, як і будь-яке, щоб зберегти їх.

Time.at (int) .to_datetime ~ 2.8x швидше

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>

**** відредаговано так, щоб не бути абсолютно та абсолютно невірним у всіх відношеннях ****

**** додано орієнтири ****


3
Здавалося, правдоподібно, і я вже подав заявку (не можу скасувати відмову зараз), але після подальшої перевірки вашої претензії щодо UTC є неправдивою. Отриманий в результаті об'єкт DateTime / Time буде в UTC та локальному, так, але початкова мітка часу трактується як UTC у обох випадках! Тож момент часу рівний незалежно від методу. Спробуйте Time.at(1318996912) == DateTime.strptime("1318996912",'%s')в часовому поясі без UTC, і ви побачите!
— Ееро

4
Вибачте, але те, що ви виправили, все-таки помиляється! :-) Запустіть, Time.use_zone "Samoa" do Time.at(1318996912) == DateTime.strptime("1318996912",'%s') endщоб переконатися, що час однаковий, немає часової позначки LOCAL, і в обох випадках часова мітка Unix трактується як UTC. Time.at представляє отриманий об’єкт Time у локальному часовому поясі та DateTime.strptime представляє отриманий об’єкт DateTime в UTC, але незалежно від презентації вони рівні, оскільки є рівнозначним моментом часу.
— Ееро

Заява, тоді як Time.at(1318996912) # => 2011-10-19 00:01:52 -0400відображає значення повернення у часовому поясі LOCAL , не видається точним ... Чи можете ви підтвердити це? Я вважаю, що ваше твердження було б правдивим лише в тому випадку, якщо ви використовувалиTime.zone.at(1318996912)
— BigRon

Так, це здається точно. Моя локальна машина встановлена ​​на EST, а час відображається в EST.
— WattsInABox

Чи можете ви навести приклад, коли це не так @BigRon? Який часовий пояс, рубінова версія тощо не веде себе таким чином?
— WattsInABox

10

Одна команда для перетворення часу дати у формат Unix, а потім у рядок

    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

нарешті строповий текст використовується для форматування дати

Приклад:

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

Варто зазначити, що формат епохи не має часового поясу, тому ланцюжок utc перед ланцюжком to_i не потрібна Time.now.utc.to_i.
— Тревор Маккасланд

1

Це повідомляє про дату кількості секунд у майбутньому з моменту виконання коду.

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

ставить (час)

відповідно до поточного часу, я відповідаю на питання, яке воно друкує 047-05-14 05:16:16 +0000 (1 мільярд секунд у майбутньому)

або якщо ви хочете відлічити мільярд секунд за певний час, це у форматі Time.mktime(year, month,date,hours,minutes)

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

put ("мені було б 1 мільярд секунд:" + час)


0

Якщо ви хотіли просто побачити, ви можете робити Date.strptime(invoice.date.to_s, '%s')там, де invoice.dateнадходить у формі, Fixnumа потім перетворити на а String.


3
Time.at(1500923406).to_date.to_s=>"2017-07-24"
— Хлоя
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.