如何解析ISO8601兼容字符串到perl的DateTime对象?

问题描述:

我的最终目标是将当前日期和时间与ISO8601格式的TVMaze API返回的日期和时间进行比较,以确定是否播放了新的电视节目。如何解析ISO8601兼容字符串到perl的DateTime对象?

use strict; 
use warnings; 
use feature 'say'; 
use DateTime; 
my $curmytime = DateTime->now()->format_cldr("yyyy-MM-dd'T'HH:mm:ssZ"); 
# Output is: Time now in UTC:2017-07-17T10:44:52+0000 
say "Time now in UTC:". $curmytime; 
my $strtobeparsed = '2017-04-09T21:00:00-0400'; 
# Next, parse the string "2017-04-09T21:00:00-0400" to a DateTime object 

如何解析字符串为DateTime对象?

+0

该格式似乎不被默认的DateTime ::格式:: ISO8601被包括在内。请参阅https://metacpan.org/pod/distribution/DateTime-Format-ISO8601/lib/DateTime/Format/ISO8601.pod#5.4.1。最简单的方法是推出自己的解析器。 – simbabque

+0

以* extended *格式(带有连字符和冒号分隔符)和* basic *格式的时区具有日期和时间是非常奇怪的。你确定不应该是'-04:00'吗? – Borodin

+0

@Borodin,是的,'format_cldr(“yyyy-MM-dd'T'HH:mm:ssZ”)'没有冒号就返回它。我不得不从API字符串中删除冒号来比较两者。 – Droidzone

DateTime does not parse dates and times。为此,您需要使用DateTime :: Format :: namespace中的许多模块之一。如果没有可用的,你可以简单地使用DateTime::Format::Strptime。给它一个pattern并交给它一个字符串,它会为你创建一个DateTime对象。

use DateTime::Format::Strptime; 
my $format = DateTime::Format::Strptime->new(pattern => '%FT%T%z'); 
my $dt = $format->parse_datetime('2017-04-09T21:00:00-0400'); 

然后,您可以将它与另一个DateTime进行比较。

print "ok" if $dt < DateTime->now; 

如果你想将其转换成自己的类,这是相当微不足道了。

package DateTime::Format::TVMaze; 
use strict; 
use warnings; 
use DateTime; 
use parent 'DateTime::Format::Strptime'; 

sub new { 
    my $class = shift; 
    my %params = @_; 

    $params{pattern} = '%FT%T%z'; 

    return $class->SUPER::new(%params); 
} 

现在你可以使用它像这样

my $dt = DateTime::Format::TVMaze->new->parse_datetime('2017-04-09T21:00:00-0400'); 
+1

谢谢。模块POD似乎表明它必须首先转换为UTC,然后才能比较日期。 – Droidzone

+0

@Droidzone很有可能。 – simbabque

+0

@ikegami是的。在这种情况下,已经有DateTime :: Format :: ISO8601准备好了,但缺少的冒号是这里的问题。鲍罗廷在对这个问题发表评论时提到。 – simbabque