I only code on days ending in Y

Generate a calendar with PHP

Note: This article has been marked for a quality review and will soon be updated.

Calendars are useful for a wide variety of things, least of all planning and recording events that are going to happen in the future, and while it may not be obvious at first, there a are a number of challenges in creating a dynamic calendar with PHP. In this tutorial I will show you the basics of what you need to get started. See an example of what we will be creating here.

Let's first think about what we are creating. We want a standard calendar that will display dates month by month, and in this tutorial we will make it dynamic as to display the current month, and highlight the current day. But unfortunately this isn't as simple as printing out 31 days and labelling them up. Because calendars show dates preceding and succeeding the month, we need to display our data based on the day of the week that the month starts on, this is something we need to think about when designing the code. Not all months have 31 days in them either, so we need to build a system which adapts to each month.

Let's take a look at the PHP. First we will gather all the information we need about the month - we will be using the current month, but you could change the values of the following variables based on your needs.

$today = date("d"); // Current day
$month = date("m"); // Current month
$year = date("Y"); // Current year
$days = cal_days_in_month(CAL_GREGORIAN,$month,$year); // Days in current month

$lastmonth = date("t", mktime(0,0,0,$month-1,1,$year)); // Days in previous month
		
$start = date("N", mktime(0,0,0,$month,1,$year)); // Starting day of current month
$finish = date("N", mktime(0,0,0,$month,$days,$year)); // Finishing day of  current month
$laststart = $start - 1; // Days of previous month in calendar

Okay, so the code above utilises some inbuilt functions and stores al the data we need. Firstly we get today's date using PHP's date() function, having this will allow us to highlight the current day. We then collect the current month, year, and the number of days in the current month. All pretty standard so far. Then we go on to get the number of days in the month preceding the current month, as well as both the start and end date of the current month. We can use those variables to figure out an offset so that we can display the day on which the current month started correctly.

To that we will add the logic that will actually display the calendar:

$today = date("d"); // Current day
$month = date("m"); // Current month
$year = date("Y"); // Current year
$days = cal_days_in_month(CAL_GREGORIAN,$month,$year); // Days in current month

$lastmonth = date("t", mktime(0,0,0,$month-1,1,$year)); // Days in previous month

$start = date("N", mktime(0,0,0,$month,1,$year)); // Starting day of current month
$finish = date("N", mktime(0,0,0,$month,$days,$year)); // Finishing day of  current month
$laststart = $start - 1; // Days of previous month in calander

$counter = 1;
$nextMonthCounter = 1;

if($start > 5){	$rows = 6; }else {$rows = 5; }
for($i = 1; $i <= $rows; $i++){
	echo '<tr class="week">';
	for($x = 1; $x <= 7; $x++){				
		
		if(($counter - $start) < 0){
			$date = (($lastmonth - $laststart) + $counter);
			$class = 'class="blur"';
		}else if(($counter - $start) >= $days){
			$date = ($nextMonthCounter);
			$nextMonthCounter++;
			
			$class = 'class="blur"';
		
		}else {
			$date = ($counter - $start + 1);
			if($today == $counter - $start + 1){
				$class = 'class="today"';
			}
		}
				
			
		echo '<td '.$class.'><a class="date">'. $date . '</a></td>';
		
		$counter++;
		$class = '';
	}
	echo '</tr>';
}

Let's go over what that does. To begin with we figure out how many rows we are going to need by checking to see if the start day is greater than a Friday; if it is, we have 6 rows, otherwise we have 5. We then have a nested loop - one for the weeks, and one for the days in the weeks. Looking at the code we can see that the first loop runs as many times as there are rows, while the inner loop always loops 7 times. Then we have a fancy if statement to give us our date. In plain English, this is what it does: if the number of days already processed, take the starting day of the current month is less than 0, output a day from the last month - this makes sure we fill in the gaps, so if the current month started on a Tuesday, this code would get executed on the first iteration to display last month's Monday. If not, is the day in question part of next month? If so output the day with it's own date - nice an simple because all months start from 1.

And then we come to the last part of the if statement, which will be executed if the day in question is part of the current month. If it is today's date we give it a class of "today". Then we output the variables, increment our counter variable to keep track of the current day, and reset our $class variable.

So to put it all together within a table we would have:

<section id="content" class="planner">	
<h2><?php echo date("F Y") ?></h2>

<table class="month">
	<tr class="days">
		<td>Mon</td>
		<td>Tues</td>
		<td>Wed</td>
		<td>Thurs</td>
		<td>Fri</td>
		<td>Sat</td>
		<td>Sun</td>
	</tr>
<?php 
		
	$today = date("d"); // Current day
	$month = date("m"); // Current month
	$year = date("Y"); // Current year
	$days = cal_days_in_month(CAL_GREGORIAN,$month,$year); // Days in current month
	
	$lastmonth = date("t", mktime(0,0,0,$month-1,1,$year)); // Days in previous month
	
	$start = date("N", mktime(0,0,0,$month,1,$year)); // Starting day of current month
	$finish = date("N", mktime(0,0,0,$month,$days,$year)); // Finishing day of  current month
	$laststart = $start - 1; // Days of previous month in calander
	
	$counter = 1;
	$nextMonthCounter = 1;
	
	if($start > 5){	$rows = 6; }else {$rows = 5; }

	for($i = 1; $i <= $rows; $i++){
		echo '<tr class="week">';
		for($x = 1; $x <= 7; $x++){				
			
			if(($counter - $start) < 0){
				$date = (($lastmonth - $laststart) + $counter);
				$class = 'class="blur"';
			}else if(($counter - $start) >= $days){
				$date = ($nextMonthCounter);
				$nextMonthCounter++;
				
				$class = 'class="blur"';
					
			}else {
				$date = ($counter - $start + 1);
				if($today == $counter - $start + 1){
					$class = 'class="today"';
				}
			}
				
			
			echo '<td '.$class.'><a class="date">'. $date . '</a></td>';
		
			$counter++;
			$class = '';
		}
		echo '</tr>';
	}
	
?>
</table>
</section>	

If you wanted to add things like 'st' to each date, or even the day to each date you could use a case statement to switch on the $x variable - 1 being Monday, 2 being Tuesday, and so on. And that's that! Don't forget to style the classes that I added such as "blur" to those days that don't fall in the current month, as well as "today" to, well I'm sure you can figure that one out 😉 And as always check out the demo here.

Published by

Tom

http://fulltimeninja.com/tom

6 thoughts on “Generate a calendar with PHP”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.