【问题标题】:How I can check for a valid date format in Perl?如何在 Perl 中检查有效的日期格式?
【发布时间】:2010-10-25 19:57:59
【问题描述】:


我正在从数据库中的一个变量中获取日期字段,目前我正在使用以下代码检查日期是否为“yyyy-mm-dd”格式

if ( $dat =~ /\d{3,}-\d\d-\d\d/ )

我的问题,有没有更好的方法来做到这一点。

非常感谢

【问题讨论】:

  • 如果这些数据的来源是你的数据库,为什么还要检查格式呢?只是好奇。
  • 以什么方式更好?您是否担心不存在的日期?还是要允许其他日期格式?
  • 你到底想做什么?人们为此提供了一些完全有效的正则表达式。如果你只是想检查格式,这些基本上都可以。如果你想检查日期的完整性,你需要做更多的事情。如果您想实际检查日期的有效性,甚至更多。我们可以安全地假设数据库没有将其存储在日期字段中并且数据可能无效吗?
  • 是的,从数据库中验证日期是没有意义的,除非它们被存储为字符串——但为什么会这样呢?!如果你想把它们拆开,那么最好找出你的数据库把它们放在哪种格式中,然后编写一个正则表达式。

标签: perl date format


【解决方案1】:

OWASP Validation Regex Repository 的美国格式日期版本,支持闰年:

^(?:(?:(?:0?[13578]|1[02])(/|-|.)31)\1|(?:(?:0?[1,3-9 ]|1[0-2])(/|-|.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\ d{2})$|^(?:0?2(/|-|.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?( ?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$ |^(?:(?:0?[1-9])|(?:1[0-2]))(/|-|.)(?:0?[1-9]|1\d| 2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

Regular Expression Library 包含与其他建议类似的更简单的版本,已翻译为您的问题:

^\d{4}-\d{1,2}-\d{1,2}$

【讨论】:

    【解决方案2】:

    正如其他人所指出的,如果这是来自数据库的日期字段,它应该采用明确定义的格式,因此您可以使用简单的正则表达式,例如 toolkit 提供的。

    但这样做的缺点是它会接受无效的日期,例如 2009-02-30。同样,如果您正在处理的日期成功地变成了数据库中的日期类型字段,那么您应该是安全的。

    更可靠的方法是使用 CPAN 中的众多日期/时间模块之一。可能 Date::Manip 是一个不错的选择,特别是检查 ParseDate() 函数。

    http://metacpan.org/pod/Date::Manip

    【讨论】:

    • Time::Piece(从 5.10 开始在核心中),有 strptime,POSIX::strptime 也是如此,Date::Manip(和 DateTime)对于这个任务来说有点重量级,安装 Date:: Manip 有点乱,因为 6.x 只到了 5.10+,并且 i 中添加了 5.x 版本。
    • Time::Piece 不检查诸如 2009-02-30 之类的内容! eval { my $t = Time::Piece->strptime('2009-02-30', "%Y-%m-%d" ); };
    【解决方案3】:

    怎么样

    /\d{2}\d{2}?-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/
    

    【讨论】:

      【解决方案4】:

      \d 可以匹配其他语言的数字字符。 YYY 真的是有效的年份吗?如果它必须是四位数,破折号,两位数,破折号,两位数,我更喜欢/^[0-9]{4}-[0-9]{2}-[0-9]{2}$//^[12][0-9]{3}-[0-9]{2}-[0-9]{2}$/。请注意要匹配的字符串周围的空格字符。

      当然,除了第二个例子中的第一个字符之外,这并不会检查那里的字符的合理性。如果需要,最好将其传递给日期解析模块,然后检查其输出以获取逻辑结果。

      【讨论】:

        【解决方案5】:

        最好的轻量级解决方案是使用 Date::Calccheck_date 子例程,这是一个示例:

        use strict;
        use warnings
        use Date::Calc qw[check_date];
        
        ## string in YYYY-MM-DD format, you can have any format
        ## you like, just parse it
        my @dt_dob = unpack("A4xA2xA2",$str_dob_date);
        
        unless(check_date(@dt_dob)) {
            warn "Oops! invalid date!";
        }
        

        希望对你有所帮助:-)

        【讨论】:

          【解决方案6】:

          你可以从以下开始:

          /\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|30|31)/ 
          

          【讨论】:

            【解决方案7】:

            我强烈建议您不要编写自己的正则表达式来执行此操作。日期/时间解析很简单,但有一些棘手的方面,这是一个已经解决了数百次的问题。无需您设计、编写和调试另一个解决方案。

            如果你想要一个正则表达式,最好的解决方案可能是为 Regexp::Common 模块使用我的 Regexp::Common::time 插件。您可以指定简单或复杂、严格或模糊的日期/时间匹配,并且它具有非常广泛的测试套件。

            如果您只想解析特定的日期格式,最好使用 Dave Rolsky 出色的 DateTime 模块的众多解析/格式化插件之一。

            如果您想在匹配后验证日期/时间值,我建议您使用 Time::Normalize 模块。

            希望这会有所帮助。

            【讨论】:

              【解决方案8】:

              我认为使用没有外部检查的正则表达式非常复杂!我用一个小子来得到它:

              sub check_date {
                  my $date_string = shift;
              
                  # Check the string fromat and get year, month and day out of it.
                  # Best to use a regex.
                  return 0 unless $date_string =~ m/^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
                  
                  # 31. in a month with 30 days
                  return 0 if ($3 >= 31 and ($2 == 4 or $2 == 6 or $2  == 9 or $2 == 11));
                  # February 30. or 31.
                  return 0 if ($3 >= 30 and $2 == 2);
                  # February 29. in not a leap year.
                  return 0 if ($2 == 2 and $3 == 29
                               and not ($1 % 4 == 0 and ($1 % 100 != 0 or $1 % 400 == 0)));
                  
                  # Date is valid
                  return 1;
              }
              

              我从regular-expressions.info 得到了这个想法(以及大部分代码)。还有其他例子。

              【讨论】:

                猜你喜欢
                • 2011-04-06
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多