Calendar for Custom Year

PHP source code and discussion

The calendar generator has been written in PHP 5 and the source code can be viewed here. It may be used and altered in any way. You can create tables for a year with it or also display a custom number of days from any starting date (e.g. to display the next 100 days as of today).

Technical Description

The core of the calendar generator are the methods createMatrix($date, $numberOfDays) and createYearMatrix($year). The former generates a two-dimensional array representing a layout table, i.e. each entry in the first dimension ($matrix[1]) is a row and every entry in there is a specific field ($matrix[1][0]), containing the date's day.

For example, createMatrix($date, 21) with $date being a timestamp for 2015-05-04 (a Monday), will return:

   |[0]|[1]|[2]|[3]|[4]|[5]|[6]
[0]|  4|  5|  6|  7|  8|  9| 10
[1]| 11| 12| 13| 14| 15| 16| 17
[2]| 18| 19| 20| 21| 22| 23| 24

The method createYearMatrix($year) generates such a matrix per month for you, i.e. it will return an array of twelve elements where each field contains the matrix of the month.

If you just want to display a year's calendar, simply call generateYearHtml($year) and it will take care of the details for you. The output HTML contains CSS classes so you can refine the output to your wishes. You can view the calendar CSS rules that this demo page uses as an example.

Similarly, generateHtmlTable($matrix) will generate a HTML table from a given matrix. For more control, you can use the method generatePlainTable or generateYearPlainOutput which lets you define all the texts before/after a row, between the cells, etc. (Hint: generateHtmlTable is just a custom call to generatePlainTable.)

For more specific use cases, you can always extend or modify the class to your wishes or just take the matrix and use your own displaying function, as shown here below.

Example: Work Week Only

If you want to generate a work week calendar, you could remove the last two entries from each row and call it a day. The following shows a possible solution (in particular, notice how $matrix is assigned).

$generator = new CalendarGenerator();
function 
removeWeekend($row) {
  return 
array_slice($row05);
}

$fullMatrix $generator->createYearMatrix(2015);
$matrix array_map(function ($month) {
  return 
array_map('removeWeekend'$month);
}, 
$fullMatrix);

// Display workday matrix
$i 1;
foreach (
$matrix as $month) {
  echo 
"\n<h2>" $generator->getMonthNames()[$i] . '</h2>';
  echo 
'<table><tr><th>' implode('</th><th>', ['Mon','Tue','Wed','Thu','Fri']) . '</th></tr>';
  foreach (
$month as $row) {
    echo 
"\n<tr><td>" implode('</td><td>'$row) . '</td></tr>';
  }
  echo 
'</table>';
  ++
$i;
}

Example: Show Month Next to Table

The year output function shows the month, but this is not the case for createMatrix(). To programmatically know the current month in a large table, you could check when the current row has a smaller date than the current one, e.g. if the above row displays the date "25" and the next one has date "1", you know that the month has changed. The following is a possible way to do this. In particular, note how we use $currentMonth and when it is updated.

$matrix $generator->createMatrix(mktime(1200542015), 120);
$totalRows count($matrix);
$currentMonth 4// -1 of the current month to compensate ++
$months $generator->getMonthNames();

echo 
'<table><tr><th>Month</th><th>'
  
implode('</th><th>', ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'])
  . 
'</th></tr>';
for (
$i 0$i $totalRows; ++$i) {
  echo 
"\n<tr><td>";
  if (
$i === || $matrix[$i][0] < $matrix[$i-1][0]) {
    
$currentMonth = (++$currentMonth 12) ? $currentMonth;
    echo 
$months[$currentMonth];
  }
  echo 
'</td><td>' implode('</td><td>'$matrix[$i]) . '</td></tr>';
}
echo 
'</table>';

For large number of days, the code could be expanded to also display the year for every January.

Limits and Caveats

The calendar generator heavily relies on PHP's built-in date functions and therefore, one must not forget about the limits of Unix time. For most systems, this means you should only use it for years 1901 - 2037.

As commented in the utility function makeTime(), daylight savings time plays a dirty trick on you if you pass a timestamp with a time early in the morning (before 2 AM). If you iteratively add the number of seconds in a day to a timestamp in order to advance one day, you might get a day twice because we go one hour back as we exit DST. Pass timestamps with a later time, or use the utility function (sets the time to 12 PM).

We see in both examples that as soon as we want more control over the output, we have to write our own display function. The examples are hopefully a sufficient reference for such situations. I think for many cases it might make sense to use the matrix and to write your own display logic. A sort of template system with tags may have been a better approach in the calendar generator.

Lastly, as always, if you allow week names or month names to come from user input, it must be treated with caution. The plain output functions have an option whether the names of the months and week days should be HTML-escaped or not. Other contexts might require different types of escaping or sanitization.