Calculate time elapsed from log timestamps using Ruby - ruby

I am parsing a log and would like an elegant way of calculating the difference between these time stamps shown below:
[Mar 2, 2010 1:54:40 AM]
[Mar 4, 2010 10:54:40 PM]
I've looked at DateTime however I wasnt sure if it was ncessary to seperate the Date from the actual time part and create a Time object. If there is an easier way please fire away.
Regards.
Snappy

Using only DateTime class:
require 'date'
d1, d2 = 'Mar 2, 2010 1:54:40 AM', 'Mar 4, 2010 10:54:40 PM'
diff = DateTime.parse(d2) - DateTime.parse(d1)
hours,minutes,seconds,frac = Date.send(:day_fraction_to_time, diff)
# => [69, 0, 0, 01]

Use chronic gem to parse the two times to obtain two time objects then substract

Related

Ruby Date Time Subtraction

I am trying to calculate the exact duration a process took from some log file result. After parsing the log, I reached at the following stage:
my_array = ["Some_xyz_process", "Start", "2018-07-12", "12:59:53,397", "End", "2018-07-12", "12:59:55,913"]
How can I subtract the start date and time from the end date and time in order to retrieve the exact duration the process took?
my_array = ["Some_xyz_process",
"Start", "2018-07-12", "12:59:53,397",
"End", "2018-07-12", "12:59:55,913"]
require 'date'
fmt = '%Y-%m-%d%H:%M:%S,%L'
is = my_array.index('Start')
#=> 1
ie = my_array.index('End')
#=> 4
DateTime.strptime(my_array[ie+1] + my_array[ie+2], fmt).to_time -
DateTime.strptime(my_array[is+1] + my_array[is+2], fmt).to_time
#=> 2.516 (seconds)
See DateTime#strptime and DateTime# (the latter for format directives). As long as the date and time formats are known I always prefer strptime to parse. Here's an example of why:
DateTime.parse 'Theresa May has had a bad week over Brexit'
#=> #<DateTime: 2018-05-01T00:00:00+00:00 ((2458240j,0s,0n),+0s,2299161j)>`.
You can concat the date and time field and use Time.parse to convert it to a time object and then calculate the difference in number of seconds
Time.parse('2018-07-12 12:59:55,397').to_i - Time.parse('2018-07-12 12:59:53,913').to_i
Hope this helps

How to compare two Time objects only down to the hour

I want to compare two Time objects only down to the hour, while ignoring the difference of minutes and seconds.
I'm currently using t0.strftime("%Y%m%d%H") == t1.strftime("%Y%m%d%H"), but I don't think this is a good solution.
Is there better way to do this?
You can use this trick in pure Ruby
t0.to_a[2..9] == t1.to_a[2..9]
Where Time#to_a
$> Time.now.to_a
# => [7, 44, 2, 8, 3, 2014, 6, 67, false, "GMT"]
# [ sec, min, hour, day, month, year, wday, yday, isdst, zone ]
So you can check that the times are equals or not up to the level you want and without missing important components of the object like the zone, etc.
If you have ActiveSupport (either through Rails, or just installed as a gem), it includes an extension to the Time class that adds a change method which will truncate times:
$> require "active_support/core_ext/time"
# => true
$> t = Time.now
# => 2014-03-07 21:30:01 -0500
$> t.change(hour: 0)
# => 2014-03-07 00:00:00 -0500
This won't modify the original time value either. So you can do this:
t0.change(minute: 0) == t1.change(minute: 0)
It'll zero out everything at a lower granularity (seconds, etc.).
require 'time'
t1 = Time.new ; sleep 30 ; t2 = Time.new
t1.hour == t2.hour
This should give you a boolean answer.

Ruby on Rails 3: Why is the conversion from Date to seconds different from Time to seconds

In Ruby I am trying to convert a Date into a format that is usable by the HighCharts JavaScript charting library. Odd thing is when I convert the Date to seconds it converts differently than when I convert a Time to seconds and differently when I convert a DateTime to seconds. Due to this difference in conversion the dates displayed on the Graph can be as much as 1 date behind.
I am sure this has something to do with Rails and how it handles conversion from UTC to Local. If someone could explain to me the details I would greatly appreciate it.
In my examples below I use the same date '2011/05/02' but the seconds come out to be different.
Examples:
Date.new(2011, 5, 2).to_time.to_i * 1000
=> 1304265600000
=> 05/01/2011
Time.utc(2011, 5, 2).to_i * 1000
=> 1304294400000
=> 05/02/2011
Date.new(2011, 5, 2).to_datetime.to_i * 1000
=> 1304294400000
=> 05/02/2011
ruby-1.9.2-p180 :106 > Time.utc(2011, 5, 2)
=> 2011-05-02 00:00:00 UTC
ruby-1.9.2-p180 :107 > Date.new(2011, 5, 2).to_time
=> 2011-05-02 00:00:00 +0300
Date.to_time generates Time with timezone. That's your difference.
The quick fix/hack that popped instantly into my mind is:
Date.new(2011, 5, 2).to_time.utc.midnight
Edit:
http://apidock.com/rails/Date/to_time
Date.new(2011, 5, 2).to_time(:utc)

Business date/holiday handling

I've posted this question for C# but I may be working in Ruby instead. So I'm asking the same question about Ruby:
I'm looking for a Ruby class/library/module that works similarly to the Perl module Date::Manip as far as business/holiday dates. Using that module in Perl, I can pass it a date and find out whether it's a business day (ie, Mon-Fri) or a holiday. Holidays are very simple to define in a config file (see Date::Manip::Holidays). You can enter a 'fixed' date that applies to every year like:
12/25 = Christmas
or 'dynamic' dates for every year like:
last Monday in May = Memorial Day
or 'fixed' dates for a given year like:
5/22/2010 = Bob's Wedding
You can also pass in a date and get back the next/previous business day (which is any day that's not a weekend and not a holiday).
Does anyone know of anything like that in the Ruby world?
You may use the holidays-gem.
http://rubygems.org/gems/holidays
Some national (and regional) holidays are already predefined, you may define your own holiday definitions.
The business_time gem should do what you need.
The example at bottom of the README doc is a good starting example:
require 'rubygems'
require 'active_support'
require 'business_time'
# We can adjust the start and end time of our business hours
BusinessTime::Config.beginning_of_workday = "8:30 am"
BusinessTime::Config.end_of_workday = "5:30 pm"
# and we can add holidays that don't count as business days
# July 5 in 2010 is a monday that the U.S. takes off because
# our independence day falls on that Sunday.
three_day_weekend = Date.parse("July 5th, 2010")
BusinessTime::Config.holidays << three_day_weekend
friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
tuesday_morning = 1.business_hour.after(friday_afternoon)
You probably going to need the chronic gem to help you build the holiday dates from your config file. However YMMV because your example last monday in may doesn't work in chronic. Hackaround is do something like this:
# last monday in May (2010)
Chronic.parse('last monday', :now => Time.parse('2010-06-01'))
And look at the tickle gem which works on top of chronic for a way to add recurring events.
/I3az/
You could take a look at my Workpattern gem. It allows you to specify working and resting times. It was aimed at producing a "Calendar" like is used in planning tools such as Microsoft Project and Primavera P6, so you can specify right down to the minute.
Here is a simple example:
Create a new Workpattern mywp=Workpattern.new('My Workpattern',2011,10) This is for 10 years from 2011 but you can make it longer or shorter.
Tell it you want the Weekends to be resting and that you also want to rest during the week so you work between 9 and 12 in the morning and 1 and 6 in the afternoon.
mywp.resting(:days => :weekend)
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(0,0),:to_time=>Workpattern.clock(8,59))
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(12,0),:to_time=>Workpattern.clock(12,59))
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(18,0),:to_time=>Workpattern.clock(23,59))
Now just calculate using minutes
mydate=DateTime.civil(2011,9,1,9,0)
result_date = mywp.calc(mydate,1920) # => 6/9/11#18:00
1920 is 4 days * 8 hours a day * 60 minutes and hour.
I wrote the gem to learn Ruby - only scratched the surface.
Check out the biz gem.
Here's an example configuration:
require 'biz'
Biz.configure do |config|
config.hours = {
mon: {'09:00' => '17:00'},
tue: {'00:00' => '24:00'},
wed: {'09:00' => '17:00'},
thu: {'09:00' => '12:00', '13:00' => '17:00'},
sat: {'10:00' => '14:00'}
}
config.holidays = [Date.new(2014, 1, 1), Date.new(2014, 12, 25)]
config.time_zone = 'America/Los_Angeles'
end
When you use the optional core extensions, it's as easy as the following to find out if a date is a business day:
require 'biz/core_ext'
Date.new(2014, 12, 25).business_day? # => false

Parsing date from text using Ruby

I'm trying to figure out how to extract dates from unstructured text using Ruby.
For example, I'd like to parse the date out of this string "Applications started after 12:00 A.M. Midnight (EST) February 1, 2010 will not be considered."
Any suggestions?
Try Chronic (http://chronic.rubyforge.org/) it might be able to parse that otherwise you're going to have to use Date.strptime.
Assuming you just want dates and not datetimes:
require 'date'
string = "Applications started after 12:00 A.M. Midnight (EST) February 1, 2010 will not be considered."
r = /(January|February|March|April|May|June|July|August|September|October|November|December) (\d+{1,2}), (\d{4})/
if string[r]
date =Date.parse(string[r])
puts date
end
Also you can try a gem that can help find date in string.
Exapmle:
input = 'circa 1960 and full date 07 Jun 1941'
dates_from_string = DatesFromString.new
dates_from_string.get_structure(input)
#=> return
# [{:type=>:year, :value=>"1960", :distance=>4, :key_words=>[]},
# {:type=>:day, :value=>"07", :distance=>1, :key_words=>[]},
# {:type=>:month, :value=>"06", :distance=>1, :key_words=>[]},
# {:type=>:year, :value=>"1941", :distance=>0, :key_words=>[]}]

Resources