如何在Perl中将字符串解析为DateTime对象?

40
我知道关于DateTime Perl模块,以及许多DateTime::Format::模块来解析特定类型的日期/时间格式。但是,对于一些日期/时间字符串的示例,我如何在编码/设计时(而不是运行时)确定应使用哪个特定模块?
例如,我想解析像这样的字符串:October 28, 2011 9:00 PM PDT 是否有一个列表,列出了最常见的日期/时间格式,我可以在其中查找并找到最合适的模块?
我也知道一些模块会尝试在运行时“猜测”每个给定字符串的格式,并尽力而为。但是,对于敏感的应用程序,我希望在设计应用程序时首先确定格式,然后使用一个模块,该模块将在字符串不符合指定格式时提醒我。
我该怎么做?

1
据我所知,您无法可靠地解析时区缩写。以CST为例。 - x-yuri
5个回答

48

DateTime::Format::Strptime 将日期/时间字符串解析为 DateTime 对象。

#!/usr/bin/perl

use strict;
use warnings;

use DateTime::Format::Strptime;

my $parser = DateTime::Format::Strptime->new(
  pattern => '%B %d, %Y %I:%M %p %Z',
  on_error => 'croak',
);

my $dt = $parser->parse_datetime('October 28, 2011 9:00 PM PDT');

print "$dt\n";

模式中使用的字符序列是 POSIX 标准。详情请参见“man strftime”。


谢谢!这就是最终我所做的。不过,我很想看到一个常见或标准日期格式(ISO、RFC)的列表,以便检查我拥有的某些特定字符串是否符合其中任何一种。 - Juan A. Navarro
这里有一个(已过时的)DateTime模块列表(其中包括许多DT :: Format模块),网址为http://datetime.perl.org/wiki/datetime/page/Modules。 - Dave Cross
1
不是一个很喜欢必须非常精确地指定格式的人。 - MikeKulls
解析时区缩写是否安全? - x-yuri

36

我倾向于使用Time::Piece,因为它从Perl版本5.10开始是标准模块的一部分。

它具有无与伦比的解析日期字符串的能力

my $time = Time::Piece->strptime(
      "October 28, 2011 9:00 PM PDT",
      "%B %d, %Y %r %Z");

遗憾的是,在版本5.8中,它不是标准Perl模块集的一部分(这仍然是您可以在RHEL 5.x上运行的最高版本)。但是在5.14中有。 - Chris R. Donnelly
1
“这并不是真的。虽然 RHEL 5.x 自带 Perl 5.8.8,但你完全可以构建一个更新版本。” - Dave Cross
3
@DaveCross Chris提出了一个很重要的观点。在RPM之外安装新版本的Perl并不总是可行的。RHEL机器通常用于企业生产环境(否则,您会使用Fedora或Centos)。这些系统通常不会安装完整的_开发工具_,例如C编译器,您可能无法访问它们以安装工具,即使您可以,运行生产环境的人员也可能看不起在生产环境中安装非官方版本的Perl的人。 - David W.
2
@DavidW:我不能反驳其中任何一点。但这距离说你不能运行比5.8.8更新的任何东西还有很长的路要走。从技术上讲,没有什么能阻止你这样做。从政治上讲,可能会有。 - Dave Cross
1
感谢您让我注意到Time::Piece!这是一个很棒的模块。例如,如果您想要用一种外语输出星期几,您可以编写my $day = Time::Piece->strptime($isod, "%Y-%m-%d")->day(qw/Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag /); - lanti
显示剩余5条评论

16

可以看一下Date::Parse模块,即str2time()函数。它支持常用格式中的大部分

例如:

use Date::Parse;
use DateTime;

my $str = "Tue, 20 Sep 2011 08:51:08 -0500";
my $epoch = str2time($str);
my $datetime = DateTime->from_epoch(epoch => $epoch);

2
谢谢,但这恰恰不是我想要做的。我不希望函数猜测字符串的格式;我希望能够精确地指定代码应该期望的格式。 - Juan A. Navarro
1
很好,那正是我想要做的事情 :-) 我会推荐一个格式,但如果有人有所变动,我们会尽力配合。 - MikeKulls
事实上,那个模块看起来并不是很好。它将15/4/2015解析为1429060633,但将15/apr/2015解析为1429020000。很难想象它在这里到底在做什么,因为只是解析日期就有11.28小时的差异。应该没有时间成分。 - MikeKulls
存在一些非美国日期格式的错误。对于我的日期格式(30/10/2000)没有用。错误 当日期中同时指定月份和日期时,它们总是被解析为月份数字在日期数字之前的格式。这是美国日期中通常使用的格式。 “错误”章节的文档链接 - user3439968

4
如果你正在寻找常见的日期/时间格式,请查看DateTime::Locale
use DateTime::Locale
my $locale = DateTime::Locale->load('DE_de');

The following methods return strings appropriate for the DateTime->format_cldr() method:

$locale->date_format_full()
$locale->date_format_long()
$locale->date_format_medium()
$locale->date_format_short()
$locale->date_format_default()
$locale->time_format_full()
$locale->time_format_long()
$locale->time_format_medium()
$locale->time_format_short()
$locale->time_format_default()
$locale->datetime_format_full()
$locale->datetime_format_long()
$locale->datetime_format_medium()
$locale->datetime_format_short()
$locale->datetime_format_default()
你可以使用DateTime::Format::CLDR模块来解析日期。
use DateTime::Format::CLDR;
# 1. Basic example
my $cldr = DateTime::Format::CLDR->new(
    pattern     => 'dd.MM.yyyy HH:mm:ss',
    locale      => 'de_DE',
    time_zone   => 'Europe/Berlin',
);
my $dt = $cldr->parse_datetime('26.06.2013 11:05:28');

0

DateTime::Format::Natural 也是一个不错的选择。

测试:

perl -MDateTime::Format::Natural \
-E "my $d=DateTime::Format::Natural->new->parse_datetime('October 11, 2021'); say $d->month;"

10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接