首页 > 解决方案 > Ruby 将 csv 日期格式化为无效日期(argumentError)

问题描述

我正在解析一个 csv 文件,我需要更改 dob 以匹配某种格式YYY-MM-DD我不断收到这个错误,parse': invalid date (ArgumentError) 当它尝试解析这个日期时会发生"6/6/99"我如何解决这个问题,所以我不会收到任何错误我有哪些日期?

csv 中所有日期的列表,我不确定上述日期之后的任何其他日期是否也会出错。

"12/12/2010"
"1/1/1988"
"2/2/1966"
"6/6/99"
"1/4/88"
"4/4/1948"
"1/6/1988"
"1/7/1988"
"1/8/88"
"1/9/88"
"1988-02-12"
"1-11-88"
"1/12/88"
"1/13/88"

我的代码

require 'csv'
require 'time'
require 'date'

def parse_csv
  table = CSV.parse(File.read("input.csv", encoding: 'bom|utf-8' ), headers: true, col_sep: ",")
   formatted = table.map(&:to_h)
   formatted.each do |x|
   if x["dob"] =~ /^\d{4}-\d{2}-\d{2}$/
     p "correct"
   else
     parsed = Date.parse(x["dob"], "%Y-%m-%d")
     p parsed
   end
  end
end
parse_csv

标签: rubycsvdate

解决方案


从文档

Date.parse

解析给定的日期和时间表示,并创建一个日期对象。

此方法不能用作验证器。如果输入字符串与有效格式不严格匹配,您可能会得到一个神秘的结果。应考虑尽可能使用Date.strptime代替这种方法。

您当前的实现实际上没有意义;它没有做你认为的那样:

Date.parse('6/6/99', "%Y-%m-%d")
  #=> Date::Error: invalid date

这不是说“转换"6/6/99"成” "1999-06-06",而是说“尝试解析"6/6/99"成一个Date对象(并且第二个参数基本上被忽略了!)。

如果您确信该日期应该是什么格式,那么(根据上面引用的文档!)您可以Date.strptime尝试将其显式解析为这种格式。例如:

Date.strptime('6/6/99', "%m/%d/%y")
  #=> #<Date: 1999-06-06 ((2451336j,0s,0n),+0s,2299161j)>

或者,如果您不确定前两个值应该代表月-日还是日-月,那么您需要在代码中明确处理此问题并适当地处理错误。


tl;博士:

  • Date.parse对于任意输入不可靠;它只会对日期格式做出“最佳猜测”。不出所料,它至少在您抛出的一种模棱两可的格式中失败了。

  • Date.strptime当您知道您期望的格式时,是解析每个日期的正确方法。


推荐阅读