This PHP program creates a calendar that calculates various holidays and displays them, along with randomly-generated events.
<!DOCTYPE html>
<html>
<head>
<style>
.cArrow{
font-size:20px;
font-weight: bolder;
margin: 0px 20px;
background-color: gray;
color:white;
padding-top:2px;
padding-bottom:2px;
border-radius: 10px;
border:5px outset black;
}
.cArrow:hover {
background-color: lightgray;
}
.cCenter {
width: fit-content;
margin-left: auto;
margin-right: auto;
}
body {
font-family: arial, sans-serif;
}
h1 {
line-height: 120%;
padding: 15px 0px 0px 0px;
margin: 5px 0px 0px 0px;
border-width: 5px 0px 0px 0px;
}
th {
padding:2px;
border: none;
}
td {
border: 1px solid black;
padding:2px 5px;
text-align:center;
}
.cMonthTable {
float: left;
margin: 5px 10px;
border-collapse: collapse;
}
.cMonthRow {
width: fit-content;
margin-left: auto;
margin-right: auto;
}
.cAppointment {
background-color: #FF000060;
}
.cReview {
background-color: #00FF0060;
}
.cMeeting {
background-color: #0000FF60;
}
.cAppointment.cReview {
background: linear-gradient(90deg, #FF000060, #FF000060 50%,#00FF0060 50%,#00FF0060);
}
.cAppointment.cMeeting {
background: linear-gradient(90deg, #FF000060, #FF000060 50%,#0000FF60 50%,#0000FF60);
}
.cReview.cMeeting {
background: linear-gradient(90deg, #00FF0060, #00FF0060 50%,#0000FF60 50%,#0000FF60);
}
.cAppointment.cReview.cMeeting {
background: linear-gradient(90deg, #FF000060, #FF000060 33%,#00FF0060 33%,#00FF0060 66%,#0000FF60 66%,#0000FF60);
}
.cHoliday {
background: repeating-conic-gradient(lightgray 0 25%, white 0 50%);
background-position: 0 0, 32px 32px;
background-size: 8px 8px;
}
</style>
<script>
var gqEvents = null;
var giYearIndex = 1;
function DecrementYear() {
if (giYearIndex > 0) {
--giYearIndex;
CreateSchedule();
}
}
function IncrementYear() {
if (giYearIndex < gqEvents.miaYears.length - 1) {
++giYearIndex;
CreateSchedule();
}
}
function GetRouteScheduleViaAjax(sRoute) {
// The event arrays must be create to be the corrent size for each month
gqEvents = {miaYears:[2024,2025,2026],
msaEventNames:["Appointment", "Review", "Meeting"],
muiaaaEvents:[[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],
[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]]};
// Randomly change some of the events
for (var i = 0; i < 40; ++i) {
// Get a random year
var iYear = Math.floor(Math.random()*gqEvents.miaYears.length);
// Get a random month
var iMonth = Math.floor(Math.random()*12);
// Get a random date
const kiDatesInMonth = gqEvents.muiaaaEvents[iYear][iMonth].length;
var iDate = Math.floor(Math.random()*kiDatesInMonth);
// Get a random event number 0 - 7
var iEvent = Math.floor(Math.random()*8);
gqEvents.muiaaaEvents[iYear][iMonth][iDate] = iEvent;
}
CreateSchedule();
}
function CreateSchedule() {
// Reset the year index, if necessary.
if (giYearIndex > gqEvents.miaYears.length - 1) {
giYearIndex = gqEvents.miaYears.length - 1;
}
// Hide the unnecessary year alteration buttons.
// If the year index is zero hide the left button. If it is length -1, hide the right button.
// Get the arrow button array of two buttons
var qaArrowButtons = document.getElementsByClassName("cArrow");
if (giYearIndex <= 0) {
qaArrowButtons[0].style.visibility = "hidden";
} else {
qaArrowButtons[0].style.visibility = "visible";
}
if (giYearIndex >= gqEvents.miaYears.length - 1) {
qaArrowButtons[1].style.visibility = "hidden";
} else {
qaArrowButtons[1].style.visibility = "visible";
}
// Set the year for display
var iYear = gqEvents.miaYears[giYearIndex];
document.getElementById("idYear").innerHTML = "Calendar " + iYear;
// Get the holiday array
var qaHolidays = GetOrderedHolidays(iYear);
var iCurrentHolidayIndex = 0;
var uiaaCurrentYear = gqEvents.muiaaaEvents[giYearIndex];
for (var iMonth = 0; iMonth < 12; ++iMonth) {
// Get the month table
var qMonthTable = document.getElementById("idMonth"+iMonth).children[0];
var qFirstDayOfTheMonth = new Date(iYear, iMonth, 1);
var iFirstDayOfMonthIndex = qFirstDayOfTheMonth.getDay();
var qEndOfMonth = new Date(iYear, iMonth + 1, 0);
var iEndOfMonthDate = qEndOfMonth.getDate();
var iCurrentDate = -iFirstDayOfMonthIndex;
// Start at the third row
for (var iDateRow = 2; iDateRow < 8; ++iDateRow) {
var qDateRow = qMonthTable.children[iDateRow];
// Reset the date row class; it may get set by the holiday check later
qDateRow.className = "";
for (var iDayOfWeek = 0; iDayOfWeek < 7; ++iDayOfWeek) {
var qDateElement = qDateRow.children[iDayOfWeek];
qDateElement.className = "";
if (iCurrentDate >= 0 && iCurrentDate < iEndOfMonthDate) {
qDateElement.innerHTML = iCurrentDate + 1;
for (var i = 1; i < 8; i <<= 1) {
if ((uiaaCurrentYear[iMonth][iCurrentDate] & i) == i) {
switch (i) {
case 1:
qDateElement.className += "cAppointment ";
break;
case 2:
qDateElement.className += "cReview ";
break;
case 4:
qDateElement.className += "cMeeting ";
break;
}
}
}
} else {
qDateElement.innerHTML = " ";
}
++iCurrentDate;
// Check for a holiday
if (iCurrentHolidayIndex < qaHolidays.length) {
var qNextHoliday = qaHolidays[iCurrentHolidayIndex];
// If today is a holiday, color it.
if (qNextHoliday.getMonth() == iMonth && qNextHoliday.getDate() == iCurrentDate) {
qDateElement.className += "cHoliday";
++iCurrentHolidayIndex;
}
}
}
}
}
}
function GetOrderedHolidays(iYear) {
// Remember that months are zero-based and dates are not.
var qaHolidays = new Array();
// Add New Year's Day
qaHolidays.push(new Date(iYear, 0, 1));
// Add in Easter day
qaHolidays.push(CalculateEasterDay(iYear));
// Add Memorial day (last Monday of May)
var qEndOfMonth = new Date(iYear, 5, 0);
var iLastDateInMay = qEndOfMonth.getDate();
var iLastDayInMay = qEndOfMonth.getDay(); // Monday is the 2nd day or 1
var iDateOfMemorialDay = iLastDateInMay - (((iLastDayInMay - 1) + 7) % 7);
qaHolidays.push(new Date(iYear, 4, iDateOfMemorialDay));
// Add the 4th of July
qaHolidays.push(new Date(iYear, 6, 4));
// Add in Labor Day (first Monday of September)
var qSept1 = new Date(iYear, 8, 1);
var qLaborDate = ((1 - qSept1.getDay() + 7) % 7) + 1;
qaHolidays.push(new Date(iYear, 8, qLaborDate));
// Add Thanksgiving (fourth sunday of November) - days of the week are zero based
var qNov1 = new Date(iYear, 10, 1);
var iThanksgivingDate = ((4 - qNov1.getDay() + 7) % 7) + 22;
qaHolidays.push(new Date(iYear, 10, iThanksgivingDate));
// Add Christmas
qaHolidays.push(new Date(iYear, 11, 25));
return qaHolidays;
}
// This is the calculation for Easter. All division is integer-based.
// y = year, m = month, d = day of the month
// Reference: https://aa.usno.navy.mil/faq/easter
//----------------------------------------------------------------
// c = y / 100
// n = y - 19 * ( y / 19 )
// k = ( c - 17 ) / 25
// i = c - c / 4 - ( c - k ) / 3 + 19* n + 15
// i = i - 30 * ( i / 30 )
// i = i - ( i / 28 ) * ( 1 - ( i / 28 ) * ( 29 / ( i + 1 ) ) * ( ( 21 - n ) / 11 ) )
// j = y + y / 4 + i + 2 - c + c / 4
// j = j - 7 * ( j / 7 )
// l = i - j
// m = 3 + ( l + 40 ) / 44
// d = l + 28 - 31 * ( m / 4 )
function CalculateEasterDay(iYear) {
const kiC = Math.floor(iYear/100);
const kiN = iYear - (19*Math.floor(iYear/19));
const kiK = Math.floor((kiC - 17)/25);
var iI = kiC - Math.floor(kiC/4) - Math.floor((kiC - kiK)/3) + 19*kiN + 15;
iI = iI - 30*Math.floor(iI/30);
iI = iI - Math.floor(iI/28)*(1 - Math.floor(iI/28)*Math.floor(29/(iI+1))*Math.floor((21 - kiN)/11));
var iJ = iYear + Math.floor(iYear/4) + iI + 2 - kiC + Math.floor(kiC/4);
iJ = iJ - 7 * Math.floor(iJ/7);
const kiL = iI - iJ;
const kiM = 3 + Math.floor((kiL + 40)/44);
const kiD = kiL + 28 - 31*Math.floor(kiM/4);
// Subtract 1 because the months are zero-based.
return new Date(iYear, kiM - 1, kiD);
}
</script>
</head>
<body onload="GetRouteScheduleViaAjax('A')">
<div class="cCenter">
<button class="cArrow" type="button" onclick="DecrementYear()">⇦</button>
<h1 style="display:inline;" id="idYear"></h1>
<button class="cArrow" type="button" onclick="IncrementYear()">⇨</button>
</div>
<div id="idCalendar" class="text-center">
<?php
// Add in the month tables.
$saMonths = array();
array_push($saMonths, "January");
array_push($saMonths, "February");
array_push($saMonths, "March");
array_push($saMonths, "April");
array_push($saMonths, "May");
array_push($saMonths, "June");
array_push($saMonths, "July");
array_push($saMonths, "August");
array_push($saMonths, "September");
array_push($saMonths, "October");
array_push($saMonths, "November");
array_push($saMonths, "December");
for ($iRow = 0; $iRow < 3; ++$iRow) {
echo '<div class="cMonthRow">';
for ($iCol = 0; $iCol < 4; ++$iCol) {
$iMonthIndex = 4*$iRow + $iCol;
$sMonth = $saMonths[$iMonthIndex];
$sMonthId = "idMonth".$iMonthIndex;
// Start with the months as empty tables of dates
echo '<table cellspacing="0" cellpadding="0" border="1" id="'.$sMonthId.'" class="cMonthTable">';
echo '<tr><th colspan="7">'.$sMonth.'</th></tr>';
echo '<tr><th>S</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th></tr>';
// Create the 6 rows of potential weeks
for ($iWeek = 0; $iWeek < 6; ++$iWeek) {
echo '<tr>';
for ($iWeekday = 0; $iWeekday < 7; ++$iWeekday) {
echo '<td> </td>';
}
echo '</tr>';
}
echo '</table>';
}
echo '</div>';
}
?>
<div style="clear:both;"></div>
<div class="cCenter">
<table>
<tr>
<td style="border:none;"><div class="cAppointment" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Appointment Date</td>
<td style="border:none;"><div class="cReview" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Review Date</td>
<td style="border:none;"><div class="cMeeting" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Meeting Date</td>
</tr>
<tr>
<td style="border:none;"><div class="cAppointment cReview" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Appointment and Review Date</td>
<td style="border:none;"><div class="cAppointment cMeeting" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Appointment and Meeting Date</td>
<td style="border:none;"><div class="cReview cMeeting" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Review and Meeting Date</td>
</tr>
<tr>
<td style="border:none;"><div class="cAppointment cReview cMeeting" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Appointment, Review, and Meeting Date</td>
<td style="border:none;"><div class="cHoliday" style="width:20px;height:20px;border:1px solid black;"></div></td>
<td style="border:none;text-align:left;">Holiday</td>
</tr>
</table>
</div>
<div style="clear:both;"></div>
</body>
</html>
© 20072025 XoaX.net LLC. All rights reserved.