2009-02-19 13 views
48

Ho il codice che fa il monitoraggio del tempo per i dipendenti. Crea un contatore per mostrare al dipendente per quanto tempo sono stati sincronizzati.Come ottengo il numero di secondi tra due DateTimes in Ruby on Rails

Questo è il codice corrente:

start_time = Time.parse(self.settings.first_clock_in) 
    total_seconds = Time.now - start_time 
    hours = (total_seconds/ 3600).to_i 
    minutes = ((total_seconds % 3600)/60).to_i 
    seconds = ((total_seconds % 3600) % 60).to_i 

Questo funziona bene. Ma poiché il tempo è limitato all'intervallo tra il 1970 e il 2038, stiamo cercando di sostituire tutti gli usi temporali con DateTimes. Non riesco a capire come ottenere il numero di secondi tra due DateTimes. Sottraendo loro si ottiene un Razionale che non so come interpretare, mentre sottraendo Times si ottiene la differenza in secondi.

risposta

64

Sottraendo due DateTimes restituisce il tempo trascorso in giorni, quindi si può solo fare:

elapsed_seconds = ((end_time - start_time) * 24 * 60 * 60).to_i 
+0

Ah, lo sapevo tornato in giorni, non sapevo che questo includerebbe frazioni di un giorno pure. Grazie. – Tilendor

+4

Questo non funziona correttamente in caso di un secondo salto (https://en.wikipedia.org/wiki/Leap_second). –

+31

Solo una nota per chiunque altro possa essere confuso da questo. Sì, sottraendo due 'DateTime's restituisce il tempo trascorso in giorni. Tuttavia, in Rails un attributo di modello che viene migrato come 'datetime' potrebbe effettivamente essere un' ActiveSupport :: TimeWithZone' e sottrarre due di questi al tempo trascorso in * secondi *. – evanrmurphy

24

È possibile convertirli in float con to_f, sebbene ciò comporterà la solita perdita di precisione associata ai galleggianti. Se stai eseguendo il casting su un numero intero per interi secondi, non dovrebbe essere abbastanza grande da costituire una preoccupazione.

I risultati sono in secondi:

>> end_time.to_f - start_time.to_f 
=> 7.39954495429993 

>> (end_time.to_f - start_time.to_f).to_i 
=> 7 

In caso contrario, si potrebbe guardare con to_formatted_s sull'oggetto DateTime e vedere se si può convincere l'output in qualcosa di classe Decimal accetterà, o semplicemente la formattazione come semplice ora Unix come stringa e chiamando lo to_i su quello.

+0

Grazie Luca, la conversione .to_f è grande! Funziona indipendentemente dalla classe Date: o è un DateTime o ActiveSupport :: TimeWithZone. – yaru

+0

NoMethodError: metodo non definito 'to_f' per # jameshfisher

45

O, più essere letti:

diff = datetime_1 - datetime_2 
diff * 1.days # => difference in seconds; requires Ruby on Rails 

nota, che cosa voi o altri ricercatori potrebbe davvero essere cercando è questo:

diff = datetime_1 - datetime_2 
Date.day_fraction_to_time(diff) # => [h, m, s, frac_s] 
+0

Questo non sembra funzionare con me per (created_at e updated_at). I miei due numeri sono '2016-08-07 20: 33: 54.863568' e' 2016-08-07 20: 33: 54.788684', ma la differenza è 6469.9776. Posgres dice che quei campi sono "timestamp senza fuso orario", se questo fa la differenza. – CHawk

+1

NoMethodError: metodo 'giorni 'non definito per 1: Fixnum –

+1

nota che .days è un metodo rails e non è disponibile in ruby ​​senza di esso. – sakurashinken

6

sto usando rubino 2.1.4 e per me il seguente lavorato

Time.now - Time.new(2014,11,05,17,30,0) 

mi ha dato la differenza di tempo in secondi

di riferimento: ruby doc

+1

L'OP si riferisce all'oggetto "DateTime" non all'oggetto "Time". –

5

Altri si affidano erroneamente a frazioni o funzioni di supporto. È molto più semplice di così. DateTime stesso è intero sotto. Ecco il modo di Ruby:

stop.to_i - start.to_i 

Esempio:

start = Time.now 
=> 2016-06-21 14:55:36 -0700 
stop = start + 5.seconds 
=> 2016-06-21 14:55:41 -0700 
stop.to_i - start.to_i 
=> 5 
0

perché non utilizzare il costruito nel "sec".Ecco un esempio:

t1 = Time.now.sec 

elapsed_t = Time.now.sec - t1 

puts "it took me : #{elapsed_t} seconds to do something that is useful \n" 
+0

Il metodo sec restituirà il componente secondi di ogni volta, esclusi minuti, ore ecc. Invece potrebbe usare ad es. to_i per lavorare con secondi totali dall'epoc. –

0

definire una funzione di Ruby come questo,

def time_diff(start_time, end_time) 
    seconds_diff = (start_time - end_time).to_i.abs 

    days = seconds_diff/86400 
    seconds_diff -= days * 86400 

    hours = seconds_diff/3600 
    seconds_diff -= hours * 3600 

    minutes = seconds_diff/60 
    seconds_diff -= minutes * 60 

    seconds = seconds_diff 

    "#{days} Days #{hours} Hrs #{minutes} Min #{seconds} Sec" 
end 

E Chiamare questa funzione,

time_diff(Time.now, Time.now-4.days-2.hours-1.minutes-53.seconds)