Simple Machines Community Forum

Archived Boards and Threads... => Archived Boards => Parham's PHP Tutorials => Topic started by: Parham on May 11, 2004, 06:01:43 PM

Title: PHP Code 01 - Calendar Script
Post by: Parham on May 11, 2004, 06:01:43 PM
Let's make a calendar

While this style of tutorial will be fairly new, it will help readers apply what they have learned through the previous tutorials.  Tutorials from this point on will consist of short pieces of code with examples and line-by-line explanations.

We're going to make a calendar because it's a very simple way of applying basic loops and if statements to code.  It will also help new programmers understand basic thought processes and techniques to coding.

There are a few things you should note when making a calendar.  First of all, every month has a certain amount of days.  In English, the rule is "Thirty days hath September, April, June, and November".  The rest of the months all have thirty-one days except for February which has either 28 or 29 days depending on the year.  This isn't the biggest obstacle we have to face; the biggest obstacle is the fact that the beginning of each month starts on a different day (Sunday through Saturday as is the norm).

So let's start coding this thing and see what we can do.  The most important function we will use is the date() function (http://www.php.net/manual/en/function.date.php).  The date function will be able to get us all the information we'll need.

The script will have to know what month we are in:

$month = date('n');


It will also need to know the year:

$year = date('Y');


We will also need to know how many days are in the current month also, and we can use this to get that number:

$days_in_month = date('t');


We have some very basic information now, but we need some more information.  We need to know what day the current month starts on.  Our week starts on a Sunday and ends on a Saturday (which also happens to be how PHP works, so we can print that information out:


print "SU\tMO\tTU\tWE\tTH\tFR\tSA\n";


We used tabs in-between for uniform spacing.  It also helps us from having to work with calculating spaces to separate numbers.  To find what part of the week the first day of the month falls on, we can use the following code:


$first_day_of_month = date('w',mktime(1,1,1,$month,1,$year));


The code is very simple to understand.  "w" is the numeric representation of the day of the week, 0 (for Sunday) through 6 (for Saturday).  mktime() returns a Unix timestamp for a given date input.

int mktime ( [int hour [, int minute [, int second [, int month [, int day [, int year [, int is_dst]]]]]]])

so we simply tell PHP to give us the weekday of the first hour, minute, second, and day of the current month and year.  If that confuses you, try to match up the parameter list with the code above and it will help clear things up.  Up to now, we have all the basic information we need to build our calendar script:


$month = date('n'); //what month are we in?
$year = date('Y'); //what year are we in?
$first_day_of_month = date('w',mktime(1,1,1,$month,1,$year)); //get the first day of the month
$days_in_month = date('t'); //how many days in this month


Because we know the first day of the month doesn't start on the same weekday everyday, and we know how we will be representing our weekday ("su\tmo\ttu\twe\tth\tfr\tsa"), we have to somehow move ahead to the first day of the month, and begin counting from there all the way up to the last day of the month.

To do this, we can use a simple loop:

for ($spacer = 0; $spacer < $first_day_of_month; $spacer++) {
  print "  \t";
}


The loop counts from zero, right until before the weekday of the first day of the month.  We use two spaces and a tab to keep consistent with our weekday representations which consist of two letters and a tab.  We will subsequently make sure that our number outputs also have two digits and a tab.  This will line everything up.

Now that we've made enough spaces to know that we are at the first day of the month, we just have to keep looping until the last day of the month.


for ($x = 1; $x <= $days_in_month; $x++) {
  if ($spacer >= 7) { print "\n"; $spacer = 0; }
  if (strlen($x) == 1) { $x = "0$x"; }
  print "$x\t";
  $spacer++;
}


This code begins a loop starting from 1 to the number of days in the month ($days_in_month).  We will continue taking advantage of the $spacer variable we declared before.  We will use this to know when to go to the next line.  The second line in the above code manages when to go to the next line (this happens when we reach the end of the week, a Saturday).  When we reach the end of the week, we reset the $spacer counter to zero and go to the next line.  "if (strlen($x) == 1) { $x = "0$x"; }" takes care of spacing issues.  Because we want all of our output to be in double digits, we can use a simple statement to get double digits if we have single digits.

The final code with excessive commenting:


<?php

$day 
date('j'); //what day is it today
$month date('n'); //what month are we in?
$year date('Y'); //what year are we in?
//get the first first day of the month
$first_day_of_month date('w',mktime(1,1,1,$month,1,$year));
$days_in_month date('t'); //how many days in this month

print "SU\tMO\tTU\tWE\tTH\tFR\tSA\n"//print the weekday headers
//count ahead to the weekday of the first day of the month
for ($spacer 0$spacer $first_day_of_month$spacer++) {
  print "  \t";
}

for (
$x 1$x <= $days_in_month$x++) { //begin our main loop
  //if we have gone past the end of the week, go to the next line
  if ($spacer >= 7) { print "\n"$spacer 0; }
  //if the length of the current day is one, put a "0" in front of it
  if (strlen($x) == 1) { $x "0$x"; }
  if ($x == $day) { //is this day the current day
    print "$x^\t"//if so put an indicator
  } else {
    print "$x\t"//otherwise just print it
  }
  $spacer++; //increment our spacer
}

?>



We could have taken a few shortcuts here, but I wanted to use as many simple statements as possible.  The output of this script for the current month is:

Quote
SU   MO   TU   WE   TH   FR   SA
                              01   
02   03   04   05   06   07   08   
09   10   11^   12   13   14   15   
16   17   18   19   20   21   22   
23   24   25   26   27   28   29   
30   31   

Note that I added extra code to recognize what day in the month we are on.
Title: Re: PHP Code 01 - Calendar Script
Post by: [Unknown] on May 12, 2004, 01:00:59 AM
Quote from: Parham on May 11, 2004, 06:01:43 PM

print "SU\tMO\tTU\tWE\tTH\tFR\tSA\n";

I would recommend:

echo 'SU', "\t", 'MO', "\t", 'TU', "\t", 'WE', "\t", 'TH', "\t", 'FR', "\t", 'SA', "\n";


Because it is leagues easier to read and understand.

Quote
$first_day_of_month = date('w',mktime(1,1,1,$month,1,$year));

Sorry, spacing fanatic here:
// Second 1, minute 1, hour 1, day 1, of that month on that year.
$first_day_of_month = date('w', mktime(1, 1, 1, $month, 1, $year));


Again I think it's clearer to read with spacing.

Quoteour weekday ("su\tmo\ttu\twe\tth\tfr\tsa")

Ehm, same as above.

Quote
for ($x = 1; $x <= $days_in_month; $x++) {
  if ($spacer >= 7) { print "\n"; $spacer = 0; }
  if (strlen($x) == 1) { $x = "0$x"; }
  print "$x\t";
  $spacer++;
}

I'm crazy about spacing, again:


// Do every day in this month.
for ($x = 1; $x <= $days_in_month; $x++) {

  // Have we gotten to the end of the week yet..?
  if ($spacer >= 7) {
    // Okay, go to the next line and start back at day #0. (Sunday)
    print "\n"; $spacer = 0;
  }

  // Is this a single digit, like 5?  We like two digit numbers.
  if (strlen($x) == 1) { $x = "0$x"; }

  // Output the day of month...
  print "$x\t";

  // Next day of the week. (Monday -> Tuesday.... Thursday -> Friday -> TGIF!)
  $spacer++;
}


Although you know I'm not a fan of the interpolating.

Quote
<?php

$day 
date('j'); //what day is it today
$month date('n'); //what month are we in?
$year date('Y'); //what year are we in?
//get the first first day of the month
$first_day_of_month date('w',mktime(1,1,1,$month,1,$year));
$days_in_month date('t'); //how many days in this month

print "SU\tMO\tTU\tWE\tTH\tFR\tSA\n"//print the weekday headers
//count ahead to the weekday of the first day of the month
for ($spacer 0$spacer $first_day_of_month$spacer++) {
  print 
"  \t";
}

for (
$x 1$x <= $days_in_month$x++) { //begin our main loop
  //if we have gone past the end of the week, go to the next line
  
if ($spacer >= 7) { print "\n"$spacer 0; }
  
//if the length of the current day is one, put a "0" in front of it
  
if (strlen($x) == 1) { $x "0$x"; }
  if (
$x == $day) { //is this day the current day
    
print "$x^\t"//if so put an indicator
  
} else {
    print 
"$x\t"//otherwise just print it
  
}
  
$spacer++; //increment our spacer
}

?>


I just feel, for this code, the "compactness" and "perl-like-ness" of the code makes it a little hard to understand.  Like I try to break my posts up into small paragraphs, I like to break my code into chunks so each part can be digested and it looks simpler to the eye.

But, I do know you're a Perl fan.

-[Unknown]
Title: Re: PHP Code 01 - Calendar Script
Post by: Parham on May 12, 2004, 01:39:47 AM
when you refer to compactness, are you talking about the shortness of the code, or just how clumped up the code itself is?  i realized after writing it that this was probably not the BEST one to start off with, as it takes some thinking and understanding.  i just never figured there would be so much to explain for such little code.  i wrote it, understood it, and that was the code since then.

my commenting also tends to suck, but some comments are better than no comments.  if it was up to me, i would hardly comment my code, at least the obvious parts.
Title: Re: PHP Code 01 - Calendar Script
Post by: [Unknown] on May 12, 2004, 12:15:09 PM
Well, imho compactness is an enemy to readability... muchlikeskippingspacesinsenetences,ornotbotheringtousefullstopsandstufflikethatbutitcanstillbereadableifyou'reaccustomedtoit.

Yes, it looks *WAY* longer when it's commented and spaced out, but it also reads and makes sense faster.  Shorter, clumped code, looks confusing.  Or at least so I remember and think.

-[Unknown]