How can I start with a HH:MM:SS Ruby string like "00:00:08" and combine it with "-00:00:06" to get the difference, which would be "00:00:02" in this case?
Anything I try to look up involves converting to a DateTime, but do I really need to involve days or years to find out the relative difference?
To balance readability, testability and compactness I propose the following three methods. I don't think the complexity of the calculation justifies the creation of a class.
Convert strings to seconds
def str_to_seconds(str)
tot = str.match(/(\d{2,}):(\d{2}):(\d{2})(?!\d)/)
.captures
.zip([3600, 60, 1])
.sum { |s,d| s.to_i * d }
str[0] == '-' ? -tot : tot
end
Some examples:
puts " str str_to_seconds(str)"
puts "------------------------------------"
["00:00:07", "00:00:37", "00:02:07", "00:58:02", "02:00:07",
"06:01:02", "50:00:07", "130:00:07", "-130:00:07", "00:00:011"].each do |str|
print "%11s" % str
puts " %15d" % str_to_seconds(str)
end
str str_to_seconds(str)
------------------------------------
00:00:07 7
00:00:37 37
00:02:07 127
00:58:02 3482
02:00:07 7207
06:01:02 21662
50:00:07 180007
130:00:07 468007
-130:00:07 -468007
00:00:011
NoMethodError: undefined method `captures' for nil:NilClass
Convert seconds to strings
def seconds_to_str(secs)
abs_secs = secs.abs
hrs, abs_secs = abs_secs.divmod(3600)
mins, abs_secs = abs_secs.divmod(60)
str = "%02d:%02d:%02d" % [hrs, mins, abs_secs]
secs < 0 ? "-#{str}" : str
end
Some examples:
puts " secs seconds_to_str(secs)"
puts "-----------------------------------"
[7, 37, 127, 3482, -7207, 21662, 180007, 468007, -468007].each do |secs|
puts "%11d %14s" % [secs, seconds_to_str(secs)]
end
secs seconds_to_str(secs)
-----------------------------------
7 00:00:07
37 00:00:37
127 00:02:07
3482 00:58:02
-7207 -02:00:07
21662 06:01:02
180007 50:00:07
468007 130:00:07
-468007 -130:00:07
Compute desired result
def compute(str1, str2)
seconds_to_str(str_to_seconds(str1) + str_to_seconds(str2))
end
Some examples:
puts " str1 str2 compute(str1, sz)"
puts "------------------------------------------"
[[ "00:00:45", "00:00:17"], [" 00:00:45", "-00:00:17"],
["-00:00:45", "00:00:17"], ["-00:00:45", "-00:00:17"],
[" 16:12:05", "13:13:06"], [ "16:12:05", "-13:13:06"],
["-16:12:05", "13:13:06"], ["-16:12:05", "-13:13:06"],].each do |str1, str2|
puts "%10s %10s %10s" % [str1, str2, compute(str1, str2)]
end
str1 str2 compute(str1, sz)
------------------------------------------
00:00:45 00:00:17 00:01:02
00:00:45 -00:00:17 00:00:28
-00:00:45 00:00:17 -00:00:28
-00:00:45 -00:00:17 -00:01:02
16:12:05 13:13:06 29:25:11
16:12:05 -13:13:06 02:58:59
-16:12:05 13:13:06 -02:58:59
-16:12:05 -13:13:06 -29:25:11