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

This is a problem I keep running into and I honestly don't know how to solve it properly. It seems like there must be an elegant solution. I have a list of dates in epoch format and I want to break them into hour/day/week/month chunks for reporting (charts/statistics) purposes. Here's the approach I'm using now. Is this a sane path or is there a better way?
use warnings; use strict; use DateTime; use Data::Dumper; my @times = qw( 1176992127 1177011950 1177035464 1177059040 1177063718 + 1177074117 1177100432 1177135347 1177165344 1177193537 1177202407 11 +77222982 1177224344 1177271548 1177280164 1177290568 1177320406 11773 +69446 1177392779 1177418018 1177424739 1177450967 1177459364 11774883 +49 1177506719 1177533725 1177544267 1177554850 1177596791 ); my %date_count; foreach my $time (@times) { my $dt = DateTime->from_epoch( epoch => $time ); $date_count{$dt->year}->{$dt->month}->{$dt->day}->{$dt->hour}+ ++; } print Dumper \%date_count; exit;

Replies are listed 'Best First'.
Re: Split date ranges/chunks based on Unix epoch time?
by ikegami (Patriarch) on Apr 26, 2007 at 03:42 UTC

    Looks fine to me, though I don't know why you got DateTime involved to do what localtime does.

    my @times = ...; my %date_count; foreach my $time (@times) { my ($y,$m,$d,$h) = (localtime($time))[5,4,3,2]; $date_count{$y+1900}{$m+1}{$d}{$h}++; } ...

    I suppose you could use a flatter structure, but it's doesn't leave the data in a format as useful as yours.

    use Time::Local qw( timelocal ); my @times = ...; my %date_count; foreach my $time (@times) { my ($y,$m,$d,$h) = (localtime($time))[5,4,3,2]; $date_count{timelocal(0,0,0,$d,$m,$y)}++; } ...
Re: Split date ranges/chunks based on Unix epoch time?
by GrandFather (Saint) on Apr 26, 2007 at 04:03 UTC

    Do you want to display the statistics at different levels of granularity (by year, by month, by day or by hour), or only by hour? If you are after "only hour", then I'd generate a single level hash using "$dt->year$dt->month$dt->day$dt->hour" as the key. If you want to access the stats at multiple levels I'd do something like:

    use warnings; use strict; use Date::EzDate; use Data::Dumper; my @times = qw( 1176992127 1177011950 1177035464 1177059040 1177063718 + 1177074117 1177100432 1177135347 1177165344 1177193537 1177202407 11 +77222982 1177224344 1177271548 1177280164 1177290568 1177320406 11773 +69446 1177392779 1177418018 1177424739 1177450967 1177459364 11774883 +49 1177506719 1177533725 1177544267 1177554850 1177596791 ); my %date_count; foreach my $time (@times) { my $dt = Date::EzDate->new ($time); $date_count{$dt->{year}}++; $date_count{"$dt->{year}/$dt->{monthnum}"}++; $date_count{"$dt->{year}/$dt->{monthnum}/$dt->{dayofmonth}"}++; $date_count{"$dt->{year}/$dt->{monthnum}/$dt->{dayofmonth} $dt->{h +our}"}++; } print "Year hits:\n", join ("\n", map {"$_ ($date_count{$_})"} sort grep {/^\d{4}$/} key +s %date_count), "\n"; print "Day hits:\n", join ("\n", map {"$_ ($date_count{$_})"} sort grep {m!^\d{4}/\d\d/ +\d\d$!} keys %date_count), "\n";

    Prints:

    Year hits: 2007 (29) Day hits: 2007/03/20 (5) 2007/03/21 (3) 2007/03/22 (5) 2007/03/23 (4) 2007/03/24 (2) 2007/03/25 (5) 2007/03/26 (4) 2007/03/27 (1)

    DWIM is Perl's answer to Gödel
Re: Split date ranges/chunks based on Unix epoch time?
by jwkrahn (Abbot) on Apr 26, 2007 at 05:54 UTC
    Since you only want hour granularity just divide the epoch time by the number of seconds in an hour:
    my %date_count; foreach my $time ( @times ) { $date_count{ ( $time / 3600 ) * 3600 }++; }
    Then later you can break it down into years/months/days/hours.
      Take care, that should then be
      my %date_count; foreach my $time ( @times ) { $date_count{ int( $time / 3600 ) * 3600 }++; }
      The division operator '/' doesn't do any implicit integer truncation - yes, I know C does... :)
        Yes, thank you, I forgot about that.    :-)
Re: Split date ranges/chunks based on Unix epoch time?
by Anonymous Monk on Apr 26, 2007 at 04:51 UTC
    I'm the parent poster. Thanks a lot ikegami and GrandFather. It just seemed like there might be a significantly better approach -- but your input did help me think about it more clearly. Thank you.
Re: Split date ranges/chunks based on Unix epoch time?
by Anonymous Monk on Apr 26, 2007 at 03:14 UTC
    What you're doing is bizzare, but maybe DateTime::Duration can help if you need to do math.