Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

Sorting Dates

by josephjohn (Acolyte)
on Nov 24, 2005 at 10:26 UTC ( [id://511387] : perlquestion . print w/replies, xml ) Need Help??

josephjohn has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I am new to perl and need help in sorting dates. I have a text file with 50000 lines. One column is date in the format D/M/YYYY. I'm reading the file and making a hash for the date count. I would like to sort these dates before displaying them finally. I tried converting this to DD/MM/YYYY using regular expression but this obviously dosent work. I guess converting the date to YYYY/MM/DD, sorting and converting back is not a good idea also. I havent worked with date modules and can someone suggest which one to use Date::Calc or Date::Manip and how to use them with hash in my case. Thanks in advance. Joseph
foreach my $line (@file) { my @fields = split(/,/, $line); if ($fields[6] !~ /\d{2}\/\d{2}\/\d{4}/) { @tempdate = split(/\//, $fields[6]); if ($tempdate[0] < 10) { $newdate = "0" . $tempdate[0] . "/"; } else { $newdate = $tempdate[0] . "/"; } if ($tempdate[1] < 10) { $newdate = $newdate . "0" . $tempdate[1] . "/"; } else { $newdate = $newdate . $tempdate[1] . "/"; } $fields[6] = $newdate . $tempdate[2]; } $datecount{$fields[6]}++; } foreach my $date (sort(keys(%datecount))) { print "\n", $date, ": ", $datecount{$date}; }

Replies are listed 'Best First'.
Re: Sorting Dates
by demerphq (Chancellor) on Nov 24, 2005 at 12:20 UTC

    If you can then ditch the unsortable date format. Otherwise just transform the date before the sort and use the ISO format internally. Using non ISO compliant dates in computer software is inherently evil so doing this will be a net improvement (IMO) to your code. The sooner these regional date formats go the way of the steam engine the better. Something like the following regex should do it:


    With this representation used internally you can use lexicographical sorting on the keys of the hash. Ie:

    my @sorted=sort keys %hash;

    Alhough even here you are introducing year 10000 incompatibilities. If that worries you then you should use some other technique like the Swartzian Transform. Me, I tend to think that if they are still using my code 7000 years from now they deserve what they get.


Re: Sorting Dates
by Moron (Curate) on Nov 24, 2005 at 11:14 UTC
    Given that the dates are in one format but need to be sorted as if in another, you just need to control the behaviour of sort by inserting a sort block immediately after the sort keyword (see also sort command syntax). In this case it is also a good idea to make a separate reformatting subroutine - the conversion to dd/mm/yyyy you carry out earlier might also be yet another formatting subroutine if you want your code to look more readable. (updated to show a simple way to get the last date)
    my $lastdate; foreach my $date # n.b. $a and $b interpreted specially in a sort block ( sort { sFormat( $a ) <=> sFormat( $b ) } keys %datecount ) { print "\n", $date, ": ", $datecount{$date}; $lastdate = $date; # overwritten in order until last } sub sFormat { # convert dd/mm/yyyy into yyyymmdd my $old = shift; $old =~ /^(\d{2})\/(\d{2})\/(\d{4})$/ or die "Programming error: Invalid format $old\n"; return $3 . $2 . $1; }


    Free your mind

Re: Sorting Dates
by gjb (Vicar) on Nov 24, 2005 at 10:40 UTC

    If you want to go with your original approach, the following maybe useful:

    my @dates = qw(5/7/2001 3/10/2005 1/1/1996 2/1/1993); foreach my $date (@dates) { if ($date =~ m|(\d{1,2})/(\d{1,2})/(\d{4})|) { my $new_date = sprintf("%d/%02d/%02d", $3, $2, $1); ... } }

    Hope this helps, -gjb-

      Thanks for the suggestion gjb. Does that sort the hash too. I need to sort the dates, find the last date, and perform some calculations later in the script. Also please let me know what qw() is used for.

        This doesn't sort the hash, it only converts the date from D/M/YYYY to YYYY/MM/DD so that it can be used as a key in your %datecount hash. This hash can be sorted the way you do it in your code fragment.

        As to qw:

        $ perldoc -f qw qw/STRING/ Generalized quotes. See "Regexp Quote-Like Operators" in perlop.
        It returns a list of words without doing interpolation on them. It is just a convenient way of writing:
        my @dates = ('5/7/2001' '3/10/2005' '1/1/1996' '2/1/1993');

        Hope this helps, -gjb-

        >Does that sort the hash too

        You cannot sort a hash : a hash is by construction with no particular order. What you can do is sort the keys of a hash and print the corresponding values.

        When you do  foreach (keys %hash) you get the keys in an order that is undefined although always the same. But it will change if you add or remove keys, therefore if you need a specific order you should do  foreach ( sort { my sort function} keys %hash )

Re: Sorting Dates
by josephjohn (Acolyte) on Nov 24, 2005 at 14:47 UTC
    Thanks a lot to all of you for the suggestions. It is great to know that 1 or 2 lines of code can accomplish what i want.