0

我有多个带有日期的输入文件strftime format。日期格式是输入变量之一。我需要确定他们的时间线是否连续;换句话说,如果所有输入文件的日期间隔不重叠。

文件中的数据是连续的。这就像一个文件是一个间隔。文件中的第一个日期在间隔的左侧,最后一个日期在间隔的右侧。

为了更好地展示我的问题(只是数据格式为 %Y.%m.%d %H:%M 的示例):

有 2 个数据文件,日期格式为 %Y.%m.%d %H:%M

数据1.txt

2012.11.20 17:10 134343
2012.11.21 00:10 13323343
2012.12.22 15:10 13432323

数据2.txt

2012.10.20 17:10 134343
2012.11.29 00:10 13333223343
2012.11.30 15:10 134323123

因此,您可以看到文件 data1.txt 和 data2.txt 中的日期重叠。

       2012.10.20         2012.11.20           2012.11.30                2012.12.22

data2.txt <=============================================>

                   data1.txt <===================================================>

我正在 bash 中实现这个问题,但我也欢迎一些 Perl 片段。

我找不到任何简单的解决方案。

谢谢!

4

3 回答 3

1

计算数据范围的重叠并非易事,尤其是在处理日期/时间值时。

我建议Time::Piece::Range模块。它扩展了核心Time::Piece模块来处理日期范围,并且有一个overlap方法。

下面的代码实现了一个函数range_from_file,当提供一个文件名时,它从包含一个文件的所有记录中读取一个日期并创建一个Time::Piece对象数组。对数组进行排序,并Time::Piece::Range从排序列表的第一个和最后一个元素形成一个对象并返回。

对两个数据文件调用此子例程会产生两个Time::Piece::Range对象,并且该方法的最终调用overlap确定这两个文件是否包含重复的日期/时间。

当应用于您的示例文件data1.txt并且data2.txt此代码确认它们重叠时。

请注意,虽然Time::Piece现在是核心模块,Time::Piece::Range但不是,它还需要非核心模块Date::RangeDate::Simple安装。该cpan实用程序会自动为您安装依赖项,但如果您无权扩充 Perl 安装,这可能会成为问题。

use strict;
use warnings;

use Time::Piece::Range;

sub range_from_file {

  my $file = shift;
  open my $fh, '<', $file or die qq(Unable to open "$file" for reading);

  my @dates;
  while (<$fh>) {
    next unless /(\d+\.\d+\.\d+[ ]\d+:\d+)/;
    push @dates, Time::Piece->strptime($1, '%Y.%m.%d %H:%M');
  }

  return Time::Piece::Range->new((sort {$a <=> $b} @dates)[0,-1]);
}

my $r1 = range_from_file('data1.txt');
my $r2 = range_from_file('data2.txt');

print $r1->overlaps($r2) ? 'overlap' : 'distinct';

更新

鉴于除了核心模块之外您无法使用任何东西,并且您假设strftime格式只包含固定长度的字段(例如%B),我建议使用这种替代方法。

我已经修改了range_from_file一个附加$format参数,该参数是strftime用于解码数据的格式。

每个记录的初始日期/时间字段的长度是通过使用提供的格式格式化当前日期/时间并查找结果字符串的长度来确定的。

从每个文件记录的开头提取等效数量的字符,并将文件中的第一个和最后一个日期存储在数组中@dates

这两个日期被转换为Time::Piece对象,并作为匿名数组中的文件范围返回。

一个新的子程序overlap检查两个范围是否重叠。如果第一个结束在第二个开始之前,或者第二个结束在第一个开始之前,它们是分开的。否则它们会重叠。

同样,此代码确认您在文件中的示例数据data1.txtdata2.txt重叠。

use strict;
use warnings;

use Time::Piece 'localtime';

sub range_from_file {

  my ($file, $format) = @_;
  open my $fh, '<', $file or die qq(Unable to open "$file" for reading);

  my $size = length Time::Piece->new->strftime($format);

  my @dates;
  while (<$fh>) {
    pop @dates if @dates >= 2;
    push @dates, substr $_, 0, $size;
  }

  my @range = map Time::Piece->strptime($_, $format), @dates;
  return \@range;
}

sub overlap {
  my ($r1, $r2) = @_;
  return not $r1->[1] < $r2->[0] or $r2->[1] < $r1->[0];
}

my $r1 = range_from_file('data1.txt', '%Y.%m.%d %H:%M');
my $r2 = range_from_file('data2.txt', '%Y.%m.%d %H:%M');

print overlap($r1, $r2) ? 'overlap' : 'distinct';
于 2012-06-12T12:34:17.200 回答
0

好的,所以您需要比较已转换为词法可比格式的日期(有或没有时间?)。这意味着日期是一致的YYYY.MM.DD(必要时带有前导零。

#!/bin/bash
file1=$1
file2=$2
read -r start1 end1 < <(awk 'NR == 1 {print "$1-$2"} END {print "$1-$2"}' "$file1")
read -r start2 end2 < <(awk 'NR == 1 {print "$1-$2"} END {print "$1-$2"}' "$file2")
if [[ $start1 > $start2 || $end1 > $start2 ]]
then
    echo "Overlap!"
fi
于 2012-06-12T15:59:58.750 回答
-1

用 perl 来做。

如果两个文件续。那么只有当 file1 的最后一行中的日期早于 file2 的第一行时,日期才会重叠。

1) 获取第一行 2) 解析行 my ($date1,$data) = line (/\t/,$line); 或者你 Text:Csv 3) 解析 date1 和 date2 my ($Y1,$m1,$d1,$H1,$M1) = $date =~ m!(\d\d\d\d).(\d\ d).(\d\d)\s+(\d\d):(\d\d)!gis; 4)使用DateTime创建纪元;

$dt1 = DateTime->new(year => $Y1, month => $m1, day => $d1, hour => $h1, minute => $m1, second => 0, nanosecond => 0, time_zone = > 'UTC', ); 我的 $epoch1 = $dt1->epoch; 我的 $epoch2 = $dt2->epoch;

5)如果 epoch1 小于 epoch2 你很好。

于 2012-06-12T12:49:13.980 回答