views:

381

answers:

5

I have several thousand objects with a string property in the format of "yyyy-MM-ddTHH:mm:ssZ". I want to sort these objects by time.

Are there any useful packages or scripts for this?

(Currently I'm just comparing individual numeric values and it seems it's not very efficient and neat.)

+4  A: 

Timestamps in that format can be sorted lexicographically, so normal perl "sort" and the string comparison function "cmp" are sufficient.

Stuart Sierra
@Stuart: I also thought so at first, but would'nt the timezone part (Z) could raise some problem ?
kriss
@kriss: but that's the last character so it would mean that everything else is equal
kemp
@kemp: yes, that's the problem, what is before is equal but if it's not related to the same reference time comparing can give wrong result.
kriss
+5  A: 

sort without a sorting function sorts in lexicographical order. It fulfills your needs.

@sorted = sort @timestamps;
codeholic
I think he wants to sort the list by time first, not date.
Zaid
sorry for the confusion. I want to sort them by datetime.
ablimit
The major advantage of the ISO-8601 order for timestamps all in the same time zone (Z, Zulu or UTC in the example) is that they can be sorted alphanumerically into date/time order. If you have multiple timezones to deal with, that is a nuisance (you need to convert them all to UTC, which is not wholly trivial, and then sort the UTC values). But timezones = trouble generally.
Jonathan Leffler
A: 

If you need to compare the timestamps numerically, you can convert them to numbers using the core Time::Local module:

use Time::Local;

sub get_num {
    $_[0] =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/;
    return timegm($6, $5, $4, $3, $2 - 1, $1);
}
eugene y
`Z` means UTC, so the proper conversion function would be `timegm`, not `timelocal`.
cjm
@cjm: thanks {padding}
eugene y
+3  A: 

You can use Time::Local to convert your date to timestamp or one of the Date:: modules from cpan. You can have a look at this to see what is available.

Also notice that with the above format sorting the objects lexicographicaly would also do the trick (even if probably somewhat slower than comparing numbers, but initial conversion has it's cost).

Be careful if you use dates from throughout the world because you may encounter sort problems with timezone and daylight savings. If all datetimes are in the same place that should be OK.

kriss
A: 

Provided your string format is rigid, you can use the following subroutine to sort out your list of dates.

sub timeSort {

    my ($time) = ( shift =~ /\d{2}:\d{2}:\d{2}/ );
    return $time;
}

my @sortedList = sort { timeSort($a) <=> timeSort($b) } @oldList;
Zaid
`$_[0]` instead of using `shift` might be faster (since it will be called many times for sort). Otherwise, that's how I'd do it too.
Romuald Brunet