Ruby strptime 不会在 %Y/%m/%d 上抛出带有参数 '25/01/2017' 的 ArgumentError



今天发现了一些奇怪的行为,我希望有人能对此有所了解。

我正在使用 strptime 来验证导入文件中的日期。在这种情况下,如果文件中的行包含不符合格式 %Y/%m/%d (2017/01/25( 的日期,我想抛出错误。

我按如下方式调用 strptime:

Date.strptime('25/01/2017', '%Y/%m/%d')

我预计这不会失败,因为 25 不符合今年的标准。但是,此操作会成功,提供的日期为:

0025, 01, 20

如果我交换月份和日期(01/25/2018(,它会失败,因为它确实检测到月份无效。

那么什么给了呢?奇怪的是,它不仅创造了这个看起来很精神的年份(0025(,而且更疯狂的是,它毫无问题地忽略了字符串末尾的"17"。

提前感谢! :)

你必须思考你实际上说了什么:

Date.strptime('25/01/2017', '%Y/%m/%d')

你是说你想要0025年、01月和20日(它去掉了其余的(。 最后你会得到0025-01-20.

您不能仅依靠Date.strptime为您进行验证。

最好的是通过正则表达式实际解析它并进行验证。

对于您的格式,可能的正则表达式(一种简单的方法(:

'25/01/2017'.match(/d{4}/d{2}/d{2}/)

在您的情况下,你会得到nil,因为它不匹配。

如果您获得匹配,您将获得:#<MatchData "2017/01/25">.

问题是这不会检查日期的正确格式。 你仍然需要检查strptime是否可以解析结果(就像汤姆·洛德提供的链接一样(。

另一方面,您也可以仅使用正则表达式检查它,这可能相当复杂:(以下正则表达式检查yyyy/mm/dd格式(:

^(?:(?:(?:(?:(?:[1-9]d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:[2468][048]|[13579][26])00))(/)(?:0?21(?:29)))|(?:(?:[1-9]d{3})(/)(?:(?:(?:0?[13578]|1[02])2(?:31))|(?:(?:0?[13-9]|1[0-2])2(?:29|30))|(?:(?:0?[1-9])|(?:1[0-2]))2(?:0?[1-9]|1d|2[0-8])))))$

然后,您立即知道日期格式是否正确,并且不必检查使用strptime解析它。

编辑:

处理时间时,请记住始终执行自己的检查! 不要依赖该功能。 时间的问题在于你有很多例外,即使你有ISO 8601,也许其他一些应用程序可能不遵循它。

根据评论,我想更深入地挖掘strptime现在我想将注释粘贴到源代码中(在date_s_strptime函数和 data_core.c 中(:

/*
* call-seq:
*    Date.strptime([string='-4712-01-01'[, format='%F'[, start=Date::ITALY]]])  ->  date
*
* Parses the given representation of date and time with the given
* template, and creates a date object.  strptime does not support
* specification of flags and width unlike strftime.
*
*    Date.strptime('2001-02-03', '%Y-%m-%d')   #=> #<Date: 2001-02-03 ...>
*    Date.strptime('03-02-2001', '%d-%m-%Y')   #=> #<Date: 2001-02-03 ...>
*    Date.strptime('2001-034', '%Y-%j')    #=> #<Date: 2001-02-03 ...>
*    Date.strptime('2001-W05-6', '%G-W%V-%u')  #=> #<Date: 2001-02-03 ...>
*    Date.strptime('2001 04 6', '%Y %U %w')    #=> #<Date: 2001-02-03 ...>
*    Date.strptime('2001 05 6', '%Y %W %u')    #=> #<Date: 2001-02-03 ...>
*    Date.strptime('sat3feb01', '%a%d%b%y')    #=> #<Date: 2001-02-03 ...>
*
* See also strptime(3) and #strftime.
*/

你可以看到像 sat/feb 这样的字符串也被使用,所以解析器可以处理字符串也就不足为奇了。待续 - 深入研究 C 代码

最新更新