Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

sorting dates in YYYYMMDD format

by learner@perl (Novice)
on Jul 04, 2013 at 06:57 UTC ( #1042344=perlquestion: print w/ replies, xml ) Need Help??
learner@perl has asked for the wisdom of the Perl Monks concerning the following question:

Hi Masters,

All i am trying to sort the dates which are in format YYYYMMDD format

#!/usr/bin/perl @dates = ('20130401', '20130501', '20130601'); @ordered = sort { &compare } @dates; sub compare { $a =~ /(\d{4})(\d{2})(\d{2})/; $c = $3 . $2 . $1; $b =~ /(\d{4})(\d{2})(\d{2})/; $c = $3 . $2 . $1; $c <=> $d; } print "@ordered\n";

The output which i got after executing the code

20130501 20130401 20130601

The exepected output is

20130501 20130401 20130601

Any solutions for this, thanks in advance

Comment on sorting dates in YYYYMMDD format
Select or Download Code
Re: sorting dates in YYYYMMDD format
by hdb (Prior) on Jul 04, 2013 at 07:09 UTC

    On of the great things about YYYYMMDD is that if you sort it numerically you get it properly sorted. So just do

    @ordered = sort { $a <=> $b } @dates;

    Comment: your expected output is as wrong as your output you get, they are identical... And in your code, $d is never defined. And the example is badly chosen as all parts are identical apart from the month. In this case, it does not matter, whether year is at the beginning or at the end.

    UPDATE: Even if you sort string-wise you are fine, so sort @dates does the job.

      One of the great things about YYYYMMDD is that if you sort it lexicographically you get it properly sorted!
      @ordered = sort @dates;
        One of the great things about YYYYMMDD is that if you sort it lexicographically you get it properly sorted!

        Yes! This is what bugs me about all the international date "standards" -- none of them sort naturally. The only tweak I use is for human readability, YYYYMMmmmDD, where mmm is the 3 letter abbreviation (in the language of choice), which helps the mildly dyslexic distinguish 5 March and 3 May (though maybe that's the hardest one).

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: sorting dates in YYYYMMDD format
by Corion (Pope) on Jul 04, 2013 at 07:11 UTC

    Please describe in your own words what the variables $c and $d are supposed to contain. Maybe print them out to verify your assumptions.

    Have you noticed that dates in YYYYMMDD format can be sorted directly with sort? This is one of the major advantages of using YYYYMMDD as a date format.

Re: sorting dates in YYYYMMDD format
by 2teez (Priest) on Jul 04, 2013 at 07:12 UTC

    Hi learner@perl,
    Since your output 20130501 20130401 20130601 is the same with what you want what 20130501 20130401 20130601 what next? You have solved your own problems. Except your expected output is different.

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
      Hi Masters.

      I solved the problem

      @dates = ('20130601', '20130401', '20130501'); my @sorted = map $_->[0], sort { $a->[1] cmp $b->[1] } map [ $_, join('', (/(..)(..)(....)/)[0,1,2]) ], @dates; # DD-MM-YYYY print "@sorted\n";

      Output

      20130401 20130501 20130601

      Thanks all

        Do you realize, that

        join('', (/(..)(..)(....)/)[0,1,2])

        does not change a string $_ of length 8 in any way? (Apart from burning CPU cycles...). The regex also does not fit very well when splitting YYYYMMDD into pieces.

        ..I solved the problem..
        Good... but why not just use sort just as you have been told previously on this post.
        Yes your regexes matched successfully, see

        but even at that it a lot of work.
        However, if you must use "Schwartzian transform", you can sort on the month, since the year is the same like this:
        use warnings; use strict; my @dates = ('20130601', '20130401', '20130501'); print join ' ' => map{$_->[0]} sort{$a->[1] <=> $b->[1]} map{/.{4}(.{2})/;[$_,$1]} @dates;
        But sincerely, for this use sort just like other monks told you.

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me
Re: sorting dates in YYYYMMDD format
by Dallaylaen (Scribe) on Jul 04, 2013 at 12:30 UTC

    I've turned on warnings because I didn't get what's wrong with your code (which looks correct at first glance) and suddenly...

    -bash$ xsel -o | perl -w Name "main::d" used only once: possible typo at - line 9. Use of uninitialized value $d in numeric comparison (<=>) at - line 9. Use of uninitialized value $d in numeric comparison (<=>) at - line 9. 20130601 20130501 20130401

    It looks like $d is never initialized in the first place, and evaluates to 0 in a numeric comparison. So to make life a bit easier, I would suggest always turning on strict and warnings:

    #!/usr/bin/perl use strict; use warnings; # or just #!/usr/bin/perl -w on first line my @dates = ('20130401', '20130501', '20130601'); my @ordered = sort { &compare } @dates; print "@ordered\n"; sub compare { $a =~ /(\d{4})(\d{2})(\d{2})/; my $c = $3 . $2 . $1; $b =~ /(\d{4})(\d{2})(\d{2})/; my $d = $3 . $2 . $1; $c <=> $d; }
    And now typing $c instead of $d makes program crash on the compilation stage, instead of silently corrupting data. Also note the "my" keyword - in strict mode you have to declare your variables, instead of just using them (and probably destroying previous data). ($a and $b are special vars that require no "my" though).
Re: sorting dates in YYYYMMDD format
by sundialsvc4 (Abbot) on Jul 05, 2013 at 02:06 UTC

    Don’t make this harder than it needs to be.   The reason for using a YYYYMMDD format is that it can “just be sorted as-is,” whether numerically or as a string.   Breaking it down into three groups, only to concatenate them in the same order, does nothing at all.   If you need to isolate the string from a bigger string, a simple pattern looking for 8 consecutive digits will do it.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1042344]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2014-10-24 07:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (130 votes), past polls