Ruby中的优美日期解析

Ruby中的优美日期解析,ruby,parsing,datetime,Ruby,Parsing,Datetime,我在控制器操作中有两个日期参数,如果它们为nil或解析失败,我希望返回到默认值 不幸的是,如果解析失败,DateTime.strtime似乎会抛出一个异常,这迫使我编写这个怪物: starting = if params[:starting].present? begin DateTime.strptime(params[:starting], "%Y-%m-%d") rescue @meeting_range.first end else @meeting_ra

我在控制器操作中有两个日期参数,如果它们为nil或解析失败,我希望返回到默认值

不幸的是,如果解析失败,
DateTime.strtime
似乎会抛出一个异常,这迫使我编写这个怪物:

starting = if params[:starting].present?
  begin
    DateTime.strptime(params[:starting], "%Y-%m-%d")
  rescue
    @meeting_range.first
  end
else
  @meeting_range.first
end
他感觉很糟糕。有没有办法用Ruby stdlib解析一个不需要
begin…rescue
块的日期?在这种情况下感觉有点过头了。

为什么不简单地:

starting = DateTime.strptime(params[:starting], '%Y-%m-%d') rescue @meeting_range.first

一般来说,我不同意另一种解决方案,以这种方式使用
rescue
是不好的做法。我认为值得一提的是,如果其他人试图将这个概念应用到不同的实现中

我担心的是,您可能感兴趣的其他一些异常将被该
救援
隐藏,从而违反早期错误检测规则

以下内容适用于
Date
而不是
DateTime
,但您会明白这一点:

Date.parse(home.build_time) # where build_time does not exist or home is nil
Date.parse(calculated_time) # with any exception in calculated_time
不得不面对同样的问题,我最终用猴子补丁Ruby,如下所示:

# date.rb
class Date
  def self.safe_parse(value, default = nil)
    Date.parse(value.to_s)
  rescue ArgumentError
    default
  end
end
值中的任何异常都将在进入该方法之前上升,并且只捕获
ArgumentError
(尽管我不知道其他任何可能的异常)

内联
rescue
的唯一正确用法与此类似:

f(x) rescue handle($!)
更新

这些天我更喜欢而不是猴子补丁Ruby。相反,我将我的
日期
包装在
Rich
模块中,我将其放入
lib/Rich
,然后用以下代码调用它:

Rich::Date.safe_parse(date)

如果要挽救异常,可以通过
present?
来消除条件作用。这与您有两个日期参数而不是一个有关吗?如果没有,则从问题中删除不必要的信息有助于读者。@sawa问题的目的是完全消除
begin…rescue
块。你的另一点只是吹毛求疵。
strtime
的想法是,你已经知道解析会成功,因为在
strtime
看到它之前,你已经在代码运行时限定了日期格式<代码>日期#解析,
DateTime#parse
Time#parse
可以猜测正确的格式,当你不确定你得到了什么,尽管他们在
%m/%d/%Y
%d/%m/%Y
格式中偶然发现了日期。@Tin-Man我想要的是一个解析函数,它在失败时返回零,而不是抛出异常<代码>日期#解析,
日期时间#解析
时间#解析
所有抛出
参数错误
。我想不出在任何情况下,我希望日期参数在控制器中以这种方式运行。如果我必须使用
救援
,这看起来是一个可以接受的折衷方案。尽管如此,它仍然感觉像是一个反模式。完全一致的是,未能解析值会引发异常。类似地,如果期望值,则非值也是异常状态。Ruby不这样做,但在许多语言中,即使是在数组中搜索特定值的函数,如果该值不在数组中,也会引发异常,并且通过错误的键访问哈希元素也会引发异常(在Ruby中,该函数返回
nil
)。例外不应被视为错误,而应被视为一种令人惊讶的状态,与给定情况下的正常状态不同。如果你采用这种观点,不是反模式,而是行为的不一致性,而不是我认为反模式的例外本身。在某些情况下,抛出异常是完全合理的,这是正确的。我只希望这里有另一种选择,因为在这种情况下,解析失败并不奇怪。代码使用后面的
rescue
清除了很多蠕虫,但是如果解析之外的东西在
rescue
左侧失败,代码也可以打开一个新的蠕虫罐。这个病例看起来很温和,但需要小心。调试这类问题很烦人/令人沮丧/困难:选择任意两个。@TinMan:没错。您必须确保您的一行只抛出一种类型的异常(或者您希望对任何类型的异常进行相同的处理)。但在这种情况下,唯一的失败部分是
strtime
,而原始代码也有一个不受限制的
救援
,因此我认为我们在这里应该很好。事实上,每次我使用内联救援时,我都会后悔。我早就把解析需要使用的所有日期/时间移到了另一个位置,这就像我想要的一样。