Ruby strptime不会在参数'25 / 01/2017'的%Y /%m /%d上引发ArgumentError

时间:2018-06-27 10:34:12

标签: ruby date strptime

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

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

我将strptime称为:

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

我希望这会失败,因为25岁不符合当年的标准。但是,此操作成功,将日期设置为:

0025,01,20

如果我在2018年1月25日前后交换月份和日期,它将失败,因为它会检测到该月份无效。

那有什么用呢?看来,这不仅造成了这种令人神往的年份(0025),而且甚至疯狂地忽略了字符串末尾的“ 17”而没有问题。

提前谢谢! :)

1 个答案:

答案 0 :(得分:1)

您必须考虑自己的实际意思:

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

您是说要年份0025,月份01和日期20(除去其余部分)。最后,您得到0025-01-20

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

最好是通过regexp进行解析并进行验证。

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

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

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

如果您找到比赛,您将获得: #<MatchData "2017/01/25">

问题在于,这不会检查日期的正确格式。您仍然需要检查strptime是否可以解析结果(如Tom Lord提供的链接中的)。

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

^(?:(?:(?:(?:(?:[1-9]\d)(?:0[48]|[2468][048]|[13579][26])|(?:(?:[2468][048]|[13579][26])00))(\/)(?:0?2\1(?: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]|1\d|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代码