【问题标题】:What's a Perl regex to convert dates like 'Dec 26 2012 12:00AM' to yyyymmdd?什么是 Perl 正则表达式,可以将“2012 年 12 月 26 日 12:00AM”等日期转换为 yyyymmdd?
【发布时间】:2012-09-13 21:36:32
【问题描述】:

我已经非常努力地寻找使用 Perl 正则表达式进行这种特殊转换(这些日期格式)的示例,但无济于事。有人可以帮我在这些格式之间转换日期吗?

Dec 26 2012 12:00AM ==>  201212126

以下是我最初的尝试,但运行速度太慢(显然,我使用 substr 5 次,这太荒谬了)。

# Format the input time to yyyymmdd from 'Dec 26 2012 12:00AM' like format.
sub formatTime($)
{
    #Get passed in value of format 'Dec 26 2012 12:00AM'.
    my $col = shift; 

    if (substr($col, 4, 1) eq " "){
        substr($col, 4, 1) = "0";
    }

    return substr($col, 7, 4).$months{substr($col, 0, 3)}.substr($col, 4, 2);
}

注意:这是为了工作,用于将输入文件转换为非常大的数据库摄取,不幸的是,python 在我选择的脚本语言平台上不支持。我尝试制作自己的 Perl 正则表达式,但我只是没有时间在做其他部分时阅读并弄清楚它。昨天我已经浪费了大部分时间来编写 Perl 脚本并在剩余的时间里快速学习,这种转换花费了我太长时间。

【问题讨论】:

  • 单独的正则表达式无法将Dec 转换为12。 Perl 中没有可用的日期解析函数吗?
  • 不要自己动手。日期转换是一个已解决的问题。 CPAN 上有许多模块可以为您执行此操作,例如答案中引用的 DateTime 模块。

标签: regex perl datetime type-conversion


【解决方案1】:

我建议你使用模块 DateTime + DateTime::Format::Strptime

#!/usr/local/bin/perl
use strict;

use DateTime;
use DateTime::Format::Strptime;

my $strp = DateTime::Format::Strptime->new(
      pattern => '%b %d %Y %l:%M%p',
      locale  => 'en_US',
);

# convert date to 
my $date = 'Dec 26 2012 10:10AM';
my $dt   = $strp->parse_datetime( $date );
printf "%s -> %s\n", $date, $dt->strftime("%Y-%m-%d %H:%M");

输出

Dec 26 2012 10:10AM -> 2012-12-26 10:10

【讨论】:

    【解决方案2】:
    use strict;
    use warnings;
    
    my $str = "Dec 26 2012 12:00AM";
    
    my %months = (
        Jan => "01",
        [...]
        Dec => "12"
    );
    $str =~ /^(\w{3}) (\d{1,2}) (\d{4})/; 
    
    print $3.$months{$1}.$2;
    

    【讨论】:

    • 这是一段糟糕的代码,因为它缺少错误检查。在开始使用$1 等之前,您需要检查正则表达式是否实际匹配。此外,您应该检查您匹配的三个字符串实际上是一个有效的月份。即:if ($str =~ /^(\w{3}) (\d{1,2}) (\d{4})/ and exists $months{$1}) { print $3.$months{$1}.$2; } else { #error handling }
    【解决方案3】:

    那么,Dec 26 2012 12:00AM 的哪些部分很有趣?

    Dec    26   2012     12:00      AM
    $month $day $year $hour:$minute $pm
    

    所以我们只需定义简单的正则表达式,捕获有趣的信息,并将它们放入适当的变量中:

    my ($month, $day, $year, $hour, $minute, $pm)
      = ($string =~ m{
            (\w{3})   \s+             # 3 word characters
            (\d{1,2}) \s+             # 1 or 2 digits
            (\d{4})   \s+             # 4 digits
            (\d{2}) : (\d{2}) (AM|PM) # the hour, minute and AM/PM context
          }ix;
        );
    

    接下来,我们将月份设为数字并使用 AM/PM 信息:

    $month = {
      Jan => 1,
      Feb => 2,
      ...
      Dec => 12,
    }->{$month} or die "Unknown month $month";
    
    $hour += $pm =~ /pm/i ? 12 : 0; # if $pm contains "pm", then add 12 h
    

    然后,我们通过sprintf 构建一个适当的零填充字符串:

    my $format_string = "%04d%02d%02d" . ($include_hour ? "%02d%02d" : "");
    my $date = sprintf $format_string,
      $year, $month, $day, $hour, $minute;
    

    如果您有野心,您也可以轻松添加时区 ;-)

    当输入为16:00PM 时,此方法会产生奇怪的结果,因为这将输出2800 作为时间,这显然是错误的。如果这可能是一个问题,请仅对pm 进行更正if $hour <= 12。但是,这仅在 $include_hour 设置为真值时才重要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2014-04-26
      • 2015-05-23
      相关资源
      最近更新 更多