ruby-on-rails - ActiveRecord 添加负日期年份

标签 ruby-on-rails ruby date activerecord

我需要能够保存负日期,但遇到了一个问题:从数据库检索日期时,ActiveRecord 在年份上加 1。

迁移使用t.date

这是一个简单的示例:

我创建并保存了一个日期值为 Date.new(-44, 3, 15) 的模型。

插入数据库时​​,在数据库内部,年份是正确的。手动 psql 检查证实了这一点。

但是,当使用 ActiveRecord 从数据库检索日期时,年份为 -43。

我用谷歌搜索过,但没有结果。知道是什么原因造成的吗?

最佳答案

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

The year 1 BC/BCE is numbered 0, the year 2 BC is numbered −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 应用意味着什么?

用户输入很可能以“0044-03-15 BC”格式作为字符串(参数)提交,并分配给模型属性。

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 ,并在显示用户输入的日期时关闭一年(仅公元前)。


一些可能的 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  

希望其他人有更好的解决方案......

关于ruby-on-rails - ActiveRecord 添加负日期年份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31077771/

相关文章:

ruby-on-rails - 错误 - "gem install rails"- 缺少 libxml2

ruby-on-rails - 如果字符串包含 ruby​​ 命令,如何评估 ruby​​ 中的字符串?

ruby-on-rails - 我应该在 Gemfile 中设置显式版本吗?

ruby - bundle gem 已安装但据报告未安装

ruby - 如何使用 Nokogiri 选择元素

ruby - 如何在遍历数组时使用 Array#delete?

date - 如何根据 Microsoft Infopath Designer 中的频率计算截止日期的第一天

php - 计算两个日期之间的工作时间

python - 如何在 python 中使用日期范围在 mySQL 中拉取/查询数据

ruby-on-rails - rails 上的 ruby : Basic hello world return method not allowed in Heroku production