Ruby (with Rails) convert a string of time into seconds?
What you're asking Ruby to do with Time.parse is determine a time of day. That's not what you are wanting. All of the libraries I can think of are similar in this aspect: they are interested in absolute times, not lengths of time.
To convert your strings into time formats that we can work with, I recommend using Chronic (gem install chronic
). To convert to seconds, we can do everything relative to the current time, then subtract that time to get the absolute number of seconds, as desired.
def seconds_in(time)
now = Time.now
Chronic.parse("#{time} from now", :now => now) - now
end
seconds_in '48 hours' # => 172,800.0
seconds_in '15 minutes' # => 900.0
seconds_in 'a lifetime' # NoMethodError, not 42 ;)
A couple quick notes:
- The
from now
is is why Chronic is needed — it handles natural language input. - We're specifying
now
to be safe from a case where Time.now changes from the time that Chronic does it's magic and the time we subtract it from the result. It might not occur ever, but better safe than sorry here I think.
How to convert raw string of time in Rails?
module DurationParser
class ParseError < StandardError; end
# This is an example of how to extend it with aliases
ALAISES = {
hours: [:h, :hr],
minutes: [:m, :min],
seconds: [:s, :sec]
}
EXP = /^(?<value>[\d*|\.]*)\s*(?<token>\w*)?$/.freeze
# Parses a human readable string into a duration
# @example
# DurationParser.parse('2 hours, 1 minute')
# @return [ActiveSupport::Duration]
def self.parse(string)
string.split(/and|,/).map(&:strip).map do |pair|
matches = pair.match(EXP)
method = token_to_method(matches[:token])
raise ParseError unless method
(matches[:value].to_i).send(method)
end.reduce(&:+)
end
private
def self.token_to_method(token)
ActiveSupport::Duration::PARTS.find do |p|
p == token.downcase.pluralize.to_sym
end || ALAISES.find do |k,v|
v.include?(token.downcase.to_sym)
end&.first
end
end
And a passing spec:
require 'rails_helper'
RSpec.describe DurationParser do
describe '.parse' do
it "handles hours" do
expect(DurationParser.parse('1 h')).to eq 1.hour;
expect(DurationParser.parse('1 hr')).to eq 1.hour;
expect(DurationParser.parse('1 hour')).to eq 1.hour;
expect(DurationParser.parse('3 hours')).to eq 3.hours;
end
it "handles minutes" do
expect(DurationParser.parse('1 m')).to eq 1.minute;
expect(DurationParser.parse('1 min')).to eq 1.minute;
expect(DurationParser.parse('1 minute')).to eq 1.minute;
expect(DurationParser.parse('2 minutes')).to eq 2.minutes;
end
it "handles seconds" do
expect(DurationParser.parse('1 s')).to eq 1.second;
expect(DurationParser.parse('1 sec')).to eq 1.second;
expect(DurationParser.parse('1 second')).to eq 1.second;
expect(DurationParser.parse('15 seconds')).to eq 15.seconds;
end
it "handles comma delimeted strings" do
expect(DurationParser.parse('1 hour, 3 minutes, 15 seconds')).to eq(
1.hour + 3.minutes + 15.seconds
)
end
it "handles 'and' delimeted strings" do
expect(DurationParser.parse('1 hour and 3 minutes and 15 seconds')).to eq(
1.hour + 3.minutes + 15.seconds
)
end
it "handles mixed delimeter strings" do
expect(DurationParser.parse('1 hour and 3 minutes, 15 seconds')).to eq(
1.hour + 3.minutes + 15.seconds
)
end
it "raises when a bad token is passed" do
expect { DurationParser.parse('25 sols') }.to raise_error(DurationParser::ParseError)
end
end
end
Of course if you want something reliably machine readable you want to use ISO8601 durations and not a wonky string parser.
Ruby: Convert time to seconds?
You can use DateTime#parse
to turn a string into a DateTime
object, and then multiply the hour by 3600 and the minute by 60 to get the number of seconds:
require 'date'
# DateTime.parse throws ArgumentError if it can't parse the string
if dt = DateTime.parse("10:30") rescue false
seconds = dt.hour * 3600 + dt.min * 60 #=> 37800
end
As jleedev pointed out in the comments, you could also use Time#seconds_since_midnight
if you have ActiveSupport:
require 'active_support'
Time.parse("10:30").seconds_since_midnight #=> 37800.0
How to convert a time string to number of seconds in Ruby
To convert your string to a time use
new_time = Time.parse(time_string)
This will return a Time object. Then you can just subtract the time at midnight from your given time like so:
midnight = Time.local(2010,2,13,0,0,0)
seconds = (new_time - midnight).to_i # Number of seconds as an integer, .to_f works too
Of course, for Time.local, you should use today's date, not the hardcoded values as above.
Convert from format date string to unix (epoch) time value
To convert the string into an array of integers, look into split('/')
, to turn that into a unix time stamp look here (you probably want to_i
but be warned that it incorporates your local time zone).
Related Topics
How to "Nest" the Inclusion of Modules When Using the Ruby on Rails Activesupport::Concern Feature
Remove Element at Specific Index from Redis List
Carrierwave: Create 1 Uploader for Multiple Types of Files
Installing Pl/Ruby for Postgresql 8.3
How to Replace an Array's Element
"Ruby.Exe Is Not Recognized as an Internal or External Command" in Windows 7
Date Range Facets with Sunspot in Ruby on Rails
Running a Shell Command from Ruby: Capturing the Output While Displaying the Output
Ruby - Open File, Find and Replace Multiple Lines
How to Get Rufus-Scheduler Working with a Rails App Deployed to Heroku
Use Same Controller for Multiple Routes
Heroku and @Font-Face - Embedded Fonts Wont Display on Heroku
How to Increment an Integer in Ruby
Ruby/Rails Collection to Collection
Application.CSS Not Being Served as an Asset
Generate a 'Link_To' to the Controller Action 'Edit', Dynamically
Rbenv and Bundler: "Bad Interpreter: No Such File or Directory"