Date validation for invalid years - ruby

I am trying to do what feels like something quite basic, but struggling. I want to be able to determine if a date is valid, if it is, parse it and output in a formatted string, else return 'bad date'. This is where I have got so far;
require 'date'
date_last_printed = current_item.getProperties['Last Printed']
begin
d = DateTime.parse(date_last_printed.to_s)
if Date.valid_date?(d.year, d.month, d.day)
d.strftime("%d/%m/%Y %H:%M:%S")
else
'bad date'
end
rescue Exception => ex
ex.message
end
However 01/01/1601 is returning as a valid date.
How can I adjust my snippet to return only valid dates (on or after the start of Unix epoch time).

you could perform epoch conversion inside the begin statement.
begin
raise if (t=Time.parse(date_last_printed)).to_i < 0
t.strftime("%d/%m/%Y %H:%M:%S")
rescue
'bad date'
end

Related

How to check whether correct date format has been provided

I'm currently working through the Well-Grounded Rubyist and have a question about an exercise that is asking to check whether a date provided is in the format 'yyyy-mm-dd' as opposed to 'yy-mm-dd'.
We have a class Ticket and should create a date= method that checks whether the date provided is in the above mentioned format.
Is .strftime correct to use here?
In the end the method should return the date in the correct format and provide an error message for dates in the wrong format, like so:
ticket = Ticket.new
ticket.date = "2013-11-12"
=> "2013-11-12"
ticket.date = "13-11-12"
=> "Please submit the date in the format 'yyyy-mm-dd'."
Could someone indicate how I could perform these checks on dates?
Date::xmlschema is strict about this specific format (try this in IRB):
require 'date'
Date.xmlschema("2013-11-12") #<Date: 2013-11-12 ((2456609j,0s,0n),+0s,2299161j)>
#invalid month number:
Date.xmlschema("2013-13-12") #<ArgumentError: invalid date>
# 2 digit year:
Date.xmlschema("13-11-12") #<ArgumentError: invalid date>
# no leap year:
Date.xmlschema("2013-02-29") #<ArgumentError: invalid date>
You can throw the error to the user by using begin..rescue
require 'date'
begin
Date.parse("31-02-2010")
rescue => e
p "#{e}" #print your own custom messages and return accordingly
end
Also write
rescue ArgumentError
It will throw By default error
ArgumentError (invalid date)

Creating an error message for an invalid input

I have the following code that returns the # of days in any given month, which works fine unless someone types in something that isn't a date, or they format the date wrong. To remedy this I want to send out an error message for an invalid input, but I don't know how. So how do I create an error message for this small app?
#type in the month and year you want like so ---> "Feb 2034"
require 'date'
input = gets.chomp
inputArray = input.split(" ").to_a
textMonth = inputArray[0]
textYear = inputArray[1]
startOfMonth = Date.strptime(input, "%b %Y")
nextMonth = startOfMonth.next_month
endOfMonth = nextMonth - 1
daysInMonth = (endOfMonth - startOfMonth + 1).to_i
puts "#{textMonth} of year #{textYear} has #{daysInMonth} days!"
Probably the best way to do this is putting your input in a while loop, prompting for a new answer every time the input isn't what you expected it to be.
To check the input you should use a Regexp. Here's an explanation
how to write a regexp to match a date.
For Creating a Custom Error refer below code:
Here I create and raise InvalidDateError for the wrong date input.
#type in the month and year you want like so ---> "Feb 2034"
class InvalidDateError < StandardError
end
require 'date'
require 'pry-byebug'
input = gets.chomp
inputArray = input.split(" ").to_a
textMonth = inputArray[0]
textYear = inputArray[1]
begin
startOfMonth = Date.strptime(input, "%b %Y")
nextMonth = startOfMonth.next_month
endOfMonth = nextMonth - 1
daysInMonth = (endOfMonth - startOfMonth + 1).to_i
puts "#{textMonth} of year #{textYear} has #{daysInMonth} days!"
rescue StandardError=> e
raise InvalidDateError.new("Invalid Date : #{input}")
end
If you don't want to raise an error and only want to show error message then replace raise InvalidDateError.new("Invalid Date : #{input}")
with puts "Invalid Date : #{input}"
As suggested by Viktor, and stolen :) from crantok
require 'date'
date_valid = false
while !date_valid
puts 'Insert date as yyyy-mm-dd:'
input_date = gets.chomp
begin
parsed_date = Date.parse(input_date)
date_valid = true
rescue ArgumentError
puts 'format error'
end
end
month = parsed_date.month
year = parsed_date.year
days_in_month = Date.new(year, month, -1).day
puts "In #{year} month #{month} has #{days_in_month} days"

ArgumentError: invalid strptime format - `%m/%d/%y' work around

I am in the process of working with an sftp import bug in which I'm trying to flag any dates that are imported that are incorrect. There are two types of dates that could be off. The first is when the year is in the future, or way in the past; the second is when the actual months and days are too high. (Example, 13/20/1995, or 11/35/2000)
I'm using strptime and for dates that are off, flagging them and displaying them as a specific message. The problem I'm running into is that with the strptime format that I'm using, the errors happen right before I sub in the error message.
table_birth_dates = self.class.connection.execute("SELECT birth_date FROM #{temp_table_name}").values.flatten
table_birth_dates.map! do |date|
birth_date = Date.strptime(date, '%m/%d/%Y')
if birth_date.nil?
month_day_error_message = 'Invalid Month/Day'
elsif birth_date > Time.zone.today
future_error_message = 'Year in Future'
elsif birth_date.year < 1900
past_error_message = 'Year too old'
else
birth_date
end
end
The error is happening at the birth_date = Date.strptime(date, '%m/%d/%Y')
For a date such as 10/3/1891, it displays them as Sat, 03 Oct 1891.
However, for the messed up dates such as 33/33/2000 it shows me an error (which makes sense) however I was hoping to fix this error in my conditional.
Would anyone know what I could do?
If you want to use strptime your only option really is to rescue the error:
begin
birth_date = Date.strptime(date, '%m/%d/%Y')
rescue ArgumentError => ex
raise ex unless ex.message == 'invalid date'
# handle invalid date
end
You could set date to, e.g., :invalid there and then have date == :invalid in your conditional if you want to keep all the logic there instead of in the rescue itself.

How to check that date is correct when using date_select

I search a solution for validate user birth date, for example if user try to submit only day and month but he doesn't select year, date will be invalid, but rails don't show any exception or error if year is not set for example but he skip date, and date will not be updated
I found some old answers about the subject, and it seem not to be clear for me. (note i use date_select helper in my view)
I did already a search about date validation but I'm looking for an effective solution that is up to date
i will be thankful for any suggestion. thank you
DateTime.parse(..) will raise an error if the date is not valid:
[1] pry(main)> DateTime.parse("Feb 31, 2013")
ArgumentError: invalid date
from (pry):1:in `parse'
[2] pry(main)> e = begin; DateTime.parse("Feb 31, 2013"); rescue => e; e; end
=> #<ArgumentError: invalid date>
So just capture the error to check for a valid date:
def valid_date?(string)
begin
DateTime.parse(string)
return true
rescue => e
return false
end
end

Mysql2 throws errors on invalid dates

I have an issue with Mysql2 when it tries to get an invalid date (e.g. 2012-00-25).
For example:
require 'mysql2'
db = Mysql2::Client.new(....)
results = db.query(query)
results.each do |row|
..
..
end
If the first record has an invalid date, mysql2 will throw an error and it will stop in that point.
How could I handle it correctly (to catch the error and recover the wrong data)?
I don't have control of the source data.
Thanks in advance,
My solution:
I solved the issue adding :cast => false and parsing the date column
db.query(query,:cast => false)
results.each do |row|
..
begin
Date.parse(time)
rescue
# if date is wrong then set the date field
time = "1900-01-01 00:00:00"
end
..
end

Resources