🔖
[Bug #21199] 特定の日付を yaml で dump -> load すると日付がおかしくなるバグ報告
[Bug #21199] Psych.dump and load on Date before 1582-10-15
- 次のように
DateをPsychでdump -> loadしたときに1582-10-15よりも過去の日付の場合に正しくdump / loadされないというバグ報告-
Psychはyamlファイルの読み書きで使用されているライブラリ - なのでここに書いてる話は
yamlファイルを利用している場合に関係がある
-
require 'date'
require 'psych'
def check(date)
puts "date=#{date.inspect}"
str = Psych.dump(date, permitted_classes: [Date])
puts "str=#{str}"
date2 = Psych.load(str, permitted_classes: [Date])
puts "date2=#{date2.inspect}"
end
puts "OK"
check Date.new(2025, 9, 28)
puts
check Date.new(1582, 10, 15)
# 上の2つは意図する結果になっている
# 下は `psych.load` 後に日付がずれている
puts
puts "NG"
check Date.new(1582, 10, 4)
__END__
OK
date=#<Date: 2025-09-28 ((2460947j,0s,0n),+0s,2299161j)>
str=--- 2025-09-28
date2=#<Date: 2025-09-28 ((2460947j,0s,0n),+0s,-Infj)>
date=#<Date: 1582-10-15 ((2299161j,0s,0n),+0s,2299161j)>
str=--- 1582-10-15
date2=#<Date: 1582-10-15 ((2299161j,0s,0n),+0s,-Infj)>
NG
date=#<Date: 1582-10-04 ((2299160j,0s,0n),+0s,2299161j)>
str=--- 1582-10-14
date2=#<Date: 1582-10-14 ((2299160j,0s,0n),+0s,-Infj)>
-
1582-10-04をdumpすると1582-10-14になってしまうのが問題みたい?
require "date"
require "psych"
# date は 1582-10-04 だが Psych.dump すると 1582-10-14 になる
date = Date.new(1582, 10, 4)
yaml = Psych.dump(date, permitted_classes: [Date])
puts yaml
# => --- 1582-10-14
- これなんですが Psych では Date オブジェクトをシリアル化する際にグレゴリオ暦基準で変換しようとするのが起因みたいですね
require "date"
require "psych"
# Date のデフォルトではユリウス日が Date::ITALY (1582年10月15日) となっている
date = Date.new(1582, 10, 4)
pp date.start == Date::ITALY # => true
pp date.start == Date::GREGORIAN # => false
# これが Psych では常にグレゴリオ暦になるように変換される
# ここで日付がずれてしまっている
date2 = date.new_start(Date::GREGORIAN)
pp date2.start == Date::ITALY # => false
pp date2.start == Date::GREGORIAN # => true
pp date2
# => #<Date: 1582-10-14 ((2299160j,0s,0n),+0s,-Infj)>
- また同様に
DateをデシリアライズするとDate::GREGORIAN基準で変換される
require 'date'
require 'psych'
yaml = "--- 1582-10-14"
date = Psych.load(yaml, permitted_classes: [Date])
pp date.start == Date::ITALY # => false
pp date.start == Date::GREGORIAN # => true
pp date
# => #<Date: 1582-10-14 ((2299160j,0s,0n),+0s,-Infj)>
- ややこしい…そもそも YAML 自体にこのあたりの情報を扱う仕組みがないのが問題みたいなんですかねー
- で、これなんですが実は
psych 5.2.3までは上記のような挙動だったんですがpsych 5.2.4から自身のユリウス日の情報を準じるようになったみたいですね?
require 'date'
require 'psych'
# Psych.dump の結果が 5.2.3 と 5.2.4 で変わる
date = Date.new(1582, 10, 4)
yaml = Psych.dump(date, permitted_classes: [Date])
puts yaml
# psych 5.2.3 => --- 1582-10-14
# psych 5.2.4 => --- 1582-10-04
- これにより
Psych.dumpの結果が変わる可能性があるので注意する必要がある- とはいえピンポイントなのでまあ〜
- ちなみに
Psych.dumpの挙動はそのまま
# Psych.load の結果はそのまま
date = Psych.load("--- 1582-10-04", permitted_classes: [Date])
pp date
# psych 5.2.3 => #<Date: 1582-10-04 ((2299150j,0s,0n),+0s,-Infj)>
# psych 5.2.4 => #<Date: 1582-10-04 ((2299150j,0s,0n),+0s,-Infj)>
# Psych.load の結果はそのまま
date = Psych.load("--- 1582-10-14", permitted_classes: [Date])
pp date
# psych 5.2.3 => #<Date: 1582-10-14 ((2299160j,0s,0n),+0s,-Infj)>
# psych 5.2.4 => #<Date: 1582-10-14 ((2299160j,0s,0n),+0s,-Infj)>
- 暦周り難しい…
Discussion