@MONTHS = ('','January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November',
'December');
@DAYS = ('','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday');
@DAYSINYEAR = (
[ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 ],
[ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 ]
);
@DAYSINMONTH = (
[ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ],
[ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
);
sub leap_year {
my ($year) = @_;
my $yy = int ($year/100);
if ($year > 0) {
return ((($year & 0x03) ==0) &&
(( $yy * 100 != $year) ||
(($yy & 0x03) == 0) ) ) ? 1 : 0;
} else {
return '';
}
}
sub check_date_leap {
my ($day, $month, $year) = @_;
my $leap = leap_year($year);
return (($year >= 1) &&
($month >= 1) && ($month <= 12) &&
($day >= 1) &&
($day <= $DAYSINMONTH[$leap][$month])) ? $leap : -1;
}
sub Year_to_Days {
my ($year) = @_;
my $days = 365 * $year;
$days += ($year >>= 2);
$year = int ($year / 25);
$days -= $year;
$days += ($year >> 2);
return $days;
}
sub Date_to_Days {
my ($day, $month, $year) = @_;
my $leap = check_date_leap( $day, $month, $year );
if ($leap >= 0) {
return (Year_to_Days(--$year) +
$DAYSINYEAR[$leap][$month] + $day );
} else {
return '';
}
}
sub day_of_week {
my ($day, $month, $year) = @_;
my $n_days = Date_to_Days($day, $month, $year);
if ($n_days > 0) {
$n_days--;
$n_days %= 7;
$n_days++;
return $n_days;
} else {
return '';
}
}
sub split_date {
local ($date) = $_[0];
local ($day,$month,$year);
if ($date) {
$day = $date % 100;
$month = (int ($date/100)) % 100;
$year = int ($date/10000);
} else {
($day,$month,$year) = ('','','');
}
return ($day,$month,$year);
}
sub join_date {
local ($day,$month,$year) = @_;
local ($date);
if ($day > $DAYSINMONTH[leap_year($year)][$month] ) {
$date = -1;
} else {
$date = ($year * 10000) + ($month * 100) + $day;
}
return ($date);
}
sub easter_sunday
{
my ($year) = @_;
my ($month, $day);
################################################################
# #
# Gauss'sche Regel (Gaussian Rule) #
# ================================ #
# #
# Quelle / Source: #
# #
# H. H. Voigt, "Abriss der Astronomie", Wissenschaftsverlag, #
# Bibliographisches Institut, Seite 9. #
# #
################################################################
my ($a, $b, $c, $d, $e, $m, $n);
if (($year <= 0) || ($year < 1583) || ($year > 2299)) {
die "Easter_Sunday: Year out of range";
}
if ($year < 1700) { $m = 22; $n = 2; }
elsif ($year < 1800) { $m = 23; $n = 3; }
elsif ($year < 1900) { $m = 23; $n = 4; }
elsif ($year < 2100) { $m = 24; $n = 5; }
elsif ($year < 2200) { $m = 24; $n = 6; }
else { $m = 25; $n = 0; }
$a = $year % 19;
$b = $year % 4;
$c = $year % 7;
$d = (19 * $a + $m) % 30;
$e = (2 * $b + 4 * $c + 6 * $d + $n) % 7;
$day = 22 + $d + $e;
$month = 3;
if ($day > 31)
{
$day -= 31; # same as $day = $d + $e - 9;
$month++;
}
if (($day == 26) && ($month == 4))
{
$day = 19;
}
if (($day == 25) && ($month == 4) &&
($d == 28) && ($e == 6) && ($a > 10))
{
$day = 18;
}
return (&join_date($day, $month, $year));
}
#
# hash_holidays : Fills a hash with all holiday dates for the specified year
#
sub hash_holidays {
local ($year) = $_[0];
local (%holiday) = ();
# New Year's Day
local($testday) = &day_of_week (1,1,$year);
if ($testday > 5) {
$holiday{&join_date((9 - $testday),1,$year)} = 1;
} else {
$holiday{&join_date(1,1,$year)} = 1;
}
#
# Calculate Easter to get Good Friday & Easter Monday
#
local ($easter) = &easter_sunday($year);
$holiday{&prev_date(&prev_date($easter))} = 1; # Good Friday
$holiday{&next_date($easter)} = 1; # Easter Monday
#
# Bank hols on first & last monday in May + last monday in August
#
$testday = &day_of_week (1,5,$year);
if ($testday == 1) {
$holiday{&join_date(1,5,$year)} = 1;
} else {
$holiday{&join_date((9 - $testday),5,$year)} = 1;
}
$testday = &day_of_week (31,8,$year);
$holiday{&join_date((32 - $testday),8,$year)} = 1;
#
# ... unless it's 2002 (god bless you ma'am)
#
if ($year == 2002) {
$holiday{&join_date(3,6,2002)} = 1;
$holiday{&join_date(4,6,2002)} = 1;
} else {
$testday = &day_of_week (31,5,$year);
$holiday{&join_date((32 - $testday),5,$year)} = 1;
}
#
# Christmas Day & Boxing Day, unless they fall on a weekend
#
$testday = &day_of_week (25,12,$year);
if ($testday > 5) {
$holiday{&join_date(27,12,$year)} = 1;
$holiday{&join_date(28,12,$year)} = 1;
} elsif ($testday == 5) {
$holiday{&join_date(25,12,$year)} = 1;
$holiday{&join_date(28,12,$year)} = 1;
} else {
$holiday{&join_date(25,12,$year)} = 1;
$holiday{&join_date(26,12,$year)} = 1;
}
return (%holiday);
}
1;