Perl において、任意の日付から n 営業日後、または n 営業日前の日付を求める覚書き。単純に± n 日とするのでなく、土日や日本の祝祭日、祝祭日が日曜に掛かった場合の振替休日、更に会社や学校の創立記念日などの任意に設定された休日も考慮します。
#!/usr/bin/perl
use v5.10;
use Calendar;
use Calendar::Japanese::Holiday;
### 任意指定の休日 MM/DD/YYYY
my %special_holiday = map{ $_ => 1 } qw{
12/29/2015
12/30/2015
12/31/2015
01/04/2016
};
### $_[0] から $_[1] 営業日後(前)の日付を返す
sub dt2offset {
my $datetime = shift;
my $offset = int shift || 0;
my $offset_dir = 0 < $offset ? +1 : -1;
# 月末をまたぐ計算などが面倒なので Calendar モジュールを使う
my( $y, $m, $d ) = $datetime =~ /(\d+)\D+(\d+)\D+(\d+)/;
my $c = Calendar->new_from_Gregorian( $m, $d, $y );
while( $offset ){
$c += $offset_dir;
# 土日はカウントしない
next if $c->weekday == 0; # 日曜
next if $c->weekday == 6; # 土曜
# 日本の祝祭日はカウントしない(振替休日を考慮する→第4引数)
next if isHoliday( $c->year, $c->month, $c->day, 1 );
# 特別休日はカウントしない
next if $special_holiday{$c};
# オフセットを進める
$offset -= $offset_dir;
}
$c->date_string( '%Y-%m-%d' );
}
# 年末年始で動作確認
say dt2offset( '2015-12-31', +3 ); # 2016-01-07
say dt2offset( '2016/01/04', -3 ); # 2015-12-24
# 成人の日前後(振替休日あり)で動作確認
say dt2offset( '2016-01-08', +3 ); # 2016-01-14
say dt2offset( '2016-01-13', -3 ); # 2016-01-07
振替と返します。MM/DD/YYYY 形式で日付を返すので、%special_holiday に特別休日の指定がないか調べています。