Search code examples
rubytimedatetime-conversion

Calculating the difference between durations with milliseconds in Ruby


TL;DR: I need to get the difference between HH:MM:SS.ms and HH:MM:SS.ms as HH:MM:SS:ms


What I need:

Here's a tricky one. I'm trying to calculate the difference between two timestamps such as the following:

In: 00:00:10.520
Out: 00:00:23.720

Should deliver:

Diff: 00:00:13.200

I thought I'd parse the times into actual Time objects and use the difference there. This works great in the previous case, and returns 00:0:13.200.

What doesn't work:

However, for some, this doesn't work right, as Ruby uses usec instead of msec:

In: 00:2:22.760
Out: 00:2:31.520
Diff: 00:0:8.999760

Obviously, the difference should be 00:00:8:760 and not 00:00:8.999760. I'm really tempted to just tdiff.usec.to_s.gsub('999','') ……


My code so far:

Here's my code so far (these are parsed from the input strings like "0:00:10:520").

tin_first, tin_second = ins.split(".")
tin_hours, tin_minutes, tin_seconds = tin_first.split(":")
tin_usec = tin_second * 1000
tin = Time.gm(0, 1, 1, tin_hours, tin_minutes, tin_seconds, tin_usec)

The same happens for tout. Then:

tdiff = Time.at(tout-tin)

For the output, I use:

"00:#{tdiff.min}:#{tdiff.sec}.#{tdiff.usec}"

Is there any faster way to do this? Remember, I just want to have the difference between two times. What am I missing?

I'm using Ruby 1.9.3p6 at the moment.


Solution

  • Using Time:

    require 'time' # Needed for Time.parse
    
    def time_diff(time1_str, time2_str)
      t = Time.at( Time.parse(time2_str) - Time.parse(time1_str) )
      (t - t.gmt_offset).strftime("%H:%M:%S.%L")
    end
    
    out_time = "00:00:24.240"
    in_time  = "00:00:14.520"
    
    p time_diff(in_time, out_time)
    #=> "00:00:09.720"
    

    Here's a solution that doesn't rely on Time:

    def slhck_diff( t1, t2 )
      ms_to_time( time_as_ms(t2) - time_as_ms(t1) )
    end
    
    # Converts "00:2:22.760" to 142760
    def time_as_ms( time_str )
      re = /(\d+):(\d+):(\d+)(?:\.(\d+))?/
      parts = time_str.match(re).to_a.map(&:to_i)
      parts[4]+(parts[3]+(parts[2]+parts[1]*60)*60)*1000
    end
    
    # Converts 142760 to "00:02:22.760"
    def ms_to_time(ms)
      m = ms.floor / 60000
      "%02i:%02i:%06.3f" % [ m/60, m%60, ms/1000.0 % 60 ]
    end
    
    t1 = "00:00:10.520"
    t2 = "01:00:23.720"
    p slhck_diff(t1,t2)
    #=> "01:00:13.200"
    
    t1 = "00:2:22.760"
    t2 = "00:2:31.520"
    p slhck_diff(t1,t2)
    #=> "00:00:08.760"