I have a datetime picker which sends the checkin & checkout dates with search box. Then the url looks like;
http://localhost:3000/locations/listings?utf8=%E2%9C%93&search=london&start_date=12%2F04%2F16&end_date=20%2F04%2F16
and I take the params hash and parse the string,
start_date = Date.parse(params[:start_date])
end_date = Date.parse(params[:end_date])
first of all, I have to check if (start_date.present? && end_date.present?) and that works fine.
But if the user manually types something else rather than the date to url such as;
http://localhost:3000/locations/listings?utf8=%E2%9C%93&search=london&start_date=londoneye6&end_date=20%2F04%2F16
Then of course I get an error;
invalid date
How should I control if the string is parsable on controller action. I should be also checking london-eye, london/eye strings, which include - /
Thank you
You have to try parsing the string and rescue ArgumentError
begin
myDate = Date.parse("31-01-2016")
rescue ArgumentError
# handle invalid date
end
one line (please note that this rescues all errors)
myDate = Date.parse("31-01-2016") rescue nil
You can validate time with Date.parse, and just trap ArgumentError exception on parse returning nil out:
controller:
def param_date date
Date.parse(date)
rescue ArgumentError
nil
end
start_date = param_date(params[:start_date])
end_date = param_date(params[:end_date])
Related
I have tried many ways of writing a validate date function in ruby which handles all the edge cases like , if the current date is valid according to leap year, and also if the date is passed in invalid format like 20-05-2022 it should return false , it should only valid format of date in yyyy-mm-dd format.
Functions I tried before asking here(this function I got from one of the Stackoverflow link):
require 'date'
def validate_date?(string)
date_format = '%Y-%m-%d'
DateTime.strptime(date, date_format)
true
rescue ArgumentError
false
end
But the problem with this function is it is not able to handle some of the invalid date formats like :
validate_date('202200-06-02') -> returns true (As the date is in incorrect format)
validate_date('2022-060-002') -> returns true (As the date is in incorrect format)
I want to return false if these invalid date formats are applied.
Any suggestions or improvements are welcome, or even what else should I try to write a proper validate_date function which can be used for all kinds of edge cases.
If you are using Rails you can use method to_date in combination with regexp
def valid_date?(string)
!!(string.to_date && /^\d{4}-\d{1,2}-\d{1,2}$/ =~ string)
rescue Date::Error
false
end
If you are not
require 'date'
def valid_date?(string)
!!(Date.parse(string) && /^\d{4}-\d{1,2}-\d{1,2}$/ =~ string)
rescue Date::Error
false
end
I need to test a specific array of dates to ensure that they are in the correct format, however I cannot use 'parse' because, if I do, the dates that are incorrect are sorted out. For instance, if I have an incorrect date with a month "13", it adds another year and sets the month to 1.
My code pulls in the dates from an SQL query:
table_birth_dates = self.class.connection.execute("SELECT birth_date FROM #{temp_table_name}").values.flatten
[
[0] "1980-30-54",
[1] "1980-30-54",
[2] "2020-09-10",
[3] "1890-10-30"
]
yr = 1900
year_test = table_birth_dates.select{|d| Date.parse(d).year < yr}
This now gives me an ArgumentError: invalid date.
I thought of using:
splitted_birth_date = table_birth_dates.first.split("-")
splitted_birth_date.first.to_i > 1900?
but if I try to loop through all of my dates, I'm not able to manipulate anything via splitting:
table_birth_dates.each do |birth_date|
birth_date.split("-")
end
What can I do with this?
I need to test a specific array of dates to ensure that they are in
the correct format...
If you get an error it means that the date is incorrect, you could rescue that error and do anything you want with that date to make it valid or whatever.
table_birth_dates.each do |birth_date|
begin
if Date.parse(d).year < yr
# do smth
end
rescue ArgumentError => e
# do smth with `d`
end
end
You could combine your select and split approaches together:
table_birth_dates.select { |d| d.split('-').first.to_i < 1900 }
#=> ["1890-10-30"]
I have a custom date validator that looks like this:
# app/validators/date_validator.rb
class DateValidator < ActiveModel::EachValidator
DATE_REGEX = /\d{2}\/\d{2}\/\d{4}/
def validate_each(record, attribute, value)
before_type_cast = "#{attribute}_before_type_cast"
raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
raw_value ||= value
return if raw_value.blank?
record.errors[attribute] << (options[:message] || "must be in correct date format") if (raw_value =~ DATE_REGEX).nil?
end
end
In my model, I use that validator with the following code:
validates :date_assigned :date => true
My problem is, that when a user enters an invalid date, I'd like to display the invalid date on the form so they can correct it. But currently, when I enter "11111" into the date assigned field on the form, I believe the rails typecasting is converting it to nil (date_assigned is a date value in the DB), so instead of "11111" being displayed, nothing is.
If a user enters "01/01/01" (invalid per the date regex), the view is displaying "0001-01-01" instead of the original (invalid) string of "01/01/01".
Can someone help me figure out how to do this? Thanks
The application I'm working with insists on displaying all user-input dates (via jquery datepicker) in the non standard American %m/%d/%Y format. As a result we have a lot of strptime methods scattered throughout our controllers.
I'm trying to clean it up and would like to overload the Rails to_date, to_datetime, and to_time extensions so these are no longer necessary.
#config/initializers/string.rb
class String
def to_date
begin
Date.strptime(self, '%m/%d/%Y') #attempt to parse in american format
rescue ArgumentError
Date.parse(self, false) unless blank? #if an error, execute original Rails to_date
#(pulled from Rails source)
end
end
def to_datetime
begin
DateTime.strptime(self,'%m/%d/%Y')
rescue ArgumentError
DateTime.parse(self, false) unless blank?
end
end
def to_time(form = :local)
begin
Time.strptime(self,'%m/%d/%Y')
rescue ArgumentError
parts = Date._parse(self, false)
return if parts.empty?
now = Time.now
time = Time.new(
parts.fetch(:year, now.year),
parts.fetch(:mon, now.month),
parts.fetch(:mday, now.day),
parts.fetch(:hour, 0),
parts.fetch(:min, 0),
parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
parts.fetch(:offset, form == :utc ? 0 : nil)
)
form == :utc ? time.utc : time.getlocal
end
end
end
Anyway, this works great in rails console; "06/24/2014".to_date and variants behave exactly as I would like them. However, it looks like ActiveRecord doesn't use these overloaded definitions when creating/validating new table entries, eg
MyModelName.create(start_date:"06/07/2014") gives a start date of 2014-07-06.
What can I do to make ActiveRecord recognize these overloaded definitions?
You can set default time and date formats in config/application.rb file this way:
my_date_formats = { :default => '%d.%m.%Y' }
Time::DATE_FORMATS.merge!(my_date_formats)
Date::DATE_FORMATS.merge!(my_date_formats)
The ruby-american_date gem may be what you want. It forces Date/DateTime/Time.parse to parse American formatted dates. Simply include it in your project's Gemfile.
I want get all my records which have a start_date(So not the normal creation_date) from my stringed date(11-20-2013) within a scope of 1 week.
I've never really used scoping in Rails before so I'm rather lost here. Should I use a .where()? If so, How do I adress start_date+1 week in this scope?
I've tried something like:
if params[:startdate]
group = Group.find_by_id(params[:group_id]).where(:start_date => params[:startdate]..params[:startdate] + 1.weeks)
end
Which throws: can't convert ActiveSupport::Duration into String
Because params[:startdate] is String when you need DateTime.
You can try to parse it
startdate = DateTime.parse(params[:startdate]) rescue nil
if startdate
group = Group.find_by_id(params[:group_id]).where(:start_date => startdate..startdate + 1.weeks)
else
# you get wrong startdate
end