Question

I have a log file, which I want to read chunk by chunk as per time stamps (5 minutes of data, one at a time). Sample is

2014/04/24-23:29:20.003078-<String>
2014/04/24-23:29:32.003157-<String>
2014/04/24-23:29:33.004872-<String>
2014/04/24-23:29:43.005785-<String>

now I open the file and use the flip flop op to see if the line time stamp is between the 5 minutes. (I'll start with 2014/04/24-00:00:00 to 2014/04/24-00:05:00 for 1st chunk). But flip flop returns nothing. I am taking a DATE string as argument (like scr.pl 04/24/2014). My code is:

$curr = timelocal(0, 0, 0, (split /\//, $ARGV[0])[1], (split /\//, $ARGV[0])[0]-1, (split /\//, $ARGV[0])[-1]);
$currentTime = strftime "%Y/%m/%d-%H:%M:%S", localtime($curr); 
$curr += 300;
$nextTime = strftime "%Y/%m/%d-%H:%M:%S", localtime($curr);

    $file='Output.txt';
    open(INFO, $file) or die("Could not open  file.");
    foreach $line (<INFO>)  {
            print "$currentTime\n\n$nextTime";
            if (/$currentTime/../$nextTime/){
            $dataChunk = "$dataChunk\n$line"; #nothing gets added to $dataChunk
        }else{
              <DO SOME STUFF on DATACHUNK above>
            }
          }
     close(<INFO>);

Any ideas why there is nothing returned?


I am using the following code now. It works, but again its slow to what I expect .

$currentTime = timelocal(0, 0, 0, (split /\//, $ARGV[0])[1], (split /\//, $ARGV[0])[0]-1, (split /\//, $ARGV[0])[-1]);
$nextTime = $currentTime + 300;
            my $date = substr($line1,0,19); #2014/04/24-23:29:21
            my ($year,$mon,$mday,$hour,$min,$sec) = split(/[\s\/\-:]+/, $date); 
            my $time = timelocal($sec,$min,$hour,$mday,$mon-1,$year);
            if ($currentTime <= $time && $nextTime > $time)
Was it helpful?

Solution

Use Time::Piece along with Time::Seconds to work with the time stamp. It's a lot cleaner and easier to work with than raw parsing. Plus, it makes doing your output a bit more flexible.

I could never get the flip/flop operator to do what I want. Just use an if statement with the time range.

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw(say);
use autodie;

use Time::Seconds;
use Time::Piece;

use constant {
    START_TIME          => "2014/04/24-23:25:29",
    TIME_PERIOD         => 5,
    TIME_FORMAT         => "%Y/%m/%d-%H:%M:%S",
};

my $start_time = Time::Piece->strptime( START_TIME, TIME_FORMAT );
my $end_time   = $start_time + ( ONE_MINUTE * TIME_PERIOD );

while ( my $line = <DATA> ) {
    chomp $line;
    my $time_string = $line;
    $time_string =~ s/\..*//;
    my $time = Time::Piece->strptime( $time_string, TIME_FORMAT );
    if ( $time->epoch >= $start_time->epoch
            and $time->epoch <= $end_time->epoch ) {
        say "$line";
    }
}

__DATA__
2014/04/24-23:29:20.003078-<String>
2014/04/24-23:29:32.003157-<String>
2014/04/24-23:29:33.004872-<String>
2014/04/24-23:29:43.005785-<String>
2014/04/24-23:30:43.005785-<String>
2014/04/24-23:31:43.005785-<String>

OTHER TIPS

Personal preferences about the use of the flip-flop operator aside here are some things I see.

  1. Your regular expressions in the range flip-flop use the implicit $_ loop variable but you've explicitly told the foreach loop to use $line instead. Since there is nothing in $_ your flip-flop will always return false.

  2. You're use of the flip-flop with regular expressions means it will start and stop returning true only when it finds lines have the exact times you're looking for. Your input argument $ARGV[0] doesn't allow you to specify the time, only the date. The closest you can get is to pass in "04/24/2014" which will yield $currentTime == '2014/04/24-00:00:00' and $nextTime == '2014/04/24-00:05:00'. These times won't match any of the lines in your example input. Your update uses <= and >= instead but it could still use the flip-flop operator. This is the kind of thing it was designed for.

There are more problems though so turn on strict mode and warnings by adding the following to the top of your code:

use strict;
use warnings;

Once you've done this you'll see a bunch of syntax errors and warnings. They should lead you in the right direction. Then, debug and ask separate questions for each issue you encounter.

I'm not sure what you think // .. // will do, but I assure you it's not what you want here.

// contains a regular expression, and .. is the range operator. This means your if statement is doing this:

Compare $_ to a regex of /$currentTime/, and compare it to a regext of /$nextTime/, then returning a boolean value according to the scalar context use of the range operator:

It is false as long as its left operand is false. Once the left operand is true, the range operator stays true until the right operand is true, AFTER which the range operator becomes false again.

In your case, that means it will practically always return false, so the conditional is never executed.

What you need is to convert the time in each line into a meaningful time value, such as a unix epoch, or use the perl DateTime family of methods to do your date comparison.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top