84

I've got code that does time tracking for employees. It creates a counter to show the employee how long they have been clocked in for.

This is the current code:

  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

This works fine. But because Time is limited to the range of 1970 - 2038 we are trying to replace all Time uses with DateTimes. I can't figure out how to get the number of seconds between two DateTimes. Subtracting them yields a Rational which I don't know how to interpret, whereas subtracting Times yields the difference in seconds.

NOTE: Since Ruby 1.9.2, the hard limit of Time is removed. However, Time is optimized for values between 1823-11-12 and 2116-02-20.

Community
  • 1
  • 1
Tilendor
  • 48,165
  • 17
  • 52
  • 58

7 Answers7

97

Subtracting two DateTimes returns the elapsed time in days, so you could just do:

elapsed_seconds = ((end_time - start_time) * 24 * 60 * 60).to_i
David Ma
  • 1,342
  • 9
  • 6
  • Ah, I knew it returned it in days, I didn't know that this would include fractions of a day as well. Thanks. – Tilendor Feb 20 '09 at 00:00
  • 4
    This doesn't work correctly in case of a Leap second (https://en.wikipedia.org/wiki/Leap_second). – Rok Kralj Mar 17 '13 at 20:35
  • 47
    Just a note to anyone else who may be confused by this. Yes, subtracting two `DateTime`s returns elapsed time in days. However, in Rails a model attribute that you migrate as `datetime` may actually be an `ActiveSupport::TimeWithZone`, and subtracting two of those returns elapsed time in *seconds*. – evanrmurphy Oct 07 '13 at 21:49
  • 4
    I'm using this and getting a fraction, the datetimes are 2 seconds apart, 15 and 13, but I'm getting 1.939s instead of 2s and .to_i is truncating to 1 second. – ckarbass Oct 29 '13 at 05:14
52

Or, more readably:

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

Note, what you or some other searchers might really be looking for is this:

diff = datetime_1 - datetime_2
Date.day_fraction_to_time(diff) # => [h, m, s, frac_s]
jameshfisher
  • 34,029
  • 31
  • 121
  • 167
Avram Dorfman
  • 537
  • 4
  • 2
34

You can convert them to floats with to_f, though this will incur the usual loss of precision associated with floats. If you're just casting to an integer for whole seconds it shouldn't be big enough to be a worry.

The results are in seconds:

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

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

Otherwise, you could look at using to_formatted_s on the DateTime object and seeing if you can coax the output into something the Decimal class will accept, or just formatting it as plain Unix time as a string and calling to_i on that.

Luke
  • 4,381
  • 1
  • 21
  • 15
24

Others incorrectly rely on fractions or helper functions. It's much simpler than that. DateTime itself is integer underneath. Here's the Ruby way:

stop.to_i - start.to_i

Example:

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
Amin Ariana
  • 4,635
  • 2
  • 35
  • 21
8

I am using ruby-2.1.4 and for me the following worked

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

gave me the time difference in seconds

reference: ruby doc

Som Poddar
  • 1,428
  • 1
  • 15
  • 22
2

there's a method made for that:

Time.now.minus_with_coercion(10.seconds.ago)

equals 10.

Source: http://apidock.com/rails/Time/minus_with_coercion

Hope I helped.

Francois
  • 1,367
  • 1
  • 15
  • 23
1

Define a Ruby function like this,

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

And Call this function,

time_diff(Time.now, Time.now-4.days-2.hours-1.minutes-53.seconds)
ramya
  • 275
  • 1
  • 5
  • 13