Tuesday, November 4, 2008

My PHP Date and Time Calculator Class

This is a very unique class. It takes a date/time and adds or subtracts any units of time to it, then returns the value. It's very useful for memberships. For example, If you want to sell 30 day subscriptions on your site, you can use this script to calculate the expiration date of the subscription.

An example of how this class can be found here: http://www.elacdude.com/code/date_time_calculator/

There are hundreds of php date/time calculators, but this one works differently than any I've seen. It allows you to supply a date/time in many customizable formats. It also lets you supply date/times without leading zeros. For example a date such as: '4/25/08' normally would be unacceptable, but this class can successfully parse it. It will calculate leap years, different number of days in each month, roll over to the nexy month or year if necessary.

My goal when writing this class was to make it as flexible as possible. I was sick of using classes that only accept dates in 1 format or classes that require you to supply dates/times with leading zeros. Simply supply the date and the format that it is in using the PHP style date/time modifiers. This way it allows you to supply dates in custom formats. You aren't stuck using a format like 2008-04-25. You can use a format like 'Friday, Oct 4th, 2008 4:42pm' if you'd like.

The only problem with allowing date/times without leading zeros is if the numbers are bunched together, it can't read it properly (but neither can a human). For example, the class would read a date like '119' with a mask of 'nj' as 'November 9th', not 'January 19th'. But it is smart, if you supply a date like '219' with a mask of 'nj', it knows there's no such month as '21', so it defaults to 'February 19th", which is corrent.

The list of currently supported date/time modifiers can be found here: http://www.elacdude.com/code/date_time_calculator/date_time_formats.html

When you add units of time, simply supply the unit of time in the format of a string.
For example, all of the below would return the same result:
$obj->add("second", 30);
$obj->add("seconds", 30);
$obj->add("sec", 30);
$obj->add("sec.", 30);
$obj->add("secs", 30);
$obj->add("secs.", 30);
$obj->add("s", 30);
$obj->add("s.", 30);

Example usage of this class:


$obj=new Date_Time_Calc("11/1/2008 17:40:00","n/j/Y H:i:s");
echo$obj->add("mo",15);//you may echo the return value of add() or subtract()
//outputs: 2/1/2010 17:40:00

$obj=new Date_Time_Calc("11/20/2005 07:40:00 PM","m/d/Y h:i:s A");
echo$obj->date_time;//or you can call add() or subtract() and echo the public $date_time variable
//outputs: 11/22/2005 07:40:00 AM

$obj=new Date_Time_Calc("11/20/2005 07:40:00 PM","m/d/Y h:i:s A");
$obj->calculate("h",36,"subtract");//you can use calculate() instead of add() or subtract()
//outputs: 11/19/2005 07:40:00 AM

$obj=new Date_Time_Calc("Dec 5th, '08 08:05 am","M jS, 'y h:i a");
$obj->add("i",90);//you may do multiple calculations one after another
//outputs: Mar 5th, '10 09:35 am

$obj=new Date_Time_Calc("219","nj");//its smart... it knows there's no such month as 21, so it must be 2
//outputs: 319

$obj=new Date_Time_Calc("119","nj");//this defaults to November 9th, not January 19th.
//outputs: 129


I hope you find this class helpful. Click the download link below to download the source code.

More examples can be found at: http://www.elacdude.com/code/date_time_calculator/example.html

To download this class, go to: http://www.phpclasses.org/browse/package/4635.html

For a list of currently supported date/time modifiers, go to: http://www.elacdude.com/code/date_time_calculator/date_time_formats.html

To test this class and see it in action, go to: http://www.elacdude.com/code/date_time_calculator/index.php

Download this class at phpclasses.org

Friday, October 31, 2008

Always prepare for high amounts of traffic

Today at work I did some brainstorming about how I can make our website more efficient for high traffic. My company expects about 50,000 visitors by the end of the year so I wanted to figure out the BEST possible way to execute the database queries on the site.

For each ad on our site there is a counter that counts how many page views the ad has. So every time an ad page is visited it requires a select statement and an update statement (to update the page view count).

On a normal website, a solution like this may be fine:

- select * from table where id='123'
- update table set views='4'

But with a high traffic site, things should be done differently if you want it to run as fast as possible. See a MySQL InnoDB table uses row level locking which means nobody can access that particular row while it is being updated.

On a high traffic website, the above solution would do this:

-User A requests ad page.
-User A's page loads and is currently updating row 5 of the ads table.
-Meanwhile user B requests that same ad page. But he/she must wait until User A is done updating row 5 of the ads table.

Not good. On a very high traffic website there would be a lot of waiting. But there is a different way. Instead of using a column in the ads table to hold the pageview count, create a table that is only for holding pageview counts. This way, while the pagecount table is being updated, it doesn't get in the way of the select statements done on the ads table.

The second solution would act like this on a high traffic web site:

-User A requests ad page.
-User A's page loads.
-At the very end of the page, an update statement is executed on the pageview table. -Meanwhile, User B requests that same ad page. The page loads immediately because that row in the ad table is not locked out due to the update in the pagecount table instead of the ads table.

Much better. No wait time, no locked rows. The content is delivered as fast as possible to the user.

You may think, well how do you update the page count without first executing a select statement to figure out what the CURRENT page count is? After all, how can we update the page count to plus 1 if we don't know what it is already?

Well, the answer to that is the following:

Update pageviews set views=views+1 where id='5'

So now we have a fast and efficient high traffic web site serving content uninterrupted to users.