Solved!
Changed the script a bit: everything is now a sub/function, using DateTime (although didn't go and clean up the non-DateTime code to use DateTime (yet) ), holidays are listed in a csv file for each region (instead of having huge hashes of static holidays), etc.
the csv files are extremely simple. They are in the format of:
datestamp,"Holiday name"
best of all, it works. :)
[vxp@vxp ~]$ ./zhopa.pl 20081231 mo The full path is /home/vxp/holidays/mo.csv Date passed to script: 20081231 Checking 20090101 20090101 is a day off, now will check 20090102 Checking 20090102 20090102 is a day off, now will check 20090103 Checking 20090103 20090103 is a day off, now will check 20090104 Checking 20090104 20090104 is a day off, now will check 20090105 Checking 20090105 20090105 is a day off, now will check 20090106 Checking 20090106 The next business day is: 20090106 [vxp@vxp ~]$
Full code below.
#!/usr/bin/perl use Time::Local 'timelocal_nocheck'; use DateTime; my $date_passed = shift; my $zone = shift; my $holiday_dir = "/home/vxp/holidays/"; $zone = lc($zone); my $seconds_in_day = 86400; ############################# # was a proper date given? ############################# unless ($date_passed =~ /^\d{8}$/) { print "The date must be in the yyyymmdd format. Example: 20090 +101\n"; exit(-1); } ############################################### # is the zone correct? was it even given? ############################################### unless (($zone =~ /^ny$/) || ($zone =~ /^hk$/) || ($zone =~ /^mo$/) || + ($zone =~ /^ln$/) || ($zone =~ /^tk$/ ) || ($zone =~ /^se$/ )) { print "The acceptable zones are:\nNY\nHK\nMO\nLN\nTK\nSE\n"; exit(-1); } my $full_path_2_holiday_file = $holiday_dir . $zone . ".csv"; print "The full path is $full_path_2_holiday_file\n"; print "Date passed to script: $date_passed\n"; my $next_day = get_next_day($date_passed); while (1) { print "Checking $next_day\n"; $all_result = all_checks($next_day); if ($all_result =~ /1/) { print "The next business day is: $next_day\n"; exit(0); } else { print "$next_day is a day off, now will check "; $next_day = get_next_day($next_day); print "$next_day\n"; $all_result = all_checks($next_day); } } sub all_checks { ############################## # return codes are as follows # 0 - dayoff # 1 - workday # -1 - error ############################# my $date = shift || return(-1); my $weekend_result = weekend_check($date); my $holiday_result = holiday_check($date, $zone, $full_path_2_ho +liday_file); if (($weekend_result =~ /1/) && ($holiday_result =~ /1/)) { return(1); } else { return(0); } } sub weekend_check { ############################## # return codes are as follows # 0 - weekend # 1 - nonweekend # -1 - error ############################# my $date = shift || return(-1); my $day_of_week = get_day($date); unless (($day_of_week =~ /Monday/) || ($day_of_week =~ /Tuesday/) +|| ($day_of_week =~ /Wednesday/) || ($day_of_week =~ /Thursday/) || ( +$day_of_week =~ /Friday/) ) { return(0); } else { return(1); } } sub get_day { ##################################### # return codes are as follows # -1 - error # otherwise, returns the day's name ##################################### my $date = shift || return(-1); my @weekday = qw(Sunday Monday Tuesday Wednesday Thursday Friday S +aturday); my ($year,$mon,$mday) = $date =~ /(\d{4})(\d{2})(\d{2})/; my $epochtime = timelocal_nocheck(0, 0, 0, $mday, $mon-1, $year); my $day = (localtime($epochtime))[6]; return $weekday[$day]; } sub get_next_day { my $date = shift || return(-1); my ($year,$mon,$mday) = $date =~ /(\d{4})(\d{2})(\d{2})/; $dt = DateTime->new( year => $year, month => $mon, day => $mday, hour => 13, minute => 00, second => 00, nanosecond => 500000000, time_zone => 'local', ); # this is next day's epoch representation $epoch_time = $dt->epoch + $seconds_in_day; # converting epoch to human readable $dt = DateTime->from_epoch( epoch => $epoch_time ); # mangle it to be in the right format if ($dt =~ /(\d{4})-(\d{2})-(\d{2}).+/) { $dt = $1 . $2 . $3 } return $dt; } sub holiday_check { ############################## # return codes are as follows # 0 - holiday # 1 - nonholiday # -1 - error ############################# my $date = shift || return(-1); my $zone = shift || return(-1); my $path = shift || return(-1); open(HOLIDAYS, $path) or die "Couldn't open $path: $!\n"; while(defined($line = <HOLIDAYS>)) { chomp($line); my ($datestamp, $holiday_description) = split(/,/, $line); $holidays{ $datestamp } = $holiday_description; } if ($zone =~ /ny/) { if (exists($holidays{$date})) { return(0); } else { return(1); } } if ($zone =~ /hk/) { if (exists($holidays{$date})) { return(0); } else { return(1); } } if ($zone =~ /mo/) { if(exists($holidays{$date})) { return(0); } else { return(1); } } if ($zone =~ /ln/) { if(exists($holidays{$date})) { return(0); } else { return(1); } } if ($zone =~ /tk/) { if(exists($holidays{$date})) { return(0); } else { return(1); } } if ($zone =~ /se/) { if(exists($holidays{$date})) { return(0); } else { return(1); } } }
In reply to Re: Calculating next business day (weekends/holidays taken into account)
by vxp
in thread Calculating next business day (weekends/holidays taken into account)
by vxp
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |