2013-10-15 20 views
3

鑑於以下DateTime::SpanSet包含6個DateTime::Span對象(每個跨度打印startendDateTime),我想反轉它並限制它的跨度。更好的方法來限制在perl中反轉的DateTime :: SpanSet?

[2013-02-04T00:00:00 -> 2013-02-04T03:00:00] 
[2013-02-04T07:30:00 -> 2013-02-04T12:00:00] 
[2013-02-04T12:45:00 -> 2013-02-04T16:45:00] 
[2013-02-05T07:30:00 -> 2013-02-05T16:45:00] 
[2013-02-06T08:00:00 -> 2013-02-06T16:30:00] 
[2013-02-07T16:00:00 -> 2013-02-08T16:30:00] 

反相它,使用complement,給出如下:

[-inf -> 2013-02-04T00:00:00] 
[2013-02-04T03:00:00 -> 2013-02-04T07:30:00] 
[2013-02-04T12:00:00 -> 2013-02-04T12:45:00] 
[2013-02-04T16:45:00 -> 2013-02-05T07:30:00] 
[2013-02-05T16:45:00 -> 2013-02-06T08:00:00] 
[2013-02-06T16:30:00 -> 2013-02-07T16:00:00] 
[2013-02-08T16:30:00 -> inf] 

我正在尋找應由DateTime::Span2013-02-04T00:00:00 -> 2013-02-11T00:00:00的限制,給我下面的結果最終結果是:

[2013-02-04T03:00:00 -> 2013-02-04T07:30:00] 
[2013-02-04T12:00:00 -> 2013-02-04T12:45:00] 
[2013-02-04T16:45:00 -> 2013-02-05T07:30:00] 
[2013-02-05T16:45:00 -> 2013-02-06T08:00:00] 
[2013-02-06T16:30:00 -> 2013-02-07T16:00:00] 
[2013-02-08T16:30:00 -> 2013-02-11T00:00:00] 

我可以通過以下方式實現此目的:

sub invertSpansetByBoundary { 
    my $spanset = shift; 
    my $boundary = shift; 
    $spanset = $spanset->complement;  
    my $iter = $spanset->iterator(span => $boundary); 
    my $ss = DateTime::SpanSet->empty_set(); 
    while(my $timespan = $iter->next) { 
     $ss = $ss->union($timespan); 
    } 

    return $ss; 
} 

是否有可能以更好的方式做到這一點?

回答

0

對此的解決方案似乎太容易了,我實際上已經構建了一個測試工具來驗證您的結果與我的結果之間的關係,這些結果我將在下面介紹。我的Perl的有點生疏,但這裏是我想出瞭解決方案:

sub alternateInvert { 
    my $spanset = shift; 
    my $boundary = shift; 
    return $boundary->complement($spanset); 
} 

使用這個給了我同樣的結果你的函數。 以下是測試用具:

#!/opt/local/bin/perl 

use DateTime::Span; 
use DateTime::Format::RFC3339; 
use DateTime; 
use strict; 
use warnings; 


sub invertSpansetByBoundary { 
    my $spanset = shift; 
    my $boundary = shift; 
    $spanset = $spanset->complement;  
    my $iter = $spanset->iterator(span => $boundary); 
    my $ss = DateTime::SpanSet->empty_set(); 
    while(my $timespan = $iter->next) { 
     $ss = $ss->union($timespan); 
    } 

    return $ss; 
} 

sub alternateInvert { 
    my $spanset = shift; 
    my $boundary = shift; 
    return $boundary->complement($spanset); 
} 

sub printSpanset { 
    my $spanset = shift; 
    my $iter = $spanset->iterator(span => $spanset); 
    while(my $timespan = $iter->next) { 
     printf "[%s -> %s]\n", $timespan->start, $timespan->end; 
    } 
} 

my $datestrs = [ 
    ["2013-02-04T00:00:00Z", "2013-02-04T03:00:00Z"], 
    ["2013-02-04T07:30:00Z", "2013-02-04T12:00:00Z"], 
    ["2013-02-04T12:45:00Z", "2013-02-04T16:45:00Z"], 
    ["2013-02-05T07:30:00Z", "2013-02-05T16:45:00Z"], 
    ["2013-02-06T08:00:00Z", "2013-02-06T16:30:00Z"], 
    ["2013-02-07T16:00:00Z", "2013-02-08T16:30:00Z"]]; 

my $spanset = DateTime::SpanSet->empty_set(); 
my $format = DateTime::Format::RFC3339->new(); 

foreach my $set (@$datestrs) { 
    my $startdt = $format->parse_datetime($set->[0]); 
    my $enddt = $format->parse_datetime($set->[1]); 
    $spanset = $spanset->union(DateTime::Span->from_datetimes(start => $startdt, end => $enddt)); 
} 

my $bstartdt = $format->parse_datetime("2013-02-04T00:00:00Z"); 
my $benddt = $format->parse_datetime("2013-02-11T00:00:00Z"); 

my $boundary = DateTime::Span->from_datetimes(start => $bstartdt, end => $benddt); 

my $result; 

print "Input:\n"; 
printSpanset($spanset); 

# $result = invertSpansetByBoundary($spanset, $boundary); 
# print "\nBaseline Result:\n"; 
# printSpanset($result); 

$result = alternateInvert($spanset, $boundary); 
print "\nImproved Result:\n"; 
printSpanset($result);