Generate a calendar with PHP

Please note: This post was written 5 years ago, which is an age in programming terms, so please don't treat this as gospel! I'll be updating all posts soon enough, but if you'd especially like this one to be updated let me know.

I only code on days ending in Y

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.

***

If you found this particularly useful and want to share the ♥ you can donate here.

***

6 Responses

  1. Baldford

    I would like to see how to create a calendar with events and being able to send it both to email and database. thanks

    Reply
    • Tom

      You would just create a separate table in which to store events, and when iterating over the days query that table for the date that is currently being out-putted.

      Reply
  2. vignesh

    nice one

    Reply
  3. Tim

    Thank you for making the first decent calendar to show up on google

    Reply
  4. Adib

    good tutorial. I want to ask you something, if you not mind.
    echo ''. $date . '';
    what the function of this line?

    Reply
    • Tom

      That line outputs the contents of the $date variable to the browser.

      Reply


~ Comments are now closed ~

Get in touch here