auto
  #   ˆl—äY>”ªe¶¥8 \¸Û—}LZ7ÿÁƒh¹À¿      disabled
  0   ˆl–äY>” ”†Ù”ê€nã.\ÊbÑ¿Â„®„?_‹uÐb&=LV[(ÂÁ ?÷     package DateTime::Duration;
{
  $DateTime::Duration::VERSION = '1.04';
}

use strict;
use warnings;

use Carp ();
use DateTime;
use DateTime::Helpers;
use Params::Validate qw( validate SCALAR );

use overload (
    fallback => 1,
    '+'      => '_add_overload',
    '-'      => '_subtract_overload',
    '*'      => '_multiply_overload',
    '<=>'    => '_compare_overload',
    'cmp'    => '_compare_overload',
);

use constant MAX_NANOSECONDS => 1_000_000_000;    # 1E9 = almost 32 bits

my @all_units = qw( months days minutes seconds nanoseconds );

# XXX - need to reject non-integers but accept infinity, NaN, &
# 1.56e+18
sub new {
    my $class = shift;
    my %p     = validate(
        @_, {
            years        => { type => SCALAR, default => 0 },
            months       => { type => SCALAR, default => 0 },
            weeks        => { type => SCALAR, default => 0 },
            days         => { type => SCALAR, default => 0 },
            hours        => { type => SCALAR, default => 0 },
            minutes      => { type => SCALAR, default => 0 },
            seconds      => { type => SCALAR, default => 0 },
            nanoseconds  => { type => SCALAR, default => 0 },
            end_of_month => {
                type  => SCALAR, default => undef,
                regex => qr/^(?:wrap|limit|preserve)$/
            },
        }
    );

    my $self = bless {}, $class;

    $self->{months} = ( $p{years} * 12 ) + $p{months};

    $self->{days} = ( $p{weeks} * 7 ) + $p{days};

    $self->{minutes} = ( $p{hours} * 60 ) + $p{minutes};

    $self->{seconds} = $p{seconds};

    if ( $p{nanoseconds} ) {
        $self->{nanoseconds} = $p{nanoseconds};
        $self->_normalize_nanoseconds;
    }
    else {

        # shortcut - if they don't need nanoseconds
        $self->{nanoseconds} = 0;
    }

    $self->{end_of_month} = (
          defined $p{end_of_month} ? $p{end_of_month}
        : $self->{months} < 0      ? 'preserve'
        : 'wrap'
    );

    return $self;
}

# make the signs of seconds, nanos the same; 0 < abs(nanos) < MAX_NANOS
# NB this requires nanoseconds != 0 (callers check this already)
sub _normalize_nanoseconds {
    my $self = shift;

    return
        if ( $self->{nanoseconds} == DateTime::INFINITY()
        || $self->{nanoseconds} == DateTime::NEG_INFINITY()
        || $self->{nanoseconds} eq DateTime::NAN() );

    my $seconds = $self->{seconds} + $self->{nanoseconds} / MAX_NANOSECONDS;
    $self->{seconds}     = int($seconds);
    $self->{nanoseconds} = $self->{nanoseconds} % MAX_NANOSECONDS;
    $self->{nanoseconds} -= MAX_NANOSECONDS if $seconds < 0;
}

sub clone { bless { %{ $_[0] } }, ref $_[0] }

sub years       { abs( $_[0]->in_units('years') ) }
sub months      { abs( $_[0]->in_units( 'months', 'years' ) ) }
sub weeks       { abs( $_[0]->in_units('weeks') ) }
sub days        { abs( $_[0]->in_units( 'days', 'weeks' ) ) }
sub hours       { abs( $_[0]->in_units('hours') ) }
sub minutes     { abs( $_[0]->in_units( 'minutes', 'hours' ) ) }
sub seconds     { abs( $_[0]->in_units('seconds') ) }
sub nanoseconds { abs( $_[0]->in_units( 'nanoseconds', 'seconds' ) ) }

sub is_positive { $_[0]->_has_positive  && !$_[0]->_has_negative }
sub is_negative { !$_[0]->_has_positive && $_[0]->_has_negative }

sub _has_positive {
    ( grep { $_ > 0 } @{ $_[0] }{@all_units} ) ? 1 : 0;
}

sub _has_negative {
    ( grep { $_ < 0 } @{ $_[0] }{@all_units} ) ? 1 : 0;
}

sub is_zero {
    return 0 if grep { $_ != 0 } @{ $_[0] }{@all_units};
    return 1;
}

sub delta_months      { $_[0]->{months} }
sub delta_days        { $_[0]->{days} }
sub delta_minutes     { $_[0]->{minutes} }
sub delta_seconds     { $_[0]->{seconds} }
sub delta_nanoseconds { $_[0]->{nanoseconds} }

sub deltas {
    map { $_ => $_[0]->{$_} } @all_units;
}

sub in_units {
    my $self  = shift;
    my @units = @_;

    my %units = map { $_ => 1 } @units;

    my %ret;

    my ( $months, $days, $minutes, $seconds