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 )