Date-Business
view release on metacpan or search on metacpan
Business.pm view on Meta::CPAN
return $sign * ($weeks + $days);
}
# adds n business days
sub addb($$) {
my($self, $inc) = @_;
return if ($inc == 0 || $inc < 0 && $self->subb(-$inc));
my($start) = $self->{'val'};
my($weeks) = int($inc/5) * 7;
my($dow) = (($self->{'val'} + E_SUNDAY) / DAY) % 7;
my($days) = $inc % 5;
if ($dow > THURSDAY) {
$self->{'val'} -= 1 * DAY if ($dow == FRIDAY);
$self->{'val'} -= 2 * DAY if ($dow == SATURDAY);
$dow-- if ($days == 0);
}
$days += 2 if ($days + $dow > THURSDAY);
$self->{'val'} += ($weeks + $days) * DAY;
if (ref($self->{HOLIDAY}) eq 'CODE') {
my($start_txt) = POSIX::strftime("%Y%m%d", gmtime($start + DAY));
my($numHolidays) = $self->{HOLIDAY}->($start_txt, $self->image);
$self->addb($numHolidays) if ($numHolidays);
}
return 1;
}
# subs n business days
sub subb($$) {
my($self, $dec) = @_;
return if ($dec == 0 || $dec < 0 && $self->addb(-$dec));
my($start) = $self->{'val'};
my($weeks) = int($dec/5) * 7;
my($dow) = (($self->{'val'} + E_SUNDAY) / DAY) % 7;
my($days) = $dec % 5;
if ($dow > 4) {
$self->{'val'} += 2 * DAY if ($dow == FRIDAY);
$self->{'val'} += 1 * DAY if ($dow == SATURDAY);
$days += 2 if ($days);
} else {
$days += 2 if ($days > $dow);
}
$self->{'val'} -= ($weeks + $days) * DAY;
if (ref($self->{HOLIDAY}) eq 'CODE') {
my($end_txt) = POSIX::strftime("%Y%m%d", gmtime($start - DAY));
my($numHolidays) = $self->{HOLIDAY}->($self->image, $end_txt);
$self->subb($numHolidays) if ($numHolidays);
}
return 1;
}
1;
__END__
=head1 NAME
Date::Business - fast calendar and business date calculations
=head1 SYNOPSIS
All arguments to the Date::Business constructor are optional.
# simplest case, default is today's date (localtime)
$d = new Date::Business();
# initialize with date string,
# offset in business days is optional
$d = new Date::Business(DATE => '19991124' [, OFFSET => <integer>]);
# initialize with another Date::Business object
# offset in business days is optional
$x = new Date::Business(DATE => $d [, OFFSET => <integer>]);
# initialize with holiday function (see Holidays, below)
$d = new Date::Business(HOLIDAY => \&holiday);
# force weekends/holidays to the previous or next business day
$d = new Date::Business(FORCE => 'prev'); # Friday (usually)
$d = new Date::Business(FORCE => 'next'); # Monday (usually)
$d->image(); # returns YYYYMMDD string
$d->value(); # returns Unix time as integer
$d->day_of_week(); # 0 = Sunday
$d->datecmp($x); # are two dates equal?
$d->eq($x); # synonym for datecmp
$d->lt($x); # less than
$d->gt($x); # greater than
Calendar date functions
$d->next(); # next calendar day
$d->prev(); # previous calendar day
$d->add(<offset>); # adds n calendar days
$d->sub(<offset>); # subtracts n calendar days
$d->diff($x); # difference between two dates
Business date functions
$d->nextb(); # next business day
$d->prevb(); # previous business day
$d->addb(<offset>); # adds n business days
$d->subb(<offset>); # subtracts n business days
$d->diffb($x); # difference between two business dates
$d->diffb($x, 'next'); # treats $d weekend/holiday as next business date
$d->diffb($x, 'next', 'next'); # treats $x weekend/holiday as above
=head1 DESCRIPTION
Date::Business provides the functionality to perform simple date
manipulations quickly. Support for calendar date and
business date math is provided.
Business dates are weekdays only. Adding 1 to a weekend returns
Monday, subtracting 1 returns Friday.
The difference in business days between Friday and the following
Monday (using the diffb function) is one business day. The number
of business days between Friday and the following Monday (using the
betweenb function) is zero.
=head1 EXAMPLE
Date::Business works very well for iterating over dates,
and determining start and end dates of arbitray n business day
periods (e.g. consider how to perform a computation for
a series of business days starting from an arbitrary day).
$end = new Date::Business(); # today
# 10 business days ago
$start = new Date::Business(DATE => $end, OFFSET => -10);
while (!$start->gt($end)) {
compute_something($start);
$start->nextb();
}
=head1 HOLIDAYS
Optionally, a reference to a function that counts the number of
holidays in a given date range can be passed. Business date addition,
subtraction, and difference functions will consider holidays.
Sample holiday function:
# MUST BE NON-WEEKEND HOLIDAYS !!!
sub holiday($$) {
my($start, $end) = @_;
my($numHolidays) = 0;
my($holiday, @holidays);
push @holidays, '19981225'; # Christmas
push @holidays, '19990101'; $ New Year's
foreach $holiday (@holidays) {
$numHolidays++ if ($start le $holiday && $end ge $holiday);
}
return $numHolidays;
}
Example using the holiday function:
# 10 business days after 21 DEC 1998, where
# 25 DEC 1998 and 01 JAN 1999 are holidays
#
$d = new Date::Business(DATE => '19981221',
OFFSET => 10,
HOLIDAY => \&holiday);
print $d->image."\n"; # prints 19990106
( run in 1.733 second using v1.01-cache-2.11-cpan-140bd7fdf52 )