Perl:提取时间戳的开始和结束日期

Perl: Extracting begin and End date for timestamps

需要帮助提取以下日期和时间戳列表中的开始和结束日期
假设我从日志文件中提取了以下时间戳数据,并且只需要提取每个日期和时间的开始和结束。 输出将用于计算开始到结束之间的时间差。

数据
2021 年 11 月 16:27:39
2021 年 11 月 16:28:10
2021 年 11 月 16:30:47
2021 年 11 月 16:30:47
2021 年 12 月 09:27:03
2021 年 12 月 10:27:03
2021 年 12 月 18:22:15
2021 年 13 月 08:57:16
2021 年 13 月 08:57:37
2021 年 13 月 11:33:25
2021 年 13 月 11:33:25
2021 年 11 月 8 日 16:45:17
2021 年 11 月 8 日 16:49:10
2021 年 11 月 8 日 17:00:50
2021 年 11 月 8 日 22:10:24
2021 年 11 月 9 日 11:51:35
2021 年 11 月 9 日 11:52:40
2021 年 11 月 9 日 12:14:39
2021 年 11 月 9 日 14:23:10
...
...
...

预期输出
开始:2021 年 11 月 16:27:39
结束时间:2021 年 11 月 16:30:47
开始:2021 年 12 月 09:27:03
结束时间:2021 年 12 月 18:22:15
开始时间:2021 年 13 月 08:57:16
结束时间:2021 年 10 月 13 日 11:33:25
开始时间:2021 年 11 月 8 日 16:45:17
结束时间:2021 年 11 月 8 日 22:10:24
开始时间:2021 年 11 月 9 日 11:51:35
结束时间:2021 年 11 月 09 日 14:23:10


下面是我的脚本,但我只设法提取了开始数据

%key;
     while ( <IN> ) {
              $_=~ s/^\s+|\s+$//g; 
              my ($saved_date, $record_date);
              chomp ;
              my ($k, $d) = split;
               
                if (! exists $key{ $k } ) {
                    $key{ $k } = $d;
                    my ($dtformat) = $d =$dtformat;
                    $end_date = Time::Piece->strptime($_, $dtformat);
                    next;
                    
                    my ($dtformat) = $key{ $k } = $dtformat;
                    $saved_date = Time::Piece->strptime($_, $dtformat);
    
                    my ($dtformat) = $d =$dtformat;
                    $record_date = Time::Piece->strptime($_, $dtformat);
                    
                    if ( $record_date - $saved_date > 0 ) {
                       $key{ $k } = $d;
                    }
                }   
        }#endofwhile
        for ( sort keys %key ) {
             print "begin: ", $_, " ",$key{ $_ },"\n"; 

        }
     

输出
开始:2021 年 11 月 8 日 16:45:17
开始:2021 年 11 月 9 日 11:51:35
开始:2021 年 10 月 21:59:39
开始:2021 年 10 月 11 日 00:21:46
开始:2021 年 12 月 09:27:03
开始:2021 年 10 月 13 日 08:57:16
开始:2021 年 9 月 30 日 00:21:23

需要帮助如何获得“结束”部分

谢谢

秘诀在于您用来存储数据的数据结构。由于您对一天的第一个和最后一个时间戳感兴趣,因此我构建了一个以日期为键值的散列,其中值是一个包含当天所有时间戳的数组。然后我们可以对每一天的时间戳进行排序,并轻松提取最早和最晚的。

#!/usr/bin/perl

use strict;
use warnings;

use feature 'say';

use Time::Piece;

# The hash where we'll store our data
my %dates;
# The format of our dates
my $date_format = '%Y-%b-%d %H:%M:%S';

# Read each data item from DATA (or wherever)
while (<DATA>) {
  # Remove the newline
  chomp;

  # Parse the string into a Time::Piece object
  my $date = Time::Piece->strptime($_, $date_format);

  # Store the object in our hash of arrays
  push @{$dates{$date->ymd}}, $date;
}

# Get the list of hash keys sorted by date.
for (sort keys %dates) {
  # For each date key...
  # Get the sorted list of dates into an array...
  my @times = sort { $a->hms cmp $b->hms } @{ $dates{$_} };

  # And print the first and last elements of the array,
  # using the correct format string.
  say "begin: ", $times[0]->strftime($date_format);
  say "end: ", $times[-1]->strftime($date_format);
}

__DATA__
2021-Oct-11 16:27:39
2021-Oct-11 16:28:10
2021-Oct-11 16:30:47
2021-Oct-11 16:30:47
2021-Oct-12 09:27:03
2021-Oct-12 10:27:03
2021-Oct-12 18:22:15
2021-Oct-13 08:57:16
2021-Oct-13 08:57:37
2021-Oct-13 11:33:25
2021-Oct-13 11:33:25
2021-Nov-08 16:45:17
2021-Nov-08 16:49:10
2021-Nov-08 17:00:50
2021-Nov-08 22:10:24
2021-Nov-09 11:51:35
2021-Nov-09 11:52:40
2021-Nov-09 12:14:39
2021-Nov-09 14:23:10

由于输入是排序的,所以你需要的是:

my ( $prev_line, $prev_d );

while ( my $line = <> ) {
   my ( $d ) = split( ' ', $line );
   if ( !$prev_line ) {
      print "begin: $line";
      $prev_d = $d;
   }
   elsif ( $d ne $prev_d  ) {
      print "end: $prev_line";
      print "begin: $line";
      $prev_d = $d;
   }

   $prev_line = $line;
}

if ( $prev_line ) {
   print "end: $prev_line";
}