2012-06-12 65 views
0

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

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

为了更好地展示我的问题(有数据格式%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 

所以,你可以看到2012年新文件DATA1.TXT和data2.txt重叠。

 2012.10.20   2012.11.20   2012.11.30    2012.12.22 

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

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

我实现在bash这个问题,但我欢迎一些Perl的片段了。

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

谢谢!

+0

我已经尝试用Perl时间:: Piece-> strptime,但只筛选有效的日期格式 – Rob

+0

这是很不明朗,从你的数据是什么构成了*间隔*。你是否需要检查一组间隔中是否有间隙,或只是没有重叠? – Borodin

+0

每个文件内的数据都是连续的。像一个文件是一个区间 文件中的第一个日期是区间和左边的最后一个日期是区间的右侧 – Rob

回答

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)我建议这个选择。

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

日期格式不固定,但是在strftime格式中是可变的。 但在我的情况下,它并不重要,因为文件中的所有行都是有效的(除非/(\ d + \。\ d + \。\ d + [] \ d +:\ d +)/; 不是必需的)当然,如果我可以使用uncore模块。 – Rob

+0

我想你只需要看文件的第一行和最后一行,而不是每行。 –

+0

@DennisWilliamson:样本数据似乎被排序,但OP尚未确认它是如此我们不能假设它。 – Borodin

-1

用Perl来做。

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

1)获得第一行 2)解析行 my($ date1,$ data)= line(/ \ t /,$ line); ($ Y1,$ m1,$ d1,$ H1,$ M1)= $ date =〜m!(\ d \ d \ d \ d \ d)。( \ d \ d)(\ d \ d)\ S +(\ d \ d):!(\ d \ d)地理信息系统; 4)创建时期 使用DateTime;

$ DT1 = DateTime->新( 年=> $ Y1, 月=> $ M1, 天=> $ D1, 小时=> $ H1, 分钟=> $ M1, 第二= > 0, nanosecond => 0, time_zone =>'UTC', ); my $ epoch1 = $ dt1-> epoch; my $ epoch2 = $ dt2-> epoch; 5)如果epoch1小于epoch2,你很好。

+0

日期格式不固定,但它是可变的strftime格式。 – Rob

+0

这是一个可怕的答案。这是错误的,几乎不可读。 – Borodin

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 
+0

假设“这意味着日期一致YYYY.MM.DD”是不正确的。我已经尝试了nawk,但它没有像perl一样的strptime()的任何等价函数。此外,区间aritmetic至少会产生问题,因为你不知道最重要的值在哪里,第二等... – Rob

+0

@Rob:我以为你已经解析了日期解析!!?!?你是什​​么意思,你不知道最重要的价值在哪里? –