/usr/local/CPAN/Time-Vector/Time/Vector.pm
package Time::Vector;
use strict;
use Time::Simple::Range;
use Time::Seconds;
use Bit::Vector::Overload; # this thingy can't be subclassed :(
use base qw/ Class::Accessor::Fast /;
use overload
'fallback' => 0,
'&' => 'and',
'|' => 'or',
'=' => 'clone',
'""' => 'stringify';
our $VERSION = '1.1';
__PACKAGE__->mk_accessors(qw/ vec first last /);
use constant BITS_PER_DAY => 1440; # 1 bit per minute
sub new
{
my ($proto, $vec) = @_;
my $class = ref($proto) || $proto;
my $self = bless $proto->SUPER::new(), $class;
$self->vec(defined $vec ? $vec : Bit::Vector->new(BITS_PER_DAY));
$self->first(undef);
$self->last(undef);
return bless $self, $class;
}
sub new_range
{
my ($proto, @range) = @_;
my $self = new Time::Vector;
while (scalar @range >= 2) {
my @r = splice(@range, 0, 2);
$self->add_range(Time::Simple::Range->new($r[0], $r[1]));
}
return $self;
}
sub add_range
{
my ($self, $range) = @_;
my $start = $range->start->hours * 60 + $range->start->minutes;
my $end = $range->end->hours * 60 + $range->end->minutes;
$end--
unless $range->end->seconds == 59;
$self->first($range->start)
if not defined $self->first
or $range->start < $self->first;
$self->last($range->end)
if not defined $self->last
or $range->end > $self->last;
# Bitwise OR between old vector and range vector
my $nv = $self->vec | Bit::Vector->new_Enum(BITS_PER_DAY, "$start-$end");
$self->vec($nv);
}
sub after
{
my $self = shift;
return undef unless defined $self->last;
return Time::Vector->new_range($self->last, Time::Simple->new('23:59:59'));
}
sub before
{
my $self = shift;
return undef unless defined $self->first;
return Time::Vector->new_range(Time::Simple->new('00:00:00'), $self->first);
}
sub range
{
my $self = shift;
my @range;
my $base = Time::Simple->new('00:00:00');
my $enum = $self->vec->to_Enum;
foreach my $r (split(/,/, $enum)) {
if ($r =~ /^(\d+)-(\d+)$/) {
my $s = $base + ($1 * 60);
my $e = $base + ($2 * 60) + 60;
push(@range, Time::Simple::Range->new($s, $e));
} elsif ($r =~ /^(\d+)$/) {
my $s = $base + ($1 * 60);
my $e = $s + 60;
push(@range, Time::Simple::Range->new($s, $e));
}
}
return @range;
}
sub duration
{
my $self = shift;
my $d = 0;
foreach ($self->range) {
$d += $_->duration;
}
return new Time::Seconds($d);
}
sub and
{
my ($a, $b) = @_;
my $vec = $a->vec & $b->vec;
return Time::Vector->new($vec);
}
sub or
{
my ($a, $b) = @_;
my $vec = $a->vec | $b->vec;
return Time::Vector->new($vec);
}
sub stringify
{
return join(',', map {
$_->start->format('%H:%M')
. '-'
. $_->end->format('%H:%M')
} (shift)->range);
}
sub clone
{
my $self = shift;
return Time::Vector->new($self->vec->Clone);
}
1;