Rails Date#strptime在200年之前错误地解析日期

时间:2016-11-14 05:18:37

标签: ruby-on-rails ruby

为什么Rails' files : [ { expand : true, flatten : true, src : [ 'index.html' ], dest : 'build/index.html' }, ] 解析" 13/08"在200年之前的8月15日或8月14日?

Date#strptime

2 个答案:

答案 0 :(得分:2)

总结一下:

如果您不使用timecop gem,则Date#strptime似乎可以正常使用年份< 200。

如果使用timecop,则会覆盖Date#strptime并使用Time#to_date,这似乎会返回错误的年份值< 200。

简单的解决方案:

  • 不要使用timecop
  • 如果您使用,请使用Date#strptime_without_mock_date 时空特警
  • 使用Date.new + Time#strptime

更难的解决方案: 了解Time#to_date的实施有什么问题(参见Stefan的解释。)

[0] pry(main)> Time.local(99,8,13).to_date
=> #<Date: 0099-08-15 ((1757444j,0s,0n),+0s,2299161j)>
[1] pry(main)> Date.strptime('13/08/99', '%d/%m/%Y')
=> #<Date: 0099-08-13 ((1757442j,0s,0n),+0s,2299161j)>
[2] pry(main)> require 'timecop'
=> true
[3] pry(main)> Date.strptime('13/08/99', '%d/%m/%Y')
=> #<Date: 0099-08-15 ((1757444j,0s,0n),+0s,2299161j)>
[4] pry(main)> Date.strptime_without_mock_date('13/08/99', '%d/%m/%Y')
=> #<Date: 0099-08-13 ((1757442j,0s,0n),+0s,2299161j)>
[5] pry(main)> time = Time.strptime('13/08/99', '%d/%m/%Y')
=> 0099-08-13 00:00:00 +0053
[6] pry(main)> Date.new(time.year,time.month,time.day)
=> #<Date: 0099-08-13 ((1757442j,0s,0n),+0s,2299161j)>

答案 1 :(得分:2)

  

使用github.com/daveallie/where_is

Where.is(Date, :strptime)
#=> ["/home/deployer/.rvm/gems/ruby-2.3.1/gems/timecop-0.7.0/lib‌​/timecop/time_extens‌​ions.rb", 46]
     

导致timecop/time_extensions.rb#L46

def strptime_with_mock_date(str, fmt)
  Time.strptime(str, fmt).to_date
end

那是正确的,Timecop转向:

Date.strptime('13/08/99', '%d/%m/%Y')
#=> #<Date: 0099-08-13 ((1757442j,0s,0n),+0s,2299161j)>

成:

Time.strptime('13/08/99', '%d/%m/%Y').to_date
#=> #<Date: 0099-08-15 ((1757444j,0s,0n),+0s,2299161j)>
  

所以它不是Date,那个有问题的,Time

它并非完全错误,只是不同。 Time#to_date将这些值解释为公历日历日期:

Date.new(99, 8, 13, Date::GREGORIAN).new_start
#=> #<Date: 0099-08-15 ((1757444j,0s,0n),+0s,2299161j)>

Date.new(99, 8, 13, Date::ITALY).new_start
#=> #<Date: 0099-08-13 ((1757442j,0s,0n),+0s,2299161j)>

以下是Wikipedia的摘要:

Julian range             | Proleptic Gregorian range | Gregorian ahead by:
-------------------------|---------------------------|--------------------
03/03/4    - 01/03/100   | 01/03/4    - 28/02/100    | −2 days
02/03/100  - 29/02/200   | 01/03/100  - 28/02/200    | −1 days
01/03/200  - 28/02/300   | 01/03/200  - 28/02/300    |  0 days
29/02/300  - 27/02/500   | 01/03/300  - 28/02/500    |  1 day
28/02/500  - 26/02/600   | 01/03/500  - 28/02/600    |  2 days
27/02/600  - 25/02/700   | 01/03/600  - 28/02/700    |  3 days
26/02/700  - 24/02/900   | 01/03/700  - 28/02/900    |  4 days
25/02/900  - 23/02/1000  | 01/03/900  - 28/02/1000   |  5 days
24/02/1000 - 22/02/1100  | 01/03/1000 - 28/02/1100   |  6 days
23/02/1100 - 21/02/1300  | 01/03/1100 - 28/02/1300   |  7 days
22/02/1300 - 20/02/1400  | 01/03/1300 - 28/02/1400   |  8 days
21/02/1400 - 19/02/1500  | 01/03/1400 - 28/02/1500   |  9 days
20/02/1500 - 04/10/1582  | 01/03/1500 - 14/10/1582   | 10 days