DateTime-Lite
view release on metacpan or search on metacpan
lib/DateTime/Lite/Duration.pm view on Meta::CPAN
{
$self->{months} += $p{years} * 12;
}
if( exists( $p{weeks} ) )
{
$self->{days} += $p{weeks} * 7;
}
if( exists( $p{hours} ) )
{
$self->{minutes} += $p{hours} * 60;
}
if( exists( $p{end_of_month} ) )
{
unless( $p{end_of_month} =~ /^(?:wrap|limit|preserve)$/ )
{
return( $self->error( "Invalid end_of_month mode '$p{end_of_month}'. Must be 'wrap', 'limit', or 'preserve'." ) );
}
$self->{end_of_month} = $p{end_of_month};
}
$self->_normalise_nanoseconds;
return( $self );
}
# NOTE: Accessors (absolute values, matching DateTime::Duration API)
sub nanoseconds { abs( ( $_[0]->in_units( 'nanoseconds', 'seconds' ) )[0] ) }
sub seconds { abs( ( $_[0]->in_units( 'seconds', 'minutes' ) )[0] ) }
sub minutes { abs( ( $_[0]->in_units( 'minutes', 'hours' ) )[0] ) }
sub hours { abs( $_[0]->in_units( 'hours' ) ) }
sub days { abs( ( $_[0]->in_units( 'days', 'weeks' ) )[0] ) }
sub weeks { abs( $_[0]->in_units( 'weeks' ) ) }
sub months { abs( ( $_[0]->in_units( 'months', 'years' ) )[0] ) }
sub years { abs( $_[0]->in_units( 'years' ) ) }
# NOTE: Duration arithmetic
sub add
{
my $self = shift( @_ );
return( $self->add_duration( $self->_duration_from_args( @_ ) ) );
}
sub add_duration
{
my $self = shift( @_ );
my $dur = shift( @_ );
unless( Scalar::Util::blessed( $dur ) && $dur->isa( 'DateTime::Lite::Duration' ) )
{
return( $self->error( "Argument to add_duration() must be a DateTime::Lite::Duration object." ) );
}
foreach my $unit ( @UNITS )
{
$self->{ $unit } += $dur->{ $unit };
}
$self->_normalise_nanoseconds;
return( $self );
}
sub calendar_duration
{
my $self = shift( @_ );
return( ref( $self )->new(
months => $self->{months},
days => $self->{days},
end_of_month => $self->{end_of_month},
) );
}
sub clock_duration
{
my $self = shift( @_ );
return( ref( $self )->new(
minutes => $self->{minutes},
seconds => $self->{seconds},
nanoseconds => $self->{nanoseconds},
) );
}
sub clone { bless( { %{ $_[0] } }, ref( $_[0] ) ) }
# NOTE: Class method: comparison
sub compare
{
my $class = ref( $_[0] ) ? undef : shift( @_ );
my( $d1, $d2 ) = @_;
foreach my $unit ( @UNITS )
{
my $cmp = $d1->{ $unit } <=> $d2->{ $unit };
return( $cmp ) if( $cmp );
}
return(0)
}
# delta_* return the raw (signed) internal values
sub delta_days { $_[0]->{days} }
sub delta_minutes { $_[0]->{minutes} }
sub delta_months { $_[0]->{months} }
sub delta_nanoseconds { $_[0]->{nanoseconds} }
sub delta_seconds { $_[0]->{seconds} }
sub deltas
{
my $self = shift( @_ );
return( map { $_ => $self->{ $_ } } @UNITS );
}
sub end_of_month_mode { return( $_[0]->{end_of_month} ); }
# Error handling: same pattern as Locale::Unicode / Module::Generic
sub error
{
my $self = shift( @_ );
if( @_ )
{
require DateTime::Lite::Exception;
my $msg = join( '', map( ( ref( $_ ) eq 'CODE' ) ? $_->() : $_, @_ ) );
my $e = DateTime::Lite::Exception->new({
lib/DateTime/Lite/Duration.pm view on Meta::CPAN
=encoding utf8
=head1 NAME
DateTime::Lite::Duration - Duration objects for use with DateTime::Lite
=head1 SYNOPSIS
use DateTime::Lite::Duration;
my $dur = DateTime::Lite::Duration->new(
years => 1,
months => 6,
days => 15,
hours => 3,
minutes => 10,
seconds => 30,
) || die( DateTime::Lite::Duration->error );
my $dur = DateTime::Lite::Duration->new(
years => 1,
months => 6,
weeks => 2,
days => 15,
hours => 3,
minutes => 10,
seconds => 30,
nanoseconds => 500_000_000,
end_of_month => 'limit', # 'wrap' (default), 'limit', 'preserve'
) || die( DateTime::Lite::Duration->error );
# Introspection
printf( "Years: %d, Months: %d\n", $dur->years, $dur->months );
# Use with DateTime::Lite
$dt->add_duration( $dur );
$dt->subtract_duration( $dur );
my $diff = $dt1->subtract_datetime( $dt2 ); # returns a Duration
# Absolute-value accessors (strip larger units)
$dur->years; # full years
$dur->months; # months after stripping years
$dur->weeks; # full weeks
$dur->days; # days after stripping weeks
$dur->hours; # full hours
$dur->minutes; # minutes after stripping hours
$dur->seconds; # seconds after stripping minutes
$dur->nanoseconds; # nanoseconds after stripping seconds
# Signed raw delta accessors
$dur->delta_months; # signed months (years * 12 + months)
$dur->delta_days; # signed days
$dur->delta_minutes; # signed minutes (hours * 60 + minutes)
$dur->delta_seconds; # signed seconds
$dur->delta_nanoseconds; # signed nanoseconds
# All signed components at once
my %d = $dur->deltas; # keys: months days minutes seconds nanoseconds
# Calendar / clock sub-durations
my $cal = $dur->calendar_duration; # months + days only
my $clock = $dur->clock_duration; # minutes + seconds + nanoseconds only
# Arithmetic on durations
$dur->add( months => 1, days => 7 );
$dur->subtract( hours => 2 );
$dur->add_duration( $other_dur );
$dur->subtract_duration( $other_dur );
my $inverse = $dur->inverse; # negate all components
my $neg = $dur->inverse( end_of_month => 'wrap' );
# Conversion
# Express as a combination of requested units:
my ( $h, $m ) = $dur->in_units( 'hours', 'minutes' ); # e.g. (3, 10)
my $total_min = $dur->in_units('minutes'); # scalar form
# Comparison
my $cmp = DateTime::Lite::Duration->compare( $dur1, $dur2 ); # -1, 0, 1
# Predicates
$dur->is_positive; # true if any component > 0, none < 0
$dur->is_negative; # true if any component < 0, none > 0
$dur->is_zero; # true if all components are 0
$dur->is_wrap_mode; # end_of_month eq 'wrap'
$dur->is_limit_mode; # end_of_month eq 'limit'
$dur->is_preserve_mode; # end_of_month eq 'preserve'
$dur->end_of_month_mode; # 'wrap', 'limit', or 'preserve'
# Cloning
my $copy = $dur->clone;
# Constants
DateTime::Lite::Duration::MAX_NANOSECONDS(); # 1_000_000_000
# Error handling
my $dur2 = DateTime::Lite::Duration->new( %bad_args ) ||
die( DateTime::Lite::Duration->error );
$dur->fatal(1); # make all errors fatal (die instead of warn+return undef)
my $err = $dur->error;
=head1 VERSION
v0.1.0
=head1 DESCRIPTION
C<DateTime::Lite::Duration> is a lightweight port of L<DateTime::Duration>, used exclusively with L<DateTime::Lite>. It stores durations in five independent "buckets": C<months>, C<days>, C<minutes>, C<seconds>, and C<nanoseconds>.
The month/day buckets are C<calendar> units, whose real length depends on the date to which the duration is applied. The minute/second/nanosecond buckets are absolute (C<clock>) units.
Unlike L<DateTime>, C<DateTime::Lite> never calls C<die()> unexpectedly.
Errors set an exception object accessible via C<< $dur->error >> and return C<undef> in scalar context, or an empty list in list context. In chaining (object context), it returns a dummy object (C<DateTime::Lite::Null>) to avoid the typical C<Can't c...
=head1 CONSTRUCTOR
=head2 new( %args )
Accepted keys:
=over 4
=item C<years>, C<months>
Calendar time. C<years> is converted to months on construction (1 year = 12 months).
=item C<weeks>, C<days>
Calendar time. C<weeks> is converted to days (1 week = 7 days).
=item C<hours>, C<minutes>
Clock time. C<hours> is converted to minutes (1 hour = 60 minutes).
=item C<seconds>, C<nanoseconds>
Clock time.
=item C<end_of_month>
How to handle month-end arithmetic when adding/subtracting months. One of C<wrap> (default), C<limit>, or C<preserve>.
=back
=head1 METHODS
=head2 Accessors (absolute values)
C<years>, C<months>, C<weeks>, C<days>, C<hours>, C<minutes>, C<seconds>, C<nanoseconds> all return the absolute (unsigned) portion of the duration in the given unit, after stripping larger units. For instance C<months()> returns the months component...
=head2 Signed delta accessors
C<delta_months>, C<delta_days>, C<delta_minutes>, C<delta_seconds>, C<delta_nanoseconds> return the raw signed internal values.
=head2 calendar_duration / clock_duration
Return new duration objects containing only the calendar (months, days) or clock (minutes, seconds, nanoseconds) components respectively.
=head2 clone
Returns a shallow copy.
=head2 compare( $dur1, $dur2 )
Class method. Compares two durations unit by unit. Returns -1, 0, or 1.
=head2 deltas
Returns a hash of all five raw signed values.
=head2 end_of_month_mode
Returns C<wrap>, C<limit>, or C<preserve>.
=head2 in_units( @units )
Returns the duration expressed as a combination of the given units.
For example: C<< $dur->in_units( 'hours', 'minutes' ) >> returns C<(3, 10)> for a 190-minute duration. If only one unit is requested, returns a scalar.
=head2 inverse
$dur->inverse;
$dur->inverse( end_of_month => $mode );
Returns a new duration with all components negated. Optionally overrides C<end_of_month>.
=head2 is_negative / is_positive / is_zero
Predicate methods.
=head2 is_wrap_mode / is_limit_mode / is_preserve_mode
Return true if the C<end_of_month> mode matches.
=head2 add
$dur->add( months => 1, days => 15 );
Adds a duration specified as key-value pairs (same keys as L</new>) to this duration in-place. Returns C<$self>.
=head2 add_duration
$dur->add_duration( $other_dur );
Adds another L<DateTime::Lite::Duration> object to this duration in-place. Returns C<$self>.
=head2 subtract
$dur->subtract( days => 1 );
Subtracts a duration specified as key-value pairs from this duration in-place. Equivalent to adding the inverse. Returns C<$self>.
=head2 subtract_duration
$dur->subtract_duration( $other_dur );
( run in 1.919 second using v1.01-cache-2.11-cpan-39bf76dae61 )