diff --git a/README.rdoc b/README.rdoc index f98f777..20e401f 100644 --- a/README.rdoc +++ b/README.rdoc @@ -250,6 +250,19 @@ Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves you adding a new one and deleting an old one to get it to work. +=== AMBIGUOUS YEAR THRESHOLD + +When dealing with 2 digit year values, by default a year is interpreted as being +in the last century at or above 30. You can customize this however + + ValidatesTimeliness::Formats.ambiguous_year_threshold = 20 + +Now you get: + + year of 19 is considered 2019 + year of 20 is considered 1920 + + === TEMPORAL RESTRICTION ERRORS: When using the validation temporal restrictions there are times when the restriction diff --git a/lib/validates_timeliness/formats.rb b/lib/validates_timeliness/formats.rb index c12dfeb..dc254c2 100644 --- a/lib/validates_timeliness/formats.rb +++ b/lib/validates_timeliness/formats.rb @@ -21,6 +21,17 @@ module ValidatesTimeliness :format_tokens, :format_proc_args + + # Set the threshold value for a two digit year to be considered last century + # Default: 30 + # + # Example: + # year = '29' is considered 2029 + # year = '30' is considered 1930 + # + cattr_accessor :ambiguous_year_threshold + self.ambiguous_year_threshold = 30 + # Format tokens: # y = year # m = month @@ -226,6 +237,49 @@ module ValidatesTimeliness compile_format_expressions end + def full_hour(hour, meridian) + hour = hour.to_i + return hour if meridian.nil? + if meridian.delete('.').downcase == 'am' + hour == 12 ? 0 : hour + else + hour == 12 ? hour : hour + 12 + end + end + + def unambiguous_year(year) + if year.length <= 2 + century = Time.now.year.to_s[0..1].to_i + century -= 1 if year.to_i >= ambiguous_year_threshold + year = "#{century}#{year.rjust(2,'0')}" + end + year.to_i + end + + def month_index(month) + return month.to_i if month.to_i.nonzero? + abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize) + end + + def month_names + defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES + end + + def abbr_month_names + defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES + end + + def microseconds(usec) + (".#{usec}".to_f * 1_000_000).to_i + end + + def offset_in_seconds(offset) + sign = offset =~ /^-/ ? -1 : 1 + parts = offset.scan(/\d\d/).map {|p| p.to_f } + parts[1] = parts[1].to_f / 60 + (parts[0] + parts[1]) * sign * 3600 + end + private # Compile formats into validation regexps and format procs @@ -285,44 +339,6 @@ module ValidatesTimeliness end end - def full_hour(hour, meridian) - hour = hour.to_i - return hour if meridian.nil? - if meridian.delete('.').downcase == 'am' - hour == 12 ? 0 : hour - else - hour == 12 ? hour : hour + 12 - end - end - - def unambiguous_year(year, threshold=30) - year = "#{year.to_i < threshold ? '20' : '19'}#{year}" if year.length == 2 - year.to_i - end - - def month_index(month) - return month.to_i if month.to_i.nonzero? - abbr_month_names.index(month.capitalize) || month_names.index(month.capitalize) - end - - def month_names - defined?(I18n) ? I18n.t('date.month_names') : Date::MONTHNAMES - end - - def abbr_month_names - defined?(I18n) ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES - end - - def microseconds(usec) - (".#{usec}".to_f * 1_000_000).to_i - end - - def offset_in_seconds(offset) - sign = offset =~ /^-/ ? -1 : 1 - parts = offset.scan(/\d\d/).map {|p| p.to_f } - parts[1] = parts[1].to_f / 60 - (parts[0] + parts[1]) * sign * 3600 - end end end end diff --git a/spec/formats_spec.rb b/spec/formats_spec.rb index e6e1589..580c18b 100644 --- a/spec/formats_spec.rb +++ b/spec/formats_spec.rb @@ -155,6 +155,28 @@ describe ValidatesTimeliness::Formats do end end + describe "parsing date with ambiguous year" do + it "should return year in current century if year below threshold" do + time_array = formats.parse('01-02-29', :date) + time_array.should == [2029,2,1,0,0,0,0] + end + + it "should return year in last century if year at or above threshold" do + time_array = formats.parse('01-02-30', :date) + time_array.should == [1930,2,1,0,0,0,0] + end + + it "should allow custom threshold" do + default = ValidatesTimeliness::Formats.ambiguous_year_threshold + ValidatesTimeliness::Formats.ambiguous_year_threshold = 40 + time_array = formats.parse('01-02-39', :date) + time_array.should == [2039,2,1,0,0,0,0] + time_array = formats.parse('01-02-40', :date) + time_array.should == [1940,2,1,0,0,0,0] + ValidatesTimeliness::Formats.ambiguous_year_threshold = default + end + end + describe "removing formats" do it "should remove format from format array" do formats.remove_formats(:time, 'h.nn_ampm')