App-csvtool
view release on metacpan or search on metacpan
lib/App/csvtool/Timetools.pm view on Meta::CPAN
default => "%Y-%m-%dT%H:%M:%S" },
{ name => "utc|U", description => "Use UTC instead of local time" },
);
sub formattime ( $pkg, $opts, $time )
{
my $TIMEFMT = $opts->{timefmt};
my @t = $opts->{utc} ? gmtime( $time ) : localtime( $time );
return strftime( $TIMEFMT, @t );
}
sub parsetime ( $pkg, $opts, $str )
{
my $TIMEFMT = $opts->{timefmt};
my @t = ( strptime $str, $TIMEFMT )[0..5]; # take only sec-year, ignore wday/yday
grep { defined } @t or
warn( "Unable to parse '$str' as a timestamp\n" ), return undef;
# Fill in zeroes for undefined smaller fields
foreach my $i ( 0 .. 5 ) {
last if defined $t[$i];
$t[$i] = ( $i == 3 ) ? 1 : 0; # mday is 1-indexed
}
# TODO: warn if any of [0]-[5] left undefined
return $opts->{utc} ? timegm( @t[0..5] ) : mktime( @t[0..5] );
}
=head1 COMMANDS
=cut
package App::csvtool::strftime
{
use base qw( App::csvtool::Timetools );
=head2 strftime
$ csvtool strftime -fFIELD --timefmt=... FILE
Formats a timestamp by using a C<strftime> format, replacing the field with
the same time formatted as a string.
=head3 --field, -f
The field index to format the timestamp into (defaults to 1).
=cut
use constant COMMAND_DESC => "Format a timestamp from UNIX time";
use constant COMMAND_OPTS => (
__PACKAGE__->COMMON_COMMAND_OPTS,
{ name => "field|f=", description => "Field to use for timestamp",
default => 1 },
);
use constant WANT_READER => 1;
use constant WANT_OUTPUT => 1;
sub run ( $pkg, $opts, $reader, $output )
{
my $FIELD = $opts->{field}; $FIELD--;
while( my $row = $reader->() ) {
$row->[$FIELD] = __PACKAGE__->formattime( $opts, $row->[$FIELD] );
$output->( $row );
}
}
}
package App::csvtool::strptime
{
use base qw( App::csvtool::Timetools );
=head2 strptime
$ csvtool strptime -fFIELD --timefmt=... FILE
Parses a timestamp by using a C<strptime> format, replacing the field with the
same time expressed as a UNIX epoch integer.
=head3 --field, -f
The field index to parse the timestamp from (defaults to 1).
=cut
use constant COMMAND_DESC => "Parse a timestamp into UNIX time";
use constant COMMAND_OPTS => (
__PACKAGE__->COMMON_COMMAND_OPTS,
{ name => "field|f=", description => "Field to use for timestamp",
default => 1 },
);
use constant WANT_READER => 1;
use constant WANT_OUTPUT => 1;
sub run ( $pkg, $opts, $reader, $output )
{
my $FIELD = $opts->{field}; $FIELD--;
while( my $row = $reader->() ) {
$row->[$FIELD] = __PACKAGE__->parsetime( $opts, $row->[$FIELD] );
$output->( $row );
}
}
}
package App::csvtool::tsort
{
use base qw( App::csvtool::Timetools );
=head2 tsort
$ csvtool tsort -fFIELD --timefmt=... FILE
A variant of the basic C<sort> command that parses a timestamp from a field
and sorts rows in chronological order based on those timestamps.
=head3 --field, -f
The field index to parse the sorting timestamp from (defaults to 1).
=head3 --reverse, -r
Reverses the order of sorting.
=cut
use constant COMMAND_DESC => "Sort rows into chronological order by a timestamp";
use constant COMMAND_OPTS => (
__PACKAGE__->COMMON_COMMAND_OPTS,
{ name => "field|f=", description => "Field to use for timestamp",
default => 1 },
{ name => "reverse|r", description => "Reverse order of sorting" },
);
use constant WANT_READER => 1;
use constant WANT_OUTPUT => 1;
sub run ( $pkg, $opts, $reader, $output )
{
my $FIELD = $opts->{field}; $FIELD--;
my @rows;
while( my $row = $reader->() ) {
# Parse the timestamps on each line, rather than doing them all at
# once later using e.g. nsort_by {}, so that warnings come out at the
# right time
my $time = __PACKAGE__->parsetime( $opts, $row->[$FIELD] );
push @rows, [ $time, @$row ];
}
@rows = sort { $a->[0] <=> $b->[0] } @rows;
shift @$_ for @rows; # remove timestamp keys
if( $opts->{reverse} ) {
$output->( $_ ) for reverse @rows;
}
else {
$output->( $_ ) for @rows;
}
}
}
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;
( run in 0.812 second using v1.01-cache-2.11-cpan-39bf76dae61 )