I'm using Perl and have an input file with multiple dates such as 17/04/2021 written in it as text. How could I go about turning them into date formats and then comparing them to see which one is the most recent?
Input file format:
01/09/2020
23/10/2019
12/06/2022
15/08/2017
Perl Script:
#! /usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my $InputFile = "path/to/file.input";
open(FH, '<', $InputFile) or die $!;
while(my $Line = <FH>)
{
}
close(FH);
Thanks.
CodePudding user response:
strftime
is (always) your friend:
#!/usr/bin/env perl
# Sort timestamps
use 5.12.10;
use Time::Piece;
my $fmt='%d/%m/%Y';
my @t;
while( <DATA> ){
chop; # Delete newline
eval { push @t, Time::Piece->strptime($_, $fmt) } or say "Unexpected input: $_";
}
say $_->strftime($fmt) foreach sort @t;
__DATA__
01/09/2020
23/10/2019
12/06/2022
15/08/2017
CodePudding user response:
Here's one way:
#! /usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use Time::Local;
my $InputFile = $ARGV[0];
open(my $fh, '<', $InputFile) or die $!;
## A hash to hold the times so we can sort later
my %seconds;
while(my $Line = <$fh>){
chomp($Line);
my ($day, $month, $year) = split(/\//, $Line);
my $secondsSinceTheEpoch = timelocal(0, 0, 0, $day, $month-1, $year);
$seconds{$secondsSinceTheEpoch}
}
close($fh);
my @sortedSeconds = sort {$a <=> $b} keys(%seconds);
print "$sortedSeconds[0]\n";
Or, if you're into the whole brevity thing:
#! /usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use Time::Local;
## A hash to hold the times so we can sort later
my %seconds;
while(<>){
chomp();
my ($day, $month, $year) = split(/\//);
$seconds{timelocal(0, 0, 0, $day, $month-1, $year)}
}
my @sortedSeconds = sort {$a <=> $b} keys(%seconds);
print "$sortedSeconds[0]\n";
In both cases, you need to pass the file to the script as an argument:
$ foo.pl file
1502744400
CodePudding user response:
Dates in the format yyyymmdd
can be just compared directly, numerically or lexically. So turn it around
use warnings;
use strict;
use feature 'say';
# use List::Util qw(max);
my @dates;
while (<>) {
chomp;
push @dates, join '', reverse split '/';
}
@dates = sort { $a <=> $b } @dates; # latest: $dates[-1]
say for @dates;
# Or, if only the last one is needed (uncomment 'use' statement)
# my $latest_date = max @dates;
The "diamond operator" <>
reads line by line files submitted on the command line, when used in scalar context. The split argument for the separator is still a regular expression even as I use ''
delimiters instead of /\//
, for convenience. (Its other argument is by default $_
variable.) Also see
reverse,
join,
sort, and List::Util, as needed.
Can do it in a commnad-line program ("one-liner") as well
perl -wnlE'push @d, join "", reverse split "/"; }{ say for sort @d' file
where }{
stands for the beginning of END { }
block. Or
perl -MList::Util=max -wnlE'... }{ say max @d' file
If you'd like it more compact,
use warnings;
use strict;
use feature 'say';
say for sort map { chomp; join '', reverse split '/' } <>;
That same diamond operator in the list context returns all lines at once.
Or on the command line
perl -wE'say for sort map { chomp; join "", reverse split "/" } <>' file