Since Postgres 10, Postgres has used the Gregorian calendar for all dates, including dates before the Gregorian calendar was in use.
Ruby claims to, by default, uses the Gregorian calendar for 1582-10-15 and later, and the Julian calendar otherwise; however, this is only valid for dates 1582-10-04 and earlier. Dates using the default Date::ITALY epoch cannot be created between 1582-10-05 and 1582-10-14, and attempting to do so raises invalid date (Date::Error).
Because PG::TextDecoder::Date uses the default Date initializer, attempting to read a date in this range also raises this error.
Steps to reproduce:
-
create an ActiveRecord model with a date field:
class CreateDateRecords < ActiveRecord::Migration[8.1]
def change
create_table :date_records do |t|
t.date :some_date
t.timestamps
t.check_constraint "num_nonnulls(from_date, to_date, from_year, to_year) >= 1"
end
end
end
class DateRecord < ApplicationRecord; end
-
create and persist an instance of this model with the date field set to a value in this range:
date_value = Date.new(1582, 10, 10, Date::GREGORIAN)
record = DateRecord.create!(date_field: date_value)
-
load the record from the database:
reloaded = DateRecord.find_by(id: record.id)
Expected:
- record is reloaded
- date value matches original value
Actual:
Proposed fix:
The most correct fix, in terms of matching the Postgres documentation, would be to modify PG::TextDecoder::Date to pass Date::GREGORIAN explicitly, and have all dates returned from Postgres us the Gregorian epoch.
This would be a change in behavior for dates 1582-10-04 and earlier, though, and might surprise some users -- for instance, saving and reloading the naive Julian value Date.new(1582, 10, 3) would return a Date that would not be equal to the original.
A less correct but more compatible fix would be to only pass start = Date::GREGORIAN for dates in the invalid range, possibly in a rescue block.
Since Postgres 10, Postgres has used the Gregorian calendar for all dates, including dates before the Gregorian calendar was in use.
Ruby claims to, by default, uses the Gregorian calendar for 1582-10-15 and later, and the Julian calendar otherwise; however, this is only valid for dates 1582-10-04 and earlier. Dates using the default
Date::ITALYepoch cannot be created between 1582-10-05 and 1582-10-14, and attempting to do so raisesinvalid date (Date::Error).Because
PG::TextDecoder::Dateuses the defaultDateinitializer, attempting to read a date in this range also raises this error.Steps to reproduce:
create an ActiveRecord model with a
datefield:create and persist an instance of this model with the date field set to a value in this range:
load the record from the database:
Expected:
Actual:
reloading fails with a stack trace like:
Proposed fix:
The most correct fix, in terms of matching the Postgres documentation, would be to modify
PG::TextDecoder::Dateto passDate::GREGORIANexplicitly, and have all dates returned from Postgres us the Gregorian epoch.This would be a change in behavior for dates 1582-10-04 and earlier, though, and might surprise some users -- for instance, saving and reloading the naive Julian value
Date.new(1582, 10, 3)would return aDatethat would not be equal to the original.A less correct but more compatible fix would be to only pass
start = Date::GREGORIANfor dates in the invalid range, possibly in a rescue block.