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

标签 ruby date strptime

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

我正在使用 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可以解析结果(就像 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 检查解析它.

编辑:

处理时间时,请记住始终执行您自己的检查!不要依赖函数。时间问题是你有很多异常(exception),即使你有 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 代码

关于Ruby strptime 不会在参数为 '25/01/2017' 的 %Y/%m/%d 上抛出 ArgumentError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51060593/

相关文章:

ruby - 如何摆脱 Haml & Ruby 渲染的 html 中的多余空格?

ruby - 为什么我不能从 ruby​​ 中的选定键创建新的散列?

ruby-on-rails - 登台或生产时出现错误 Rails 4 控制台

ruby - ruby 中的康威斯人生游戏

java - 如何在java中按日期/时间比较和排序列表?

c++ - 如何使用 C++ 将时区化的 XML 类型 dateTime 转换为 time_t

C : Validation in strptime

r - 时间序列,将每月数据更改为每季度一次

python - SQLite:选择所有日期值对,其中每个日期和第一个日期之间的距离是特定时间段的倍数

python - datetime.strptime 在 PyQt4 QtGui.QWidget 继承类中不起作用