vishless
vishless

Reputation: 898

Get time in seconds from string and add to current time?

timestr = '15h 37m 5s'

I want to get the hours minutes and seconds from the above string and add it to current time.

  def next_run
    timestr = '15h 37m 5s'
    timearr = timestr.split(' ').map { |t| t.to_i }
    case timearr.count
    when 3
      next_ = (timearr[0] * 3600) + (timearr[1] * 60) + timearr[2]
    when 2
      next_ = (timearr[1] * 60) + timearr[2]
    when 1
      next_ = timearr[2]
    else
      raise 'Unknown length for timestr'
    end
    time_to_run_in_secs =  next_
  end

Now I get the total seconds. I want to make it into hours minutes and seconds, then add it to current time to get next run time. Is there any easy way to do this?

Upvotes: 0

Views: 262

Answers (5)

Cary Swoveland
Cary Swoveland

Reputation: 110685

The following method can be used to compute the the numbers of seconds from the string.

def seconds(str)
  3600 * str[/\d+h/].to_i + 60 * str[/\d+m/].to_i + str[/\d+s/].to_i
end

Note nil.to_i #=>0. A slight variant would be to write 3600 * (str[/\d+h/] || 0) +....

Then

Time.now + seconds(str)

Examples of possible values of str are as follows: ”3h 26m 41s”, ”3h 26m”, ”3h 41s”, ”41s 3h”, ”3h”,”41s” and ””.

One could instead write the operative line of the method as follows.

%w| s m h |.each_with_index.sum { |s,i| 60**i * str[/\d+#{s}/].to_i }

Though DRYer, I find that less readable.

Upvotes: 1

radoAngelov
radoAngelov

Reputation: 714

Firstly instead of spliting the string, you can use Time#parse method. Make sure you have required the library as well.

require 'time'
=> true
Time.parse('15h 37m 5s')
=> 2018-05-27 15:37:05 +0300

This returns a new object of class Time and it has some really useful methods for you - #sec, #min, #hour.

time = Time.parse('15h 37m 5s')
time.sec       #=> 5
time.min       #=> 37
time.hour      #=> 15

Adding adding one Time object to another is pretty straightforward since you can do it only by seconds. A simple solution for the current problem would be:

def next_run
  time = Time.parse('15h 37m 5s')
  seconds_to_add = time.hour * 3600 + time.min * 60 + time.sec
  Time.now + seconds_to_add
end

Hopefully this will answer your question! :)

Upvotes: 1

siegy22
siegy22

Reputation: 4413

If you don't need to parse the duration of time, and just want to define it in your code, use ActiveSupport::Duration for readability . (add the gem to your Gemfile, and read the guide on how to use it)

Then you can use it like this:

require 'active_support'
require 'active_support/core_ext/integer'    

DURATION = 15.hours + 37.minutes + 5.seconds
# use DURATION.seconds or DURATION.to_i to get the seconds

def next_run
  Time.now + DURATION
end

See the API documentation of ActiveSupport::Duration

If you need to define the next run by a user input, it's a good practice to use ISO 8601 to define a duration of time: https://en.wikipedia.org/wiki/ISO_8601#Durations

ISO 8601 durations are parseable:

ActiveSupport::Duration.parse('PT15H37M5S') # => 15 hours, 37 minutes, and 5 seconds (duration)

Upvotes: 1

A. KUMAR
A. KUMAR

Reputation: 480

you can convert your string into seconds from this method

def seconds(str)
  (3600 * str[/\d+(h|H)/].to_i) + (60 * str[/\d+(m|M)/].to_i) + (str[/\d+(s|S)/].to_i)
end

and then convert current time to seconds using method

next_run_time = Time.now.to_i + seconds(<Your Time String>)

now get next run time using

Time.at(next_run_time)

get desired format of time by using strftime method, in your case

Time.at(next_run_time).strftime("%Hh %Mm %Ss")

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

DateTime#+ accepts Rational instance as days to be added. All you need as you have seconds would be to convert it to a number of days and plain add to the current timestamp:

DateTime.now.tap do |dt|
  break [dt, dt + Rational(100, 3600 * 24) ]
end
#⇒ [
#    [0] #<DateTime: 2018-05-27T11:13:00+02:00 ((2458266j,33180s,662475814n),+7200s,2299161j)>,
#    [1] #<DateTime: 2018-05-27T11:14:40+02:00 ((2458266j,33280s,662475814n),+7200s,2299161j)>
# ]

Upvotes: 1

Related Questions