Ruby strptime with greater than 24 hours - ruby-on-rails

I have a string of the following format:
"136:16:11.862504"
(hours:minutes:seconds:milliseconds)
Whenever I try to use Ruby's strptime to parse this string, it throws an ArgumentError: invalid strptime format - '%H:%M:%S'
I've actually searched quite extensively and cannot figure out an elegant way to parse this (besides the rather clunky solution of splitting the string by its colons and periods, and doing it all manually). Is there a way of doing this that I'm overlooking?
EDIT: I'm not looking to get a timestamp out of this, I'm looking to get a time duration.

What is your expected output? '136' is not a valid hour, and since you don't have a date portion, we can't simply turn those 'extra' hours into days. If you don't care about the date portion, this solution may work for you:
time = "136:16:11.862504"
hours, minutes, seconds = time.split(":").map(&:to_f)
hours %= 24
minutes %= 60
seconds %= 60
Time.new(0, 1, 1, hours, minutes, seconds, 0)
=> 0000-01-01 16:16:11 +0000

In case if nothing blocks you from using Regexp, you could use something based on this answer, for example:
/^(\d+):([0-5][0-9]):([0-5][0-9])\.\d+$/ =~ "136:16:11.862504"
puts "#{$1} : #{$2} : #{$3}"
136 : 16 : 11

Related

How may i convert minutes "00:15" into hours in Rails 4

I have send the value as "00:15" in database.But its in string.So I converted into time but i'm getting error while doing so.
I used
("00:15".to_time) / 1.hours
but its giving error as
"NoMethodError: undefined method `/' for 2017-02-16 00:15:00 +0530:Time"
So i need to convert minutes into hours and update it into database so i get value as 15mins = 0.25 hrs
According to Stefan's comment I would suggest the following method:
time = "02:15" #or whatever time you want
time.to_time.hour + time.to_time.min / 60.00 #results in 2.25
The hour methods returns the hour part of a given time object, the min methods returns only the minute part of a time object.
The right part of the addition in the second line converts the minute part into the decimal part of an hour.
You can't do division on a string, you need to convert it to an integer before doing the calculation. Dividing by a float automatically converts it to a float so you get the decimal places; if you divided by 60 you would get 0
("00:15".to_time.strftime('%M').to_i / 60.00)

Getting "argument out of range" when trying to turn a duration into milliseconds in Rails 4

I’m using Rails 4.2.4. I have the below method for converting a time (duration) to milliseconds …
Time.parse(convert_to_hrs(duration)).seconds_since_midnight * 1000
in which the method “convert_to_hrs” is defined as
def convert_to_hrs(string)
case string.count(':')
when 0
'00:00:' + string.rjust(2, '0')
when 1
'00:' + string
else
string
end
end
However, if the duration is something really big (e.g. “34:13:00” -- read: 34 hours, 13 minutes, and zero seconds), the above fails with the error
Error during processing: argument out of range
/Users/mikea/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/time.rb:302:in `local'
/Users/mikea/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/time.rb:302:in `make_time'
/Users/mikea/.rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/time.rb:366:in `parse'
/Users/mikea/Documents/workspace/myproject/app/services/my_service.rb:25:in `block in process_page_data'
/Users/mikea/Documents/workspace/myproject/app/services/my_service.rb:22:in `each'
/Users/mikea/Documents/workspace/myproject/app/services/my_service.rb:22:in `process_page_data'
How do I rewrite my first line to accurately convert duration into milliseconds?
If you know you're always going to be using a hours:minutes:seconds format, but the number in each field isn't guaranteed to be inside the 'normal' range (e.g. 0-23 for hours, 0-59 for minutes, etc), then you're probably best off doing it 'manually' using something like this:
def duration_in_milliseconds(input)
h, m, s = input.split(':').map(&:to_i)
(h.hours + m.minutes + s.seconds) * 1000
end
puts duration_in_milliseconds('34:13:00') #=> 123180000
Note that this only works with ActiveSupport, but you have that, since you've specified Rails. Also, this assumes you're always getting all three terms (e.g. 5 seconds is 00:00:05). The full setup that accepts shorter strings as well would want to also use your convert_to_hrs method.
Note also that this works even if formatting isn't strictly 'time-like', as long as you have consistent colons as seperators:
puts duration_in_milliseconds('1:1:5') #=> 3665000
The Numeric#hours, Numeric#minutes and Numeric#seconds methods are provided by ActiveSupport, as part of active_support/core-ext/time.rb. They aren't particularly documented, but they return ActiveSupport::Duration objects, which have fancy methods for interacting with Time and Date issues like 5.days.ago, but when treated as an integer are effectively a number of seconds.
Time.parse is throwing error, becuase values you passing in duration variable is out of range.
For Ex:
Time.parse(convert_to_hrs('59:59')) as per your written code, it's return 2016-07-27 00:59:59 +0530
Here the value 59:59 consider as minutes:seconds, so if you pass the value 60:60 then it will raise the error argument out of range
Here is the official documentation for parse method of Time
Hope this will help you.

Ruby on Rails - YouTube API - How to format duration ISO 8601 (PT45S)

I've searched high and low and can't seem to find a straight answer on this. Basically, I'm calling the YouTube API and getting a JSON document back, then parsing it. Everything else is good, but I don't understand how to parse the 'duration' property to display it as human readable.
The 'duration' field comes over as 'PT1H5M34S' - 1 hour 5 minutes 34 seconds
Or it could be 'PT24S' - 24 seconds
Or 'PT4M3S' - 4 minutes 3 seconds
There has to be a way in Ruby to parse this string and make it human readable so that I can just pass in the duration on the fly in my loop and convert it. Any help or guidance is greatly appreciated. I've tried using Date.parse, Time.parse, Date.strptime, along with many other things... Like just gsub-ing the PT out of the string and displaying it, but that doesn't seem right.
Try arnau's ISO8601 parser (https://github.com/arnau/ISO8601)
Usage:
d = ISO8601::Duration.new('PT1H5M34S')
d.to_seconds # => 3934.0
A simple approach to get the number of seconds for videos less than 24 hours:
dur = "PT34M5S"
pattern = "PT"
pattern += "%HH" if dur.include? "H"
pattern += "%MM" if dur.include? "M"
pattern += "%SS"
DateTime.strptime(dur, pattern).seconds_since_midnight.to_i
You can use Rails ActiveSupport::Duration
parsed_duration = ActiveSupport::Duration.parse(youtube_duration)
Time.at(parsed_duration).utc.strftime('%H:%M:%S')

How to evaluate a date difference in years, months and days (ruby)?

I have to make a simple difference between two dates:
Date.parse("2009-06-20") - Date.today
This gives me the difference of the dates in days.
Anyone know a way to easily convert that to the following format:
The event occurred X years, Y months and Z days ago
Thank you.
Found the answer here:
More precise distance_of_time_in_words
with this gem:
https://github.com/radar/dotiw
You may be looking for distance_of_times_in_words
There is a RubyGem which returns Time difference in a hash like {:year => 0, :month => 0,...}
The link is : https://rubygems.org/gems/time_diff
This is an example for difference in days, hours, seconds. Add the fields that you need.
def calculate_difference
minutes = (Date.parse("2009-06-20") - Date.today).to_i / 60
days = minutes / (24*60)
minutes -= days * 24*60
hours = minutes / 60
minutes -= hours * 60
"#{days}d#{hours}h#{minutes}m"
end
I find these generic date differences useful in many cases:
time_a = Time.zone.parse('2020-05-30')
time_b = Time.zone.parse('2010-01-18')
time_diff = {
years: time_a.year - time_b.year,
months: time_a.month - time_b.month,
days: time_a.day - time_b.day,
}
=> {:years=>10, :months=>4, :days=>12}
I don't know of any standard, correct way to do this. As odd as it may seem the standard Ruby library has a Date class but no DateSpan functionality. Rails has a solution but it feels somewhat of a pain for me to require this whole mammoth for such a trivial task.

How to get a DateTime duration?

I'm baffled how to do this.
I need to take a datetime object and get the duration in hours, days, whatever, to the current time.
Thank you.
Getting the duration in seconds is easy:
>> foo = Time.new
=> Mon Dec 29 18:23:51 +0100 2008
>> bar = Time.new
=> Mon Dec 29 18:23:56 +0100 2008
>> print bar - foo
5.104063=> nil
So, a little over five seconds.
But to present this in a somewhat more human-friendly form, you'll need a third-party addition, like time_period_to_s, or the Duration package.
distance_of_time_in_words will give you a string representation of the time between two time/date objects.
You want the Time class rather than DateTime.
If you are using rails, then distance_of_time_in_words_to_now may be what you are looking for.
i just want to share my code in order to get more readable duration time.
instead of using distance_of_time_in_words like #Ryan Bigg suggest, i like #Sören Kuklau suggestion more.
but to show human-friendly form, i make something like this.
def get_duration opts
from = Time.parse opts[:from]
to = Time.parse opts[:to]
duration = to - from
durationLabel = []
separator = " "
hours = (duration / 3600).floor
restDuration = duration%3600
durationLabel << "#{hours}h" if hours > 0
return durationLabel.join separator if restDuration.floor == 0
minutes = (restDuration / 60).floor
restDuration = duration%60
durationLabel << "#{minutes}m" if minutes > 0
return durationLabel.join separator if restDuration.floor == 0
seconds = restDuration.floor
durationLabel << "#{seconds}s" if seconds > 0
durationLabel.join separator
end
get_duration from: "2018-03-15 11:50:43", to: "2018-03-15 11:51:50"
# return 1m 7s
it will calculate the hours, minutes, and seconds.
instead of getting a vague response like about 1 minutes or hard response like 67.0, we will get something more human-friendly but accurate until second like 1m 7s

Resources