TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
Advertisement
Associates
Associates
techtuts Darkmindz
CSS Tutorials Tutorialsphere.com - Free Online Tutorials
Boston PHP SurfnLearn
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 02-27-2007, 03:29 PM   #1 (permalink)
The Wanderer
 
serversphere's Avatar
 
Join Date: Dec 2006
Location: USA
Posts: 21
Thanks: 0
serversphere is on a distinguished road
Default Tutorial - Getting th, st and rd (ordinal suffixes) on numbers and dates

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 7th, 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 3rd" 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!
Send a message via AIM to serversphere
serversphere is offline  
Reply With Quote
Old 02-27-2007, 06:17 PM   #2 (permalink)
Super ModTastic
 
mike.fro's Avatar
 
Join Date: Apr 2005
Location: Apple Valley, MN
Posts: 89
Thanks: 1
mike.fro is on a distinguished road
Default

Great contribution. We appreciate it.
__________________
Michael.Froseth
www.michaelfroseth.com | Personal Portfolio/Blog *DOWN*
Send a message via AIM to mike.fro Send a message via MSN to mike.fro
mike.fro is offline  
Reply With Quote
Old 04-04-2007, 11:06 AM   #3 (permalink)
Moderateur
RegEx Guru PHP Guru Top Contributor Advanced Programmer 
 
Salathe's Avatar
 
Join Date: Apr 2007
Posts: 713
Thanks: 2
Salathe is on a distinguished road
Default

If you're using dates, then php's date function is much more flexible. The "th/st/rd" suffixes are available by using S in the formatting string.

PHP Code:
<?php

$date 
now();
echo 
date('F jS'$date); // April 4th

?>
Salathe is online now  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 10:58 PM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0