DateTimeX-Lite
view release on metacpan or search on metacpan
lib/DateTimeX/Lite/Arithmetic.pm view on Meta::CPAN
my $class = ref $dt;
my $dt_string = overload::StrVal($dt);
Carp::croak( "Cannot add $dur to a $class object ($dt_string).\n"
. " Only a DateTimeX::Lite::Duration object can "
. " be added to a $class object." );
}
return $dt->clone->add_duration($dur);
}
sub _subtract_overload
{
my ( $date1, $date2, $reversed ) = @_;
if ($reversed)
{
( $date2, $date1 ) = ( $date1, $date2 );
}
if ( blessed $date2 && $date2->isa( 'DateTimeX::Lite::Duration' ) )
{
my $new = $date1->clone;
$new->add_duration( $date2->inverse );
return $new;
}
elsif ( blessed $date2 && $date2->isa( 'DateTimeX::Lite' ) )
{
return $date1->subtract_datetime($date2);
}
else
{
my $class = ref $date1;
my $dt_string = overload::StrVal($date1);
Carp::croak( "Cannot subtract $date2 from a $class object ($dt_string).\n"
. " Only a DateTimeX::Lite::Duration or DateTimeX::Lite object can "
. " be subtracted from a $class object." );
}
}
sub add { return shift->add_duration( DateTimeX::Lite::Duration->new(@_) ) }
sub subtract { return shift->subtract_duration( DateTimeX::Lite::Duration->new(@_) ) }
sub subtract_duration { return $_[0]->add_duration( $_[1]->inverse ) }
sub add_duration
{
my ($self, $dur) = @_;
if (! blessed $dur || !$dur->isa('DateTimeX::Lite::Duration')) {
Carp::croak("Duration is not a DateTimeX::Lite::Duration object");
}
# simple optimization
return $self if $dur->is_zero;
my %deltas = $dur->deltas;
# This bit isn't quite right since DateTimeX::Lite::Infinite::Future -
# infinite duration should NaN
foreach my $val ( values %deltas )
{
my $inf;
if ( $val == &DateTimeX::Lite::INFINITY )
{
$inf = DateTimeX::Lite::Infinite::Future->new;
}
elsif ( $val == &DateTimeX::Lite::NEG_INFINITY )
{
$inf = DateTimeX::Lite::Infinite::Past->new;
}
if ($inf)
{
%$self = %$inf;
bless $self, blessed $inf;
return $self;
}
}
return $self if $self->is_infinite;
if ( $deltas{days} )
{
$self->{local_rd_days} += $deltas{days};
$self->{utc_year} += int( $deltas{days} / 365 ) + 1;
}
if ( $deltas{months} )
{
# For preserve mode, if it is the last day of the month, make
# it the 0th day of the following month (which then will
# normalize back to the last day of the new month).
my ($y, $m, $d) = ( $dur->is_preserve_mode ?
DateTimeX::Lite::Util::rd2ymd( $self->{local_rd_days} + 1 ) :
DateTimeX::Lite::Util::rd2ymd( $self->{local_rd_days} )
);
$d -= 1 if $dur->is_preserve_mode;
if ( ! $dur->is_wrap_mode && $d > 28 )
{
# find the rd for the last day of our target month
$self->{local_rd_days} = DateTimeX::Lite::Util::ymd2rd( $y, $m + $deltas{months} + 1, 0 );
# what day of the month is it? (discard year and month)
my $last_day = (DateTimeX::Lite::Util::rd2ymd( $self->{local_rd_days} ))[2];
# if our original day was less than the last day,
# use that instead
$self->{local_rd_days} -= $last_day - $d if $last_day > $d;
}
else
{
$self->{local_rd_days} = DateTimeX::Lite::Util::ymd2rd( $y, $m + $deltas{months}, $d );
}
$self->{utc_year} += int( $deltas{months} / 12 ) + 1;
( run in 2.085 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )