Converting hours, minutes and seconds to seconds in ruby - ruby-on-rails

I was wondering how to safely convert HH:MM:SS to seconds in ruby, given the input will only be in HH:MM:SS (or H:M:S), without days.
Days would have to be in hours already - "168:00:00" instead of "7 days, 00:00:00".

'12:34:56'.split(':').map(&:to_i).inject(0) { |a, b| a * 60 + b }
=> 45296

h, m, s = "168:00:00".split(":").map(&:to_i)
h %= 24
(((h * 60) + m) * 60) + s

The solution is quite simple:
secs = 0
=> 0
"12:34:56".split(":").reverse.each_with_index do |x,y|
"#{secs} += (#{x.to_i})*(#{60**y})"
secs += (x.to_i)*(60**y)
end
=> ["56", "34", "12"]
secs
=> 45296
No use of Time or DateTime and no timezone problems!
Cheers!

Related

Need to convert to integer and then sum of the Plucked data ruby 2.6

I need SUM of the plucked timings.
I did
#dailystatus_infos.task_times.pluck(:total_min)
I got following
["00:00:00", "1:52:00", "00:00:00", "00:02:28", "1:54:00"]
output. [Hour:Minute:Second] format
Now I need to convert those Minutes to integer and sum of it.
I need SUM of the plucked timings
I'd start by writing a helper method to convert the hh:mm:ss string to seconds. A regular expression would work:
def to_seconds(string)
string.match(/(?<hours>\d+):(?<minutes>\d+):(?<seconds>\d+)/) do |m|
m[:hours].to_i * 3600 + m[:minutes].to_i * 60 + m[:seconds].to_i
end
end
to_seconds('00:00:12') #=> 12
to_seconds('00:01:00') #=> 60
to_seconds('00:01:12') #=> 72
Now you can sum the seconds via:
total_mins = ["00:00:00", "1:52:00", "00:00:00", "00:02:28", "1:54:00"]
total_mins.sum { |str| to_seconds(str) }
#=> 13708
And, if necessary, convert that back to h:mm:ss via divmod:
seconds = 13708
hours, seconds = seconds.divmod(3600)
minutes, seconds = seconds.divmod(60)
format('%d:%02d:%02d', hours, minutes, seconds)
#=> "3:48:28"
We first determine the total seconds:
arr = ["00:00:00", "1:52:00", "00:00:00", "00:02:28", "1:54:00"]
s = arr.sum do |str|
str.split(':').reduce(0) { |t, s| t * 60 + s.to_i }
end
#=> 13708
and then manipulate s as desired. The number of minutes, for example, equals
s.fdiv(60)
#=> 228.46666666666667
which might be rounded or truncated.
Something like this
total_minutes = #dailystatus_infos.task_times.pluck(:total_min)
total_minutes.map { |t| (::Time.parse(t).seconds_since_midnight / 60).to_i }.sum
arr = ["00:00:00", "1:52:00", "00:00:00", "00:02:28", "1:54:00"]
arr.map { |t| ::Time.parse(t).seconds_since_midnight / 60 }.sum.to_i
=> 228
You get the minute by splitting on :. Then map and sum.
ary = ["00:00:00", "1:52:00", "00:00:00", "00:02:28", "1:54:00"]
ary.map{ |s| s.split(':')[1].to_i }.sum #=> 108 (0 + 52 + 0 + 2 + 54)

Ruby on rails get hours, minutes, seconds from two dates and times

I need the number of hours, minutes, seconds between two dates and times.I'm able to get the number of days, hours, minutes, seconds but I don't want no.of days instead of it, I need hours, minutes, seconds only enough.
Here my code,
start_time is Wed, 13 Dec 2017 20:35:19 -0800 and end_time is today datetime
def time_diff(end_time, start_time)
diff = end_time - start_time
mm, ss = diff.divmod(60)
hh, mm = mm.divmod(60)
dd, hh = hh.divmod(24)
time = "%d h, %d m, %d s" % [hh, mm, ss]
return time
end
I need output like this "35 h, 29 m, 12 s"
Thanks for your help.
Just out of curiosity, a pure [almost] functional solution, without intermediate local variables:
start_time = DateTime.parse 'Wed, 13 Dec 2017 23:00:00 UTC'
end_time = DateTime.parse 'Wed, 15 Dec 2017 23:30:20 UTC'
sec, min, hrs = [60, 60, 1].
map.
with_object([[[end_time, start_time].
map(&:to_time).
map(&:to_i).
reduce(:-), nil]]) do |div, obj|
obj << obj.last.first.divmod(div)
obj[-2].rotate!
end.
map(&:first).
compact
#⇒ [20, 30, 48]
You've already got the answer - just don't divide by 24!
If the start_time and end_time are DateTime value you can use the following
difference = end_time - start_time
hours = (difference * 24).to_i
minutes = (difference * 24 * 60).to_i
seconds = (difference * 24 * 60 * 60).to_i

Ruby Program time conversion

The task is to Write a method that will take in a number of minutes, and returns a string that formats the number into hours:minutes.
here's what I have so far:
def time_conversion(minutes)
minutes = (minutes / 60) % 60
hours = minutes / (60 * 60)
format(" %02d:%02d ", hours, minutes)
return format
end
it's not working out for me
Try this
def time_conversion(time)
minutes = time % 60
hours = time / 60
minutes = (minutes < 10)? "0" + minutes.to_s : minutes.to_s
return hours.to_s + ":" + minutes
end
Using division in Ruby returns a whole number, lowered to the previous number. Using modulus returns the remainder after division.
Ruby's Numeric#divmod is exactly what you want here. It returns both the quotient and remainder of a division operation, so e.g. 66.divmod(60) returns [ 1, 6 ]. Combined with sprintf (or String#%, it makes for an extremely simple solution:
def time_conversion(minutes)
"%02d:%02d" % minutes.divmod(60)
end
puts time_conversion(192)
# => 03:12
Well try
h = minutes/60
M = minutes%60

Ruby average value of array of time values (fixnums)

Looking to get the average duration, where duration is in the form of 1.day, 3.months, 2.weeks format..
# provided array
a = [1.day, 3.days, 1.week, 4.days]
# desired output
a.average = "3 days"
Any way I have tried results in a number of seconds being the output.. for instance:
a.inject(:+) = "15 days"
a.inject(:+) / a.size = 324000
I've looked at the Linguistics gem, but it only outputs the value as a number (three hundred and twenty four thousand)
def average_days(a)
seconds = a.inject(:+) / a.size
minutes = seconds / 60
days = (minutes / 1440).round
"#{days} days"
end
> a = [1.day, 3.days, 1.week, 4.days]
> (a.inject(0.0) {|sum, n| sum + n} / a.size) / (60 * 60 * 24)
=> 3.75
If you insist. Round and/or truncate however you want.
((a.inject(0.0) {|sum, n| sum + n} / a.size) / (60 * 60 * 24)).days

Ruby/Rails - How to convert seconds to time?

I need to perform the following conversion:
0 -> 12.00AM
1800 -> 12.30AM
3600 -> 01.00AM
...
82800 -> 11.00PM
84600 -> 11.30PM
I came up with this:
(0..84600).step(1800){|n| puts "#{n.to_s} #{Time.at(n).strftime("%I:%M%p")}"}
which gives me the wrong time, because Time.at(n) expects n to be number of seconds from epoch:
0 -> 07:00PM
1800 -> 07:30PM
3600 -> 08:00PM
...
82800 -> 06:00PM
84600 -> 06:30PM
What would be the most optimal, time zone independent solution for this transformation?
The simplest one-liner simply ignores the date:
Time.at(82800).utc.strftime("%I:%M%p")
#-> "11:00PM"
Not sure if this is better than
(Time.local(1,1,1) + 82800).strftime("%I:%M%p")
def hour_minutes(seconds)
Time.at(seconds).utc.strftime("%I:%M%p")
end
irb(main):022:0> [0, 1800, 3600, 82800, 84600].each { |s| puts "#{s} -> #{hour_minutes(s)}"}
0 -> 12:00AM
1800 -> 12:30AM
3600 -> 01:00AM
82800 -> 11:00PM
84600 -> 11:30PM
Stephan
Two offers:
The elaborate DIY solution:
def toClock(secs)
h = secs / 3600; # hours
m = secs % 3600 / 60; # minutes
if h < 12 # before noon
ampm = "AM"
if h = 0
h = 12
end
else # (after) noon
ampm = "PM"
if h > 12
h -= 12
end
end
ampm = h <= 12 ? "AM" : "PM";
return "#{h}:#{m}#{ampm}"
end
the Time solution:
def toClock(secs)
t = Time.gm(2000,1,1) + secs # date doesn't matter but has to be valid
return "#{t.strftime("%I:%M%p")} # copy of your desired format
end
HTH
In other solutions, the hour-counter would be reset to 00 when crossing 24-hour day boundaries. Also beware that Time.at rounds down, so it will give the wrong result if the input has any fractional seconds (f.ex. when t=479.9 then Time.at(t).utc.strftime("%H:%M:%S") will give 00:07:59 and not 00:08:00` which is the correct one).
If you want a way to convert any number of seconds (even high counts larger than 24-hour day spans) into an ever increasing HH:MM:SS counter, and handle potential fractional seconds, then try this:
# Will take as input a time in seconds (which is typically a result after subtracting two Time objects),
# and return the result in HH:MM:SS, even if it exceeds a 24 hour period.
def formatted_duration(total_seconds)
total_seconds = total_seconds.round # to avoid fractional seconds potentially compounding and messing up seconds, minutes and hours
hours = total_seconds / (60*60)
minutes = (total_seconds / 60) % 60 # the modulo operator (%) gives the remainder when leftside is divided by rightside. Ex: 121 % 60 = 1
seconds = total_seconds % 60
[hours, minutes, seconds].map do |t|
# Right justify and pad with 0 until length is 2.
# So if the duration of any of the time components is 0, then it will display as 00
t.round.to_s.rjust(2,'0')
end.join(':')
end
Modified from #springerigor's and suggestion in the discussion at https://gist.github.com/shunchu/3175001

Resources