我需要能够保存否定日期,但一直遇到问题:从数据库中检索日期时,ActiveRecord正在添加1年。
迁移使用t.date
。
这是一个简单的例子:
我创建并保存日期值为Date.new(-44, 3, 15)
的模型。
当插入数据库和数据库内部时,年份是正确的。手动psql检查证实了这一点。
但是,使用ActiveRecord从数据库中检索日期时,年份为-43。
我用Google搜索并搜索了没有结果的SO。知道是什么导致了这个吗?
答案 0 :(得分:2)
http://ruby-doc.org/stdlib-1.9.3/libdoc/date/rdoc/Date.html#method-c-new
...BCE years are counted astronomically. ...the year before the year 1 is the year zero, and the year preceding the year zero is the year -1.
研究这个我认为你在Date#parse
发现了一个缺陷,然后我认为它正在按照设计的方式工作,现在我不再确定了:(
Date.parse('2015-06-15 CE') == Date.new(2015, 6, 15)
# => true
Date.parse('0000-01-01 CE') == Date.new(0, 1, 1)
# => true
Date.parse('0002-01-01 BCE') == Date.new(-1, 1, 1)
# => true
Date.parse('0000-01-01 CE') == Date.parse('0001-01-01 BCE')
# => true
Date.parse('0001-01-01 BCE') == Date.new(0, 1, 1)
# => true
https://en.wikipedia.org/wiki/Astronomical_year_numbering
公元前1年/公元前2年编号为0,公元前2年编号为-1
所以它似乎按照设计的方式工作,但可能不如预期的那样
# The year 1 BC/BCE is numbered 0
Date.parse('0001-01-01 BCE') == Date.new(0, 1, 1)
# the year 2 BC is numbered −1
Date.parse('0002-01-01 BCE') == Date.new(-1, 1, 1)
这对您和您的rails应用程序意味着什么?
用户输入最有可能以“#00; 0044-03-15 BC'作为字符串(params),分配给模型属性。
x = Widget.create(date_column: '0044-03-15 BC')
x.date_column
=> Wed, 15 Mar -0043
x.attributes_before_type_cast['date_column']
=> "0044-03-15 BC"
x.attributes_before_type_cast['date_column'].to_date
=> Wed, 15 Mar -0043
猜测to_date
也在使用Date.parse
我真的不确定如何在postgres中存储正确的值,但是rails会在该值上使用Date.parse
并在显示用户输入日期时关闭一年(仅限BCE)
一些可能的hacky解决方法
1)将值存储为整数
class Whatever < ActiveRecord::Base
# 'date' column -> the_date stored as an integer
# override the columns 'getter' method
def the_date
the_time = Time.at(self[:the_date])
Date.new(the_time.year, the_time.month, the_time.day)
end
end
# Time#to_i - epoch time
x = Whatever.create(the_date: Time.new(-44, 3, 15, 0, 0, 0).to_i)
2)将年,月,日存储为单独的数据库字段?
class Whatever < ActiveRecord::Base
# 'date' stored as 3 integer columns -> the_date_year, the_date_month, the_date_day
# use this in views, etc...
def the_date
Date.new(the_date_year, the_date_month, the_date_day)
end
end
希望其他人有更好的解决方案......