2011-11-22 60 views
5

我在字符串“11:56:41,11/22/2011”中有这个日期时间格式。如何比较perl中的字符串日期时间?

这是我想要的:

比较两个日期时间字符串。

$date1 = "11:56:41, 11/22/2011"; 
$date2 = "11:20:41, 11/20/2011"; 
if($date2 < $date1) { 
    do something... 
} else { 
    do nothing... 
} 

任何想法我怎么能在perl中实现这一点?

回答

11

一种有效的方法是将字段重新排序以进行词汇比较。

sub to_comparable { 
    my ($date) = @_; 
    my ($H,$M,$S,$d,$m,$Y) = $date =~ m{^([0-9]{2}):([0-9]{2}):([0-9]{2}), ([0-9]{2})/([0-9]{2})/([0-9]{4})\z} 
     or die; 
    return "$Y$m$d$H$M$S"; 
} 

if (to_comparable($date2) lt to_comparable($date1)) { 
    ... 
} else { 
    ... 
} 
+3

因为我们不知道单个数字日/月/小时/分钟是否为零填充,所以返回sprintf可能会更好('%04d%02d%02d%02d%02d $ 02d' ,$ Y,$ m,$ d,$ H,$ M,$ S) – bigiain

+0

@ikegami谢谢!这是最简单的答案,它的工作! – quinekxi

+0

@bigiain我遇到了一个小问题,只是一个简单的问题(我想没有必要再创建一个)如果我要比较的日期是非零填充的,那么该怎么办? – quinekxi

1

将日期时间(在你的情况下,这些是本地日期时间,因为他们没有时区)转换成ISO8601,然后你可以做常规字符串比较。

来执行转换,你应该从你的格式

HH:MM:SS, mm/DD/YYYY 

提取六种组分,并将它们重新组合成ISO 8601:

YYYY-MM-DDTHH:MM:SS 

然后一个正常的字典比较会工作。

http://codepad.org/berle9um

此重复:

sub my_format_to_iso8601 { 
    $_[0] =~ /(\d\d):(\d\d):(\d\d), (\d\d)\/(\d\d)\/(\d\d\d\d)/; 
    return "$6-$4-$5T$1:$2:$3"; 
} 

$date1 = "11:56:41, 11/22/2011"; 
$date2 = "11:20:41, 11/20/2011"; 
$d1 = my_format_to_iso8601($date1); 
$d2 = my_format_to_iso8601($date2); 
print "first is $d1\n"; 
print "second is $d2\n"; 
if ($d2 < $d1) { 
    print "second is earlier\n"; 
} else { 
    print "first is earlier\n"; 
} 

附录

  • 池上的Perl代码要好得多。
  • 日期库将成为你的朋友,只需指定一个格式字符串并使用库的解析函数来获取您的日期对象,然后就可以直接进行比较。 (也就是说,指出ISO8601在设计上可以按照字符串形式排序总是很有趣的。)
+0

谢谢,它确实对我有用。你的代码和ikegami之间没有太大的区别。两者都运作良好。 :D – quinekxi

1

在这种情况下我一直使用Date::Calc:该次转换为Time::Piece对象后使用的覆盖比较

use Date::Calc; 

my $date1 = "11:56:41, 11/22/2011"; 
my $date2 = "11:20:41, 11/20/2011"; 

my @date1arr=split /[^\d]/, $date1 if($date1 =~ m!\d{2}:\d{2}:\d{2}, \d{2}/\d{2}/\d{4}!; 
my @date2arr=split /[^\d]/, $date2 if($date2 =~ m!\d{2}:\d{2}:\d{2}, \d{2}/\d{2}/\d{4}!; 

my @diff = Delta_DHMS(@date1arr, @date2arr); 
my $less; 
foreach my $d (@diff) { $less = 1 if $d < 0; } 

if($less) { ... } 
+0

这很有效,但Date :: Calc对于这里的简单情况非常重量级。 ikegami的解决方案工作(至少在问题中给出的有限问题空间),而不需要加载所有Date :: Calc(在我的机器上可能不显着〜300 ms ...) – bigiain

12

还有一个解决方案。创建对象可能会过于简单,但如果您需要根据时间做其他事情,它们会变得非常有用。

use Time::Piece; 

my $dateformat = "%H:%M:%S, %m/%d/%Y"; 

my $date1 = "11:56:41, 11/22/2011"; 
my $date2 = "11:20:41, 11/20/2011"; 

$date1 = Time::Piece->strptime($date1, $dateformat); 
$date2 = Time::Piece->strptime($date2, $dateformat); 

if ($date2 < $date1) { 
    do something... 
} else { 
    do nothing... 
} 
+1

+1 [Time :: Piece](https://metacpan.org/module/JHI/perl-5.7.2/ext/Time/Piece/Piece.pm),这是一个日期管理模块,它已经内置于Perl –

5

什么,已经4小时,不是一个单一的DateTime(所有冰雹强大DateTime)在视线的答案吗?你消极怠工,用户...☻

use DateTime::Format::Strptime qw(); 
my $p = DateTime::Format::Strptime->new(pattern => '%T, %D', on_error => 'croak',); 

my $date1 = $p->parse_datetime('11:56:41, 11/22/2011'); 
my $date2 = $p->parse_datetime('11:20:41, 11/20/2011'); 

if($date2 < $date1) { 
    say "$date2 comes before $date1"; 
} else { 
    say "$date2 does not come before $date1"; 
} 

parse_datetime返回DateTime其比较运营商和字串符重载,来DTRT实例的方法。

+0

之内,不正常地,我的要求是我不会使用已安​​装的模块,除了已安装的perl软件包。无论如何。感谢您的输入:D – quinekxi

+0

为强大的日期时间! –

+1

因为这对手头的工作来说太过分了。 – ikegami

2

我使用unixtime。:)

我都转换次unixtime,然后我只是有两个整数比较,所以我可以使用运营商<,==>等

例如转换为unixtime如下

my $timestamp = "2014-03-25 12:33:32"; # (We assume localtime) 

# 
# To split on the space character, it's best to use the regex// 
# 
my ($date, $time) = split (/ /, $timestamp); 
my ($year, $mon, $mday) = split ('-', $date); 
my ($hour, $min, $sec) = split (':', $time); 

my $unixtime = timelocal($sec, $min, $hour, $mday, $mon-1, $year);