Perl 将格式化日期转换为 y-m-d H:M

Perl converting formatting date to y-m-d H:M

我 运行 遇到将日期 Apr 9 2017 3:45:00:000AM 转换为 2017-04-09 03:45:00

的问题

这是我试过的。

use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new(pattern   => '%h %d %Y %H:%M',);
$start_date = $strp->parse_datetime('Apr  9 2017  3:45:00:000AM');

打印 2017-04-09T03:45:00 而不是 2017-04-09 03:45:00。试图获得 24 小时制,所以当我将 AM 切换到 PM 时,同时打印。

以下代码演示了如何在没有任何模块的情况下实现所需的输出

use strict;
use warnings;
use feature 'say';

my $date   = 'Apr  9 2017  3:45:00:000AM';
my @fields = qw/month mday year hour min sec usec/;
my %months = ( Jan => 1,  Feb => 2,  Mar => 3,
               Apr => 4,  May => 5,  Jun => 6, 
               Jul => 7,  Aug => 8,  Sep => 9, 
               Oct => 10, Nov => 11, Dec => 12
            );
my %parts;

@parts{@fields} = split "[ :]+", $date;

$parts{hour} += 12 if $parts{usec} =~ /PM/;
$parts{month} = $months{ $parts{month} };

printf "%04d-%02d-%02d %02d:%02d:%02d\n", 
       @parts{qw/year month mday hour min sec/};

借助模块的 Perl 代码

use strict;
use warnings;
use feature 'say';

use DateTime::Format::DateParse;
 
my($date, $dt);

$date = 'Apr  9 2017  3:45:00:000AM';
$date =~ s/:(\d{3}[AP]M)/./;

$dt = DateTime::Format::DateParse->parse_datetime( $date );

$date = $dt;
$date =~ s/T/ /;

say $date;

更新 请参阅结尾以获得 strptime 模式以正确解析显示的输入字符串格式


显示的内容有效, 因此显示的 DateTime::Format::Strptime constructor returns a DateTime object. But when an object is simply printed then one gets the stringification

因此您需要根据需要对其进行格式化以便打印。一般的方法是 strftime

say $start_date->strftime("%F %T");

其中 %F%T 都是简写,参见 strftime patterns

或者结合基本的ymdhms方法

say $start_date->ymd('-') . ' ' . $start_date->hms(':');

查看文档并根据需要调整 if/as。有些细节没看懂


在这个确切的例子中它只是偶然工作,因为在 new 中用于解析的模式对于显示的输入格式是错误的,并且是也不符合规定的要求

  • 显示的模式没有秒的格式说明符,也没有跟随它的毫秒的格式说明符,也没有以下 AM/PM 的格式说明符——所有这些都在输入字符串中。所以一般来说,所示形式的输入无法用所示模式正确解析

  • %H 匹配 00-23 小时,因此不是 12 小时制,这是按预期说明的,并且因 AM 的存在而隐含。 (它仍然匹配一个 12 小时制的数字,但一旦添加了缺少的 AM/PM 格式说明符,它就不会匹配。)

OP 中的模式有效并正确解析给定的输入,因为 03:45... 恰好是 在 AM,该模块使用正则表达式匹配给定字符串中任意位置的给定模式(默认情况下),因此 %H:%M 匹配 03:45 并且输入字符串的其余部分无关紧要。如果我们在构造函数中打开 strict 这将失败。请参阅文档。

假设显示的输入是我们需要的正确部分

my $strp = DateTime::Format::Strptime->new(
    pattern => '%h %d %Y %I:%M:%S%3N%p'
);

此处 %I 用于 12 小时制 (1-12),添加 %S 用于秒,%3N 用于毫秒(请参阅文档中的页面了解模式,链接上面),以及 %p 对于 AM/PM.

其余部分按原样工作,并以上面给出的所需格式打印。

您的代码有两个问题。首先,您用来解析日期的模式不正确:%H 用于 24 小时格式小时。相反,您应该结合使用 %i(12 小时)和 %pAM/PM)。其次,要打印一个 DateTime 对象,你应该先格式化它(例如使用 ->strftime->ymd())。

然而,日期中的毫秒数有点问题,因为 strptime 没有匹配毫秒数的选项。我建议先从你的日期中删除它们,然后才用 strptime:

解析日期
use DateTime::Format::Strptime;

my $date = 'Apr  9 2017  3:45:00:505PM';

# Removing milliseconds from date
$date =~ s/:(\d{3})(?=AM|PM)//; 
my $milliseconds = ;

my $strp = DateTime::Format::Strptime->new(pattern => '%h %d %Y %I:%M:%S%p',);
my $start_date = $strp->parse_datetime($date);

# Taking into account the milliseconds that were removed earlier
$start_date->add(seconds => 1) if $milliseconds > 500;


say $start_date->strftime("%F %T");