From: Colin Bartlett Date: 2010-09-07T02:11:09+09:00 Subject: [ruby-core:32096] [Ruby 1.9.1-Backport#3795][Open] Date._valid_civil? in 1.9.1 raises exception for some invalid dates instead of returning false Backport #3795: Date._valid_civil? in 1.9.1 raises exception for some invalid dates instead of returning false http://redmine.ruby-lang.org/issues/show/3795 Author: Colin Bartlett Status: Open, Priority: Normal possible_bug = <<_possible_bug Date._valid_civil? in 1.9.1 raises exception for some invalid dates instead of returning false. This is a possible bug in 1.9.1 Date._valid_civil? found while I was testing changes to some methods in Date to make them faster. I tried a search but couldn't find a bug report for this. If it is a bug, then there are implications for other methods in 1.9.1 Date, and I would be more than happy to elaborate. For versions of Date.valid_civil? before Ruby 1.9.1, if the date is valid then the return value is the julian day number, else nil. In 1.9.1 Date my understanding is that the intended behaviour is if the date is valid then the return value is true, else false. But in the 1.9.1 version on my computer, for example: month = -14, day = -1 returns false; month = -13, day = -1 raises a NoMethodError exception. The behaviour is the same on http://tryruby.org: RUBY_VERSION #=> "1.9.1" Date.valid_civil? 2010, -14, -1 #=> false Date.valid_civil? 2010, -13, -1 #=> #=> NoMethodError: undefined method `+' for nil:NilClass The problem seems to be in the private method Date._valid_civil? which as currently written seems not to cater for the possibility that Date.find_ldom might return nil. The following code shows the behaviour on my computer: (a) using the current 1.9.1 Date._valid_civil?; (b) after a one line patch to Date._valid_civil? _possible_bug puts puts "Ruby #{RUBY_VERSION}" puts "defined?( Date.find_ldom() )" p defined?( Date.find_ldom() ) puts possible_bug require "date" def test_date_valid_civil() y = 2010 sg = Date::ITALY mm = [ -12, -14, -25, -13, -26, 0 ] dd = [ -1 ] mm.each do |m| dd.each do |d| print "* y=#{y}, m=#{m}, d=#{d}; sg=#{sg.inspect};" begin rr = Date.valid_civil?( y, m, d, sg ) puts " #=> #{rr.inspect}" rescue puts " #=> " + $!.inspect end end end end puts puts "(a) use Ruby 1.9.1 to test current 1.9.1 Date._valid_civil?" test_date_valid_civil() puts; puts "(b) patch and test patched Date._valid_civil?" class Date t = Module.new do private def _valid_civil? (y, m, d, sg=GREGORIAN) # :nodoc: if m < 0 m += 13 end if d < 0 # j = find_ldom(y, m, sg) #- return unless j = find_ldom(y, m, sg) #+ patch by CWB 2010-09-06 ny, nm, nd = jd_to_civil(j + d + 1, sg) return unless [ny, nm] == [y, m] d = nd end jd = civil_to_jd(y, m, d, sg) return unless [y, m, d] == jd_to_civil(jd, sg) jd end end extend t include t end test_date_valid_civil() ---------------------------------------- http://redmine.ruby-lang.org