Jump to content

Holiday Calculation Script


aesthetics1
Go to solution Solved by lemmin,

Recommended Posts

Hi there. I'm having trouble with a holiday calculation script. I picked it up online and have simply added/removed a few holidays to fit my needs.

 

It seems to calculate everything properly, except for Cesar Chavez day (March 31st).

 

The script basically looks for the holiday, and then determines what day of the week it falls on. If it's a weekday, great. If it's on a Saturday, then Friday is the observed day, so it should return Friday. If it's Sunday, it should return Monday.

 

As I said above, it works for the most part, but Cesar Chavez day won't compute (returns Jan 1 1970 date) in 2013, 2019, etc.

 

Looking at my code, can anyone determine what's going on?

 

Thanks in advance.

<?php

/* US Holiday Calculations in PHP
 * Version 1.02
 * by Dan Kaplan <design@abledesign.com>
 * Last Modified: April 15, 2001
 * ------------------------------------------------------------------------
 * The holiday calculations on this page were assembled for
 * use in MyCalendar:  http://abledesign.com/programs/MyCalendar/
 * 
 * USE THIS LIBRARY AT YOUR OWN RISK; no warranties are expressed or
 * implied. You may modify the file however you see fit, so long as
 * you retain this header information and any credits to other sources
 * throughout the file.  If you make any modifications or improvements,
 * please send them via email to Dan Kaplan <design@abledesign.com>.
 * ------------------------------------------------------------------------
*/

if(isset($_POST['year']))
{
	$current_year = $_POST['year'];
} else {
	$current_year = date('Y');
}

// Gregorian Calendar = 1583 or later
if (!$current_year || ($current_year < 1583) || ($current_year > 4099)) {
    $current_year = date("Y",time());    // use the current year if nothing is specified
}

function format_date($year, $month, $day) {
    // pad single digit months/days with a leading zero for consistency (aesthetics)
    // and format the date as desired: YYYY-MM-DD by default

    if (strlen($month) == 1) {
        $month = "0". $month;
    }
    if (strlen($day) == 1) {
        $day = "0". $day;
    }
    $date = $year ."-". $month ."-". $day;
    return $date;
}

// the following function get_holiday() is based on the work done by
// Marcos J. Montes: http://www.smart.net/~mmontes/ushols.html
//
// if $week is not passed in, then we are checking for the last week of the month
function get_holiday($year, $month, $day_of_week, $week="") {
    if ( (($week != "") && (($week > 5) || ($week < 1))) || ($day_of_week > 6) || ($day_of_week < 0) ) {
        // $day_of_week must be between 0 and 6 (Sun=0, ... Sat=6); $week must be between 1 and 5
        return FALSE;
    } else {
        if (!$week || ($week == "")) {
            $lastday = date("t", mktime(0,0,0,$month,1,$year));
            $temp = (date("w",mktime(0,0,0,$month,$lastday,$year)) - $day_of_week) % 7;
        } else {
            $temp = ($day_of_week - date("w",mktime(0,0,0,$month,1,$year))) % 7;
        }
        
        if ($temp < 0) {
            $temp += 7;
        }

        if (!$week || ($week == "")) {
            $day = $lastday - $temp;
        } else {
            $day = (7 * $week) - 6 + $temp;
        }

        return format_date($year, $month, $day);
    }
}

function observed_day($year, $month, $day) {
    // sat -> fri & sun -> mon, any exceptions?
    //
    // should check $lastday for bumping forward and $firstday for bumping back,
    // although New Year's & Easter look to be the only holidays that potentially
    // move to a different month, and both are accounted for.

    $dow = date("w", mktime(0, 0, 0, $month, $day, $year));
    
    if ($dow == 0) {
        $dow = $day + 1;
    } elseif ($dow == 6) {
        if (($month == 1) && ($day == 1)) {    // New Year's on a Saturday
            $year--;
            $month = 12;
            $dow = 31;
        } else {
            $dow = $day - 1;
        }
    } else {
        $dow = $day;
    }

    return format_date($year, $month, $dow);
}

function calculate_easter($y) {
    // In the text below, 'intval($var1/$var2)' represents an integer division neglecting
    // the remainder, while % is division keeping only the remainder. So 30/7=4, and 30%7=2
    //
    // This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
    // Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
    // 1876. This algorithm has also been published in the 1922 book General Astronomy by
    // Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
    // 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus. 

    $a = $y%19;
    $b = intval($y/100);
    $c = $y%100;
    $d = intval($b/4);
    $e = $b%4;
    $f = intval(($b+8)/25);
    $g = intval(($b-$f+1)/3);
    $h = (19*$a+$b-$d-$g+15)%30;
    $i = intval($c/4);
    $k = $c%4;
    $l = (32+2*$e+2*$i-$h-$k)%7;
    $m = intval(($a+11*$h+22*$l)/451);
    $p = ($h+$l-7*$m+114)%31;
    $EasterMonth = intval(($h+$l-7*$m+114)/31);    // [3 = March, 4 = April]
    $EasterDay = $p+1;    // (day in Easter Month)
    
    return format_date($y, $EasterMonth, $EasterDay);
}

/////////////////////////////////////////////////////////////////////////////
// end of calculation functions; place the dates you wish to calculate below
/////////////////////////////////////////////////////////////////////////////

?>



<?php

// format to use:
//
// get_holiday("year", "month", "day_of_week", "week_of_month");
// get_holiday("year", "month", "day_of_week);    // no 4th field indicates last week of month check
// format_date("year", "month", "day");
?>
<div class="clearfix">
	<form action="index.php?section=holidays" method="post">
		<p><b>Enter a Year:</b></p>
		<p class="float-left"><input type="text" name="year" value="<?php echo $current_year; ?>" size="4" maxlength="4"></p>
		<p class="float-left"><input class="button grey small" type="submit" value="Go"></p>
	</form>
</div>

<?php
echo "<p><b>".$current_year." Holidays</b></p>";
echo '<ul class="bullets">';

echo "<li>New Year's Day ". date("F d, Y", strtotime(observed_day($current_year, 1, 1)));
echo "<li>Lincoln Day ". date("F d, Y", strtotime(format_date($current_year, 2, 12)));
echo "<li>Martin Luther King Day Observed (Third Monday in January) = ". date("F d, Y", strtotime(get_holiday($current_year, 1, 1, 3)));
echo "<li>President's Day Observed (Third Monday in February) = ". date("F d, Y", strtotime(get_holiday($current_year, 2, 1, 3)));
echo "<li>Cesar Chavez Day = ". date("F d, Y", strtotime(observed_day($current_year, 3, 31)));
echo "<li>Memorial Day Observed (Last Monday in May) = ". date("F d, Y", strtotime(get_holiday($current_year, 5, 1)));
echo "<li>Independence Day Observed = ". date("F d, Y", strtotime(observed_day($current_year, 7, 4)));
echo "<li>Labor Day Observed (First Monday in September) = ". date("F d, Y", strtotime(get_holiday($current_year, 9, 1, 1)));
echo "<li>Columbus Day Observed (Second Monday in October) = ". date("F d, Y", strtotime(get_holiday($current_year, 10, 1, 2)));
// Veteran's Day Observed - November 11th ?
echo "<li>Thanksgiving (Fourth Thursday in November) = ". date("F d, Y", strtotime(get_holiday($current_year, 11, 4, 4)));
echo "<li>Day After Thanksgiving (Friday after Thanksgiving) = ". date("F d, Y", strtotime("+1 day", strtotime(get_holiday($current_year, 11, 4, 4))));
echo "<li>Christmas Day = ". date("F d, Y", strtotime(observed_day($current_year, 12, 25)));

echo "</ul>";

?>
Link to comment
Share on other sites

if ($dow == 0) {
$dow = $day + 1;
You don't have anything that wraps the last day of the month on Sunday to be the Monday in the next month. Same way you don't have anything that wraps the first day of the month on Saturday to be the Friday of the previous month.
Link to comment
Share on other sites

  • Solution

It even references it in the comments hehe:

    // although New Year's & Easter look to be the only holidays that potentially
    // move to a different month, and both are accounted for.

 

 

Try changing that function to this:

function observed_day($year, $month, $day) {
    // sat -> fri & sun -> mon, any exceptions?
	
    $dow = date("w", mktime(0, 0, 0, $month, $day, $year));
	$daystring = $year . '-' . $month . '-' . $day;
	
	if ($dow == 0)
		return $daystring . ' +1 day';
	elseif ($dow == 6)
		return $daystring . ' -1 day';
		
	return $daystring;
}
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.