quinekxi
quinekxi

Reputation: 889

How to compare string date time in perl?

I have this date time format in string "11:56:41, 11/22/2011".

Here's what I want:

Compare two date time strings like.

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

Any ideas how could i achieve this in perl?

Upvotes: 5

Views: 44777

Answers (6)

ikegami
ikegami

Reputation: 385655

An efficient method is to reorder the fields to something lexically comparable.

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 {
   ...
}

Upvotes: 11

Will
Will

Reputation: 1770

I use unixtime. :)

I convert both times to unixtime and then I just have two integers to compare and so I can use the operators <, ==, > etc

e.g. convert to unixtime as follows

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);

Upvotes: 2

daxim
daxim

Reputation: 39158

What, already 4 hours and not a single DateTime (all hail the mighty DateTime) answer in sight? You're slacking, subscribers… ☻

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";
}

The method parse_datetime returns instances of DateTime whose comparison operators and stringification are overloaded to DTRT.

Upvotes: 9

stevenl
stevenl

Reputation: 6798

One more solution that uses the overloaded comparisons after converting the times to Time::Piece objects. Creating the objects may be overkill for something simple, but they can become very useful if you need to do other things with the times.

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...
}

Upvotes: 15

Ray Toal
Ray Toal

Reputation: 88378

Convert the datetimes (in your case these are local datetimes because they have no time zones) into ISO8601 then you can do regular string comparison.

To perform the conversion, you should extract the six components from your format

HH:MM:SS, mm/DD/YYYY

and reassemble them into ISO 8601:

YYYY-MM-DDTHH:MM:SS

Then a normal lexicographic comparison will work.

See http://codepad.org/berle9um

Repeated here:

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";
}

ADDENDUM

  • ikegami's Perl code is much better.
  • A date library would be your friend here; simply specify a format string and use the library's parse function to get your date object, which it should then be able to compare directly. (That said, it is always fun to point out that ISO8601 is, by design, sortable in string form.)

Upvotes: 2

Drav Sloan
Drav Sloan

Reputation: 1562

In this instance I've always used Date::Calc:

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) { ... }

Upvotes: 1

Related Questions