views:

65

answers:

2

We have to handle user specified date formats in our application. We decided to go with Date.strptime for parsing and validation, which works great, except for how it just ignores any garbage data entered. Here is an irb session demonstrating the issue

ree-1.8.7-2010.01 > require 'date'
 => true 
ree-1.8.7-2010.01 > d = Date.strptime '2001-01-01failfailfail', '%Y-%m-%d'
 => #<Date: 4903821/2,0,2299161> 
ree-1.8.7-2010.01 > d.to_s
 => "2001-01-01" 

what we would like, is behavior more like this

ree-1.8.7-2010.01 > d = Date.strptime '2001failfailfail-01-01', '%Y-%m-%d'
ArgumentError: invalid date

Any suggestions would be appreciated

+1  A: 

One possibility is to pass the resulting date through strftime using the same format and compare to the original string.

i.e. valid = Date.strptime(date_string, format).strftime(format) == date_string

One limitation of this is that it wouldn't handle leading 0s in parts of the date e.g. if you wanted to accept 2010-6-1 but strftime returned 2010-06-01 you wouldn't have a match.

Also, I'm not sure if this is what you meant or not, but your second example Date.strptime '2001failfailfail-01-01', '%Y-%m-%d' does raise an ArgumentError. It seems like only trailing junk is ignored.

mikej
this is a really good idea. what i meant by the second block is that is the behavior i want from the first block
Matt Briggs
A: 

one way is to define a new class which does the validation first.

require 'date'

class Mydate 

    def self.strptime(string)
        raise ArgumentError 'Fail' if  string !~ /^\d\d\d\d-\d\d-\d\d$/
        Date.strptime(string)
    end
end

d = Mydate.strptime '2001-01-01'
puts d

d2 = Mydate.strptime '2001-01-02xxxx'
puts d2

Another way would be to open up the Date class, alias the strptime method, write a new one to do the validation you require and then call the aliased one.

require 'date'

class Date

    class << self
        alias :orig_strptime :strptime
    end

    def self.strptime(string)
        puts "in new strptime"
        raise ArgumentError 'Fail' if  string !~ /^\d\d\d\d-\d\d-\d\d$/ 
        Date.orig_strptime(string) 
    end  
end

d = Date.strptime '2001-01-01'
puts d

d2 = Date.strptime '2001-01-02xxxx'
puts d2   
stephenr