Jak uzyskać czas w milisekundach w Rubim?

98

Jeśli mam Timeprzedmiot otrzymany od:

Time.now

a później tworzę instancję innego obiektu z tą samą linią, jak mogę sprawdzić, ile milisekund minęło? Drugi obiekt może powstać w tej samej minucie, w ciągu następnych minut lub nawet godzin.

Geo
źródło

Odpowiedzi:

133

Jak już wspomniano, możesz operować na Timeobiektach tak, jakby były wartościami numerycznymi (lub zmiennoprzecinkowymi). Te operacje dają drugą rozdzielczość, którą można łatwo przekonwertować.

Na przykład:

def time_diff_milli(start, finish)
   (finish - start) * 1000.0
end

t1 = Time.now
# arbitrary elapsed time
t2 = Time.now

msecs = time_diff_milli t1, t2

Będziesz musiał zdecydować, czy to skrócić, czy nie.

ezpz
źródło
2
dodaj to_i i masz to jako liczbę całkowitą, np .: ((koniec - początek) * 1000.0) .to_i
Travis Reeder,
finish.to_f - start.to_f?
wyrazisty
1
finish - startdaje zmiennoprzecinkowe; .to_fbyłoby zbędne.
ezpz
5
Jeśli korzystasz z szyn lub aktywnego wsparcia, możesz użyć metody #in_milliseconds, aby wykonać tę samą konwersję(t2 - t1).in_milliseconds
Nathan Hanna
58

Możesz dodać trochę cukru składniowego do powyższego rozwiązania, wykonując następujące czynności:

class Time
  def to_ms
    (self.to_f * 1000.0).to_i
  end
end

start_time = Time.now
sleep(3)
end_time = Time.now
elapsed_time = end_time.to_ms - start_time.to_ms  # => 3004
phlipper
źródło
31

Myślę, że odpowiedź jest źle wybrana, ta metoda daje sekundy, a nie milisekundy.

t = Time.now.t­o_f
=> 1382471965.146

Przypuszczam, że wartość zmienna to milisekundy

Teoria niskiego pola
źródło
1
Wybrana odpowiedź jest prawidłowa. Używanie włączonego dodawania lub odejmowania Time.nowoznacza traktowanie czasu jako wartości zmiennoprzecinkowych z sekundami przed przecinkiem i do nanosekund po przecinku (chociaż nsec może nie być całkowicie dokładne). Więc pomnożenie tej wartości przez 1000.0milisekundy.
dfherr
tak, ale podanie tylko „Time.now” jest niedokładne i nie odpowiada dokładnie na pytanie.
LowFieldTheory
12

Aby uzyskać czas w milisekundach, lepiej dodać .round(3), więc w niektórych przypadkach będzie dokładniejszy:

puts Time.now.to_f # => 1453402722.577573

(Time.now.to_f.round(3)*1000).to_i  # => 1453402722578
Steven Yue
źródło
9

Odpowiedź ezpz jest prawie idealna, ale mam nadzieję, że mogę dodać trochę więcej.

Geo zapytał o czas w milisekundach; brzmi to jak liczba całkowita i nie wybrałbym objazdu przez ziemię zmiennoprzecinkową. Zatem moje podejście byłoby następujące:

irb(main):038:0> t8 = Time.now
=> Sun Nov 01 15:18:04 +0100 2009
irb(main):039:0> t9 = Time.now
=> Sun Nov 01 15:18:18 +0100 2009
irb(main):040:0> dif = t9 - t8
=> 13.940166
irb(main):041:0> (1000 * dif).to_i
=> 13940

Mnożenie przez liczbę całkowitą 1000 doskonale zachowuje liczbę ułamkową i może być również trochę szybsze.

Jeśli masz do czynienia z datami i godzinami, może być konieczne użycie klasy DateTime . Działa to podobnie, ale współczynnik konwersji wynosi 24 * 3600 * 1000 = 86400000 .

Zauważyłem, że funkcje strptime i strftime DateTime są nieocenione w analizowaniu i formatowaniu ciągów daty / czasu (np. Do / z dzienników). Warto wiedzieć:

  • Znaki formatujące dla tych funkcji (% H,% M,% S, ...) są prawie takie same jak dla funkcji C znajdujących się w każdym systemie Unix / Linux; i

  • Jest jeszcze kilka: w szczególności % L robi milisekundy!

Carl Smotricz
źródło
Dobrze wiedzieć! Dzięki unknown:)
Geo
1
Zresztą% L istnieje tylko w Rubim 1.9;)
Rafa de Castro
7
DateTime.now.strftime("%Q")

Przykładowe użycie:

>> DateTime.now.strftime("%Q")
=> "1541433332357"

>> DateTime.now.strftime("%Q").to_i
=> 1541433332357
Ryan McGeary
źródło
6

Time.now.to_f może ci pomóc, ale zwraca sekundy.

Generalnie podczas pracy z benchmarkami I:

  • wstaw zmienną aktualny czas;
  • wstaw blok do przetestowania;
  • wstaw do zmiennej bieżący czas, odejmując poprzednią wartość bieżącego czasu;

To bardzo prosty proces, więc nie jestem pewien, czy naprawdę o to pytałeś ...


źródło
6

%L daje milisekundy w rubinie

require 'time'
puts Time.now.strftime("%Y-%m-%dT%H:%M:%S.%L")

lub

puts Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")

poda aktualny znacznik czasu w milisekundach.

Sandeep Singh Nagra
źródło
To nie mówi, jak uzyskać upływający czas.
Robert
4

Odpowiedź brzmi mniej więcej tak:

t_start = Time.now
# time-consuming operation
t_end = Time.now

milliseconds = (t_start - t_end) * 1000.0

Jednak takie Time.nowpodejście może być niedokładne. Znalazłem ten post Luca Guidi:

https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/

zegar systemowy nieustannie płynie i nie przesuwa się tylko do przodu. Jeśli opiera się na niej obliczanie czasu, który upłynął, jest bardzo prawdopodobne, że wystąpią błędy obliczeniowe lub nawet przestoje .

Dlatego zaleca się użycie Process.clock_gettimezamiast tego. Coś jak:

def measure_time
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elapsed_time = end_time - start_time
  elapsed_time.round(3)
end

Przykład:

elapsed = measure_time do
    # your time-consuming task here:
    sleep 2.2321
end

=> 2.232
Robert
źródło
3

Spróbuj odjąć pierwszy Time.now od drugiego. Tak jak to:

a = Time.now
sleep(3)
puts Time.now - a # about 3.0

To daje zmiennoprzecinkową liczbę sekund między tymi dwoma czasami (a wraz z tym milisekundami).

mrueg
źródło