Hello, first tutorial of what will hopefully be many. :)
Ever wanted to display a date and not known how to get "th" after your 7 to make December 7
th, 1941? Or wanted to show a visitor to a website that they were the 4,721st visitor?
Well, here's an easy way to add the proper ordinal to any number. There are tons of examples on how to do this out there, but I'll show you step by step how I constructed this routine. We'll also be hitting a wall and making adjustments as we go to illustrate how you should
test your routines and how you can easily make adjustments to code after the fact.
Okay let's get started. First, we want this to be usable in a variety of situations - something we can use in multiple scripts or web pages. So, using a
function is our best bet. If you don't know about functions, read up on them
here. They're an easy and economical way to create re-usable blocks of PHP code.
Ok, so we start out with a basic outline of a function. Don't worry if you are totally confused by the code below. We'll be going through it. Just glance it over and see if you can piece together what it's doing.
Code:
<?php
function show_ordinal($num) {
$the_num = (string) $num;
$last_digit = substr($the_num, -1, 1);
switch($last_digit) {
case "1":
$the_num.="st";
break;
case "2":
$the_num.="nd";
break;
case "3":
$the_num.="rd";
break;
default:
$the_num.="th";
}
return $the_num;
}
?>
Confused? If not that's great! If so, don't worry. Let's go through the function step by step.
1. The function starts with the declaration and the variable $num in parentheses. What we're doing is passing a value to the function to be processed. If we called
Code:
$the_date = show_ordinal("321");
we want $the_date to come back as "321st". A function usually will take a variable that is passed to it, process it in some way and then return a result.
2. The second line makes sure we are working with a string of characters rather than an integer. You could pass this function an int and have it return a string.
3. The third line grabs the last digit from our variable so we can evaluate what it is and add the proper suffix.
4. Next we have the switch statement. If you are not familiar with switch() you should be! It's a wonderful way to avoid using if else after if else. Our switch here looks at the last digit from the number we passed and adds the proper suffix based on what that last digit is. If it's a 1, we concatenate an "st". If it's a 2, we add an "nd". Etc. Pretty straightforward.
5. Finally, our last line passes the value back to our calling script. It might display it, or assign it to a variable - it all depends on how we call it.
That should be it right? Let's test it out! Save this function as "show_ordinal.inc.php". Quickly, the reason I always throw in the "inc" in my function filenames is so that I know it's not a standalone page. It's a function I can include on any page and use anywhere in my web site application.
Here's a quick test page I wrote up to test our new function. Save this one as "test_ordinal.php":
Code:
<?php
require("show_ordinal.inc.php");
echo "<p>";
$cntr=0;
for ($i = 1; $i <= 200; $i++) {
echo show_ordinal($i).", ";
$cntr++;
if ($cntr>9) {
echo "<br>";
$cntr=0;
}
}
echo "</p>";
?>
Looking over my test case code - I wanted it to test up to 200, a nice round number that should give me plenty of chances to spot an error. I make it
require my function and I do a short
for {} loop to count up to my 200 test runs. I threw in a counter
($cntr) variable to insert a break after every 10 numbers, just so I can easily read the results.
Now we can run the test case. Point your browser to your test_ordinal.php script to get your results. You should get something similar to my test run results. If you get an error, check your typing and make sure your running the script on an actual web server! Here's the first few lines of mine:
Code:
1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th,
11st, 12nd, 13rd, 14th, 15th, 16th, 17th, 18th, 19th, 20th,
21st, 22nd, 23rd, 24th, 25th, 26th, 27th, 28th, 29th, 30th,
(snipped the rest)
After 10 my routine goes haywire! 11st, 12nd, 13rd?? No! What happened? Well, looking at the last digit in each, it actually would be correct were the first digit thrown away. 11st would be correct if we drop the first 1 - then it becomes 1st. Same with 12nd - get rid of that 1 and it's 2nd. Wow, we need a fix. Luckily, I have it! We need to also grab the second to the last digit and evaluate that as well. More work! But not that much and it's good that this happened because we really learned that writing a test case for a routine can make your life so much easier in the long run. :)
Check out my new solution:
Code:
<?php
function show_ordinal($num) {
// first convert to string if needed
$the_num = (string) $num;
// now we grab the last digit of the number
$last_digit = substr($the_num, -1, 1);
// if the string is more than 2 chars long, we get
// the second to last character to evaluate
if (strlen($the_num)>1) {
$next_to_last = substr($the_num, -2, 1);
} else {
$next_to_last = "";
}
// now iterate through possibilities in a switch
switch($last_digit) {
case "1":
// testing the second from last digit here
switch($next_to_last) {
case "1":
$the_num.="th";
break;
default:
$the_num.="st";
}
break;
case "2":
// testing the second from last digit here
switch($next_to_last) {
case "1":
$the_num.="th";
break;
default:
$the_num.="nd";
}
break;
// if last digit is a 3
case "3":
// testing the second from last digit here
switch($next_to_last) {
case "1":
$the_num.="th";
break;
default:
$the_num.="rd";
}
break;
// for all the other numbers we use "th"
default:
$the_num.="th";
}
// finally, return our string with it's new suffix
return $the_num;
}
?>
What have I done?! Well, I've added some comments in our new function that might help you out. I now need to not only test the last digit of the variable, but also the second to the last. I've nested a couple switches inside our old ones to take care of that second number evaluation. If you follow the logic through the routine it makes sense. If the last number is 1 and the second to the last is 1, our routine will now do the right thing and add "th". Same if the last is 1 and the second to last is 2. It will now add "st". And so on. The beauty of this is, if you think about it, only 1, 2 and 3 are different when it comes to ordinal suffixes. 4-9 and 0 all need a "th" on the end. 29th, 30th, 67th. This makes our testing lives easy!
Let's test! Save the new function with the same name - "show_ordinal.inc.php" and run our test again! My results:
Code:
1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th,
11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th,
21st, 22nd, 23rd, 24th, 25th, 26th, 27th, 28th, 29th, 30th,
31st, 32nd, 33rd, 34th, 35th, 36th, 37th, 38th, 39th, 40th,
41st, 42nd, 43rd, 44th, 45th, 46th, 47th, 48th, 49th, 50th,
51st, 52nd, 53rd, 54th, 55th, 56th, 57th, 58th, 59th, 60th,
61st, 62nd, 63rd, 64th, 65th, 66th, 67th, 68th, 69th, 70th,
71st, 72nd, 73rd, 74th, 75th, 76th, 77th, 78th, 79th, 80th,
81st, 82nd, 83rd, 84th, 85th, 86th, 87th, 88th, 89th, 90th,
91st, 92nd, 93rd, 94th, 95th, 96th, 97th, 98th, 99th, 100th,
101st, 102nd, 103rd, 104th, 105th, 106th, 107th, 108th, 109th, 110th,
111th, 112th, 113th, 114th, 115th, 116th, 117th, 118th, 119th, 120th,
121st, 122nd, 123rd, 124th, 125th, 126th, 127th, 128th, 129th, 130th,
131st, 132nd, 133rd, 134th, 135th, 136th, 137th, 138th, 139th, 140th,
141st, 142nd, 143rd, 144th, 145th, 146th, 147th, 148th, 149th, 150th,
151st, 152nd, 153rd, 154th, 155th, 156th, 157th, 158th, 159th, 160th,
161st, 162nd, 163rd, 164th, 165th, 166th, 167th, 168th, 169th, 170th,
171st, 172nd, 173rd, 174th, 175th, 176th, 177th, 178th, 179th, 180th,
181st, 182nd, 183rd, 184th, 185th, 186th, 187th, 188th, 189th, 190th,
191st, 192nd, 193rd, 194th, 195th, 196th, 197th, 198th, 199th, 200th,
I think we've gotten it! Now from any point on any page, I can include or require this function and pass a number to it to get the proper ordinal suffix.
Hint: This is FABULOUS for dates! We use this for billing - "Your invoice is due on March 3
rd" in an email really adds a more personal touch instead of "Invoice due date: 2007-3-3". ;)
Well, hope this turned out to be a great tutorial for you that you can use whenever you need it. As I said, more to come!