What am I doing wrong with DateTime.strptime? - ruby

My ruby program says that my date is invalid when I do that:
format = "%D/%M/%Y %H:%M:%S:3N"
date = "21/03/2011 16:39:11.642"
DateTime.strptime(time, format)
I have also tried this one:
format = "%D/%M/%Y %H:%M:%S:3"
All I get is this:
ArgumentError: invalid date
from /usr/local/lib/ruby/1.9.1/date.rb:1688:in `new_by_frags'
from /usr/local/lib/ruby/1.9.1/date.rb:1713:in `strptime'
from (irb):12
from /usr/local/bin/irb:12:in `<main>'

It looks like you were getting strptime's format directives confused. Notice how %M is in format twice, once representing the month and the next time representing the minute?
%D means the date as %m / %d / %y.
%d means the day of the month [01,31]
%M means the minute [00,59]
%m means the month number [01,12]
This should work:
format = "%d/%m/%Y %H:%M:%S"
date_time = "21/03/2011 16:39:11.642"
puts DateTime.strptime(date_time, format) #=> 2011-03-21T16:39:11+00:00
Here's a strptime reference

Try to use
datetime.to_date.strftime(format)
or
datetime.to_time

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

Matching Date formatted: "January 17, 2017 10:30 AM" in Ruby

I have been trying to use Date/DateTime to validate that a given date is in the correct format.
str = "January 17, 2017 10:30 AM"
temp = DateTime.strptime(str, '%B %-d, %y %l:%M %p')
but am getting the error
`strptime': invalid date (ArgumentError)
I have been able to split the string into ""January 17," "2017 10:30 AM" and validate it without issue, but I would really like to know why I can't just use strptime on the whole string, or what I am doing wrong if it can be done.
This error is happening because according to the docs of DateTime#strptime:
Parses the given representation of date and time with the given template, and creates a date object. strptime does not support specification of flags and width unlike strftime.
And your format includes a value of %-d which is a width parameter, hence the exception. If you try a basic invocation like:
DateTime.strptime(str, '%B %d, %Y')
you'll see it works. Also, you'll want uppercase-Y for the full 4-digit year.
In a nutshell: you'll need to adjust your format string
This format works fine :
temp = DateTime.strptime(str, '%B %d, %Y %l:%M %p')
#<DateTime: 2017-01-17T10:30:00+00:00 ((2457771j,37800s,0n),+0s,2299161j)>

Error using strptime, strftime while converting date to epoch

I am trying to extract dates from csv file and convert them to epoch time
CSV.foreach(File.path("month.csv")) do |row|
dateper=row[0].split(',')[0]
p DateTime.strptime(dateper,"%m/%d/%y %I:%M:%S %p %z").strftime("%s")
end
I am getting invalid date (ArgumentError) as the result. However, if I print out dateper, choose one of the outputs randomly and cop-paste it in place of dateper in line 3, I get an epoch value. What am I doing wrong? dateper is of string value, and strptime minus strftime seems to give an output.
month.csv sample:
7/26/13 12:00:00 AM -05:00,62.2,63.02,62.07,63.02,5.00168E+07
8/23/13 12:00:00 AM -05:00,71.84,71.93,71.36,71.6,5.55304E+07
8/26/13 12:00:00 AM -05:00,71.56,72.91,71.52,71.87,8.26536E+07
8/27/13 12:00:00 AM -05:00,71.16,71.81,69.49,69.82,1.058488E+08
Could someone help me with this?
You have some malformed dates somewhere. Use rescue to avoid the script choking on them.
CSV.foreach(File.path("month.csv")) do |row|
dateper=row[0].split(',')[0]
p DateTime.strptime(dateper,"%m/%d/%y %I:%M:%S %p %z").strftime("%s") rescue p "malformed date:#{dateper} on line #{$.}"
end
This will allow the script to continue and show you the bad dates.

In Ruby, is there a way (a gem, perhaps) to process time in "XX:XX" format?

In particular, to add time (e.g. 11:40 + 00:30 = 12:10) and check whether a time belongs to a range (e.g. (11:00..12:00).include?(11:30)).
I understand that I can write a class, but maybe a solution already exists.
The built-in Time class is not entirely what I want, because I am not interested in date-related features, which are built-in.
You can use strftime to format the time any way you want. If you want only the hour and minutes you can use this:
Time.now.strftime("%H:%M")
=> "08:57"
time.strftime gives you all of these options to format
%a - The abbreviated weekday name (“Sun”)
%A - The full weekday name (“Sunday”)
%b - The abbreviated month name (“Jan”)
%B - The full month name (“January”)
%c - The preferred local date and time representation
%d - Day of the month (01..31)
%H - Hour of the day, 24-hour clock (00..23)
%I - Hour of the day, 12-hour clock (01..12)
%j - Day of the year (001..366)
%m - Month of the year (01..12)
%M - Minute of the hour (00..59)
%p - Meridian indicator (“AM” or “PM”)
%S - Second of the minute (00..60)
%U - Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)
%W - Week number of the current year, starting with the first Monday as the firstday of the first week (00..53)
%w - Day of the week (Sunday is 0, 0..6)
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%y - Year without a century (00..99)
%Y - Year with century
%Z - Time zone name
%% - Literal “%” character
Here is a link to the
strftime docs
To check if time belongs to a certain range you can use the cover
method
2.1.5 :003 > (Time.now..Time.now+10).cover?(Time.now)
=> true
2.1.5 :004 > (Time.now..Time.now+10).cover?(Time.now+20)
=> false
ActiveSupport's Numeric will help you.
You can do:
require 'date'
require 'active_support/all'
DateTime.parse("11:40") + 30.minutes
You will need the ActiveSupport gem in your Gemfile.
As for checking if a time is in a range you can use #cover:
irb(main):001:0> (DateTime.parse("11:40")..DateTime.parse("11:50")).cover?(DateTime.parse("11:45"))
=> true
irb(main):002:0> (DateTime.parse("11:40")..DateTime.parse("11:50")).cover?(DateTime.parse("12:00"))
=> false

Validating a Date - m/d/yyyy Doesn't Match mm/dd/yyyy?

I have a ruby script that checks a provided date, to make sure it is today's date. This is not working when the date provided doesn't have a 2 digit padding for the month. Is there anyway to get ruby to see that as equal? The example is that it says "Date Processed 3/13/2014 is not today's date 03/13/2014!" the difference is in the month - 3 vs 03. Below is the code. ev_val is provided from a csv and it is m/d/yyyy format. It is not provided with a 0 padding, though. Any thoughts?
Thanks!
tnow = Time.now
if ev_val != tnow.strftime("%m/%d/%Y")
log_linemsg = "Date Processed #{ev_val} is not today's date #{tnow.strftime("%m/%d/%Y")}! Processing date must be today's Date!!!\nSTOPPING SCRIPT!!!"
log_line = ["#{$cname}","#{log_linemsg}","","",]
puts log_linemsg
insert_logitems(connection, table_namelog, log_line)
exit
end
require "date"
date_val = Date.parse ev_val
today = Date.today
if today != date_val
log_linemsg = "Date Processed #{ev_val} is not today's date #{today}! Processing date must be today's Date!!!\nSTOPPING SCRIPT!!!"
end
Since you only care about the date portion, I would use Date instead of Time.
Take your input string and parse it into a Date object, then compare it to today's date.
?> date_val = Date.parse('3/13/2014')
=> Thu, 13 Mar 2014
>> date_val == Date.today
=> true
In your example Date.parse(ev_val) != Date.today should work for the comparison.

Resources