比较strftime格式的日期间隔

时间:2012-06-12 10:40:06

标签: perl bash strftime

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

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

更好地展示我的问题(仅举例说明数据格式为%Y。%m。%d%H:%M):

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

DATA1.TXT

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

data2.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片段。

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

谢谢!

3 个答案:

答案 0 :(得分:1)

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

我建议使用Time::Piece::Range模块。它扩展了核心Time::Piece模块以处理日期范围,并具有overlap方法。

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

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

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

请注意,虽然Time::Piece现在是核心模块,但Time::Piece::Range不是,并且还需要安装非核心模块Date::RangeDate::Simplecpan实用程序将自动为您安装依赖项,但如果您无权扩充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),我建议使用此替代方法。< / p>

我修改了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';

答案 1 :(得分: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

答案 2 :(得分:-1)

用perl做。

如果两个文件相同。那么只有当file1的最后一行中的日期早于你可以使用的第一行file2时,日期才会重叠。

1)获得第一线 2)解析行 my($ date1,$ data)= line(/ \ t /,$ line); 或者你发短信:Csv 3)解析date1和date2 我的($ Y1,$ m1,$ d1,$ H1,$ M1)= $ date = ~m!(\ d \ d \ d \ d)。(\ d \ d)。(\ d \ d)\ s + (\ d \ d):(\ d \ d)地理信息系统; 4)创造时代 使用DateTime;

$ dt1 = DateTime-&gt; new(       年=&gt; $ Y1,       month =&gt; $ M1,       day =&gt; $ D1,       小时=&gt; $ H1,       分钟=&gt; $ M1,       second =&gt; 0,       纳秒=&gt; 0,       time_zone =&gt; '世界标准时间',   ); 我的$ epoch1 = $ dt1-&gt; epoch; 我的$ epoch2 = $ dt2-&gt; epoch;

5)如果epoch1比epoch2小,那么你就是好的。