Welcome to WebmasterWorld Guest from 34.231.247.139

Forum Moderators: coopster & jatar k

Message Too Old, No Replies

Calculate age from DOB

     
6:50 pm on Sep 10, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Hello everybody,

Could someone help me figure this one out, I have this code:


<?php

function CalculateAge($BirthDate)
{
list($Year, $Month, $Day) = explode("/", $BirthDate);

$YearDiff = date("Y") - $Year;

if(date("m") < $Month || (date("m") == $Month && date("d") < $DayDiff))
{
$YearDiff--;
}
return $YearDiff;
}

echo CalculateAge("1986/06/18");

?>


This code intends to get someone's age based on the person's date of birth, in my DB the field that captures the DOB is called "date_of_birth" so I'm assuming I have to change this line:

echo CalculateAge("1986/06/18");

for something like this:

echo CalculateAge("$result['date_of_birth']");

To calculate the age, but this is not working, can someone show me the right syntax? Thanks.
8:43 pm on Sept 10, 2010 (gmt 0)

Moderator from US 

WebmasterWorld Administrator lifeinasia is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Dec 10, 2005
posts:5847
votes: 195


Ick! :)

Why not just use the date_diff function in PHP?
9:36 pm on Sept 10, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Hey LifeinAsia,

I'm using this because 1: I didn't know about date_diff before you mentioned it.

2: It works, all I'm asking is for the right syntax to use on the echo so I can display the age.

3: I looked for an example on how to use date_diff and I couldn't make it work because then again; my problem is that I don't know the syntax when using values from the field "date_of_birth" on my database.

Any extra help would be great, thanks.
10:01 pm on Sept 10, 2010 (gmt 0)

Moderator from US 

WebmasterWorld Administrator lifeinasia is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Dec 10, 2005
posts:5847
votes: 195


I didn't know about date_diff before you mentioned it.

I'm not a PHP expert, but most programming languages have similar built-in functions for dates/times, since similar issues are very common. I did a quick search and found that function (although I guess it only applies to certain versions of PHP).

What data type is the date_of_birth field?
11:02 pm on Sept 10, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member penders is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:July 3, 2006
posts: 3147
votes: 3


The date_diff() or diff() method of the DateTime object is only available as of PHP 5.3. However, AFAIK, there is no function built in to any version of PHP that will accurately calculate a persons age taking into account leap years. So, an additional function is reqd.

However, if your date is already stored as a date in your database then it would perhaps be preferable to let your DB calculate the age. Assuming MySQL (which I don't believe has a 'calculate age' function either) then take a look at this MySQL manual page... [dev.mysql.com...]
9:39 pm on Sept 14, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Thank you all for the help, sadly I haven't figured it out yet, I guess I'm a complete newbie. After reading the responses I switched my research to MySQL age calculations and I have seen several ways to achieve this none of which I've been able to reproduce.

I have this:

$SqlQuery = "SELECT YEAR(CURRENT_DATE()) - YEAR('date_of_birth') - (RIGHT(CURRENT_DATE(),5)<'12-31') AS age";

but I don't know how to make it visible on the front end, I'm not sure if that code is the best or at least right, if someone could help me a little more please :(
10:12 pm on Sept 14, 2010 (gmt 0)

Moderator from US 

WebmasterWorld Administrator lifeinasia is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Dec 10, 2005
posts:5847
votes: 195


Try something like:
SELECT DateDiff(yy,BirthDate,CURRENT_DATE())
11:53 pm on Sept 14, 2010 (gmt 0)

Junior Member

10+ Year Member

joined:Mar 19, 2009
posts: 165
votes: 0


The following code appears accurate (minor testing). Given any birthday in "yyyy/mm/dd" format, it should give you the proper age, even with respect to leap years/etc. Additionally, if a birth date is entered that hasn't happened yet (date is in the future), it will output age as "0".

Your approach, logically speaking, is along the right path.

<?php
$date = "1987/02/03";
function CalculateAge($date)
{
$y = date('Y');
$m = date('n');
$d = date('j');
list($yr,$mo,$day) = explode('/',$date);
$now = ($y*10000+$m*100+$d);
$past = ($yr*10000+$mo*100+$day);
$diff = ($past-$now);
if ($diff>0) { $age = 0 ; }
else
{
$age = (($y-$yr)-1);
if (($m>$mo) || (($m>=$mo) && ($d>=$day))) { $age++; }
}
return $age;
}
$age = CalculateAge($date);
?>



Unfortunately, you cannot count "age" directly as the difference between 2 dates as a result of changes (leap years). So you have to derive and employ a logical extension.

Example/Demonstration
If someone asked you, "how old am I?" and they gave you their birthday... how would you figure it out? For examples sake, my birthday is 1987/02/03 (Feb 3rd, 1987); I am 23 years old.
First, you would figure out how many years have gone by (current year-birth year ... 2010-1987=23); this number will always be inflated by "1" initially, so you subtract off 1 (23-1=22).
Now, you must decide if this person's birthday has passed (occurred) during the given year. You do this by considering: (1) has their birthday month passed yet? If so, then they're age is really "age+1" (22+1=23). (2) If it is currently their birthday month, has their birth 'day' come yet? If so, age is really "age+1". In any other circumstance, the age remains as-is.

As can be seen, this approach doesn't matter whether it is a leap year or such.

Due to the more lengthy computation of this situation, I would not advise trying to use a database solution. IF all you wanted is a raw difference between 2 dates, then yes, a database approach would be feasible. But in this case of calculating age, no.

[edited by: CyBerAliEn at 11:56 pm (utc) on Sep 14, 2010]

11:54 pm on Sept 14, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Ok, I gave up on MySQL and went back to PHP, somehow I made it work using my original code:

<?php

function CalculateAge($BirthDate){
list($Year, $Month, $Day) = explode("/", $BirthDate);

$YearDiff = date("Y") - $Year;

if(date("m") < $Month || (date("m") == $Month && date("d") < $DayDiff)){
$YearDiff--;
}
return $YearDiff;
}

echo CalculateAge($result['date_of_birth']);

?>

As I said, it is working now, displays the person's age and that is what I need, but since there is nothing perfect in life now I'm getting these errors:

Notice: Undefined offset: 2 in C:\wamp\www\app\applicants.php on line 96

Notice: Undefined offset: 1 in C:\wamp\www\app\applicants.php on line 96

Line 96 is the following:
list($Year, $Month, $Day) = explode("/", $BirthDate);

I will someday take more time and learn the MySQL way but right now I really need to finish this up, thanks people, I appreciate the help :)
12:01 am on Sept 15, 2010 (gmt 0)

Junior Member

10+ Year Member

joined:Mar 19, 2009
posts:165
votes: 0


lol... after 2nd look, your func is nearly the same as mine, slightly different. Glad you got yours working!

Regarding the offset error... it sounds like "explode" is returning either less than 3 items or more than 3 items (items being "Year", "Month", "Day). You may want to check your birth date data, as some of it may contain errors driving this issue?
12:57 am on Sept 15, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Feb 16, 2004
posts:1343
votes: 5


I think you are saying the original problem was your couldn't get it to "echo" the answer. Cut and paste the following and save it as a .php file and upload that file to your php enabled web server:


<?php
// Calculate the age from a given birth date
function CalculateAge($BirthDate) {
list($Year, $Month, $Day) = explode("/", $BirthDate);
$YearDiff = date("Y") - $Year;
if(date("m") < $Month || (date("m") == $Month && date("d") < $DayDiff)) {
$YearDiff--;
}
return $YearDiff;
}
?>

<html>
<head>
<title>PHP Age Calculator</title>
</head>
<body>

<?php
$date_of_birth = '1986/06/18';
echo 'Age: ' . CalculateAge($date_of_birth);
?>

</body>
</html>


I tested it with my birthday and it got the answer right...

Then all that's needed is to get the value for $date_of_birth from the database instead of the hardcoded '1986/06/18' date...
8:24 am on Sept 15, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Apr 24, 2005
posts:697
votes: 0


I do it like this




function computeAge($starttime,$endtime)
{
$age = date("Y",$endtime) - date("Y",$starttime);
if(date("z",$endtime) < date("z",$starttime)) $age--;
return $age;
}

call like

$dob=strtotime($values['birth_date']);
$now=time();
$age=computeAge($dob,$now);
5:31 pm on Sept 15, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


@lexipixel, Anyango:

Both functions echo a year, but there is a 1 year difference, for example someone born on sept-18-1950 is 59 years old and will be 60 in three days, Anyango's function echoes 59 and lexipixel's echoes 60 and using lexipixel's code is still giving me the Undefined offset error on the same line, I wonder why...
8:13 pm on Sept 15, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member penders is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:July 3, 2006
posts: 3147
votes: 3


@Sub_Seven lexipixel's code is the same as your original function. However, there is an error in your code that is producing the erroneous age:
if(date("m") < $Month || (date("m") == $Month && date("d") < $DayDiff))

Should read:
if(date("m") < $Month || (date("m") == $Month && date("d") < $Day))

Then your function will echo 59 as well.

lexipixel's code is still giving me the Undefined offset error on the same line


This will only occur in the function itself if the date string passed to the function is not of the form "YYYY/MM/DD" (with forward slashes between).

Are you now getting your date_of_birth from your DB? What does this raw value look like?
10:11 pm on Sept 15, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Oh man that was the problem, and yeah I am getting the date_of_birth from my DB with - not / in between so changing that line to this:

list($Year, $Month, $Day) = explode("-", $BirthDate);

fixed the error messages.

Ok guys, hoping that you still have patience I'm gonna ask two more questions related to this topic

#1:

Which of both scripts is better? (I'm too much of a newbie to tell!)

#2:

If I wanted to use the age (not dob) to pull statistics how would I go about that because the age itself is not stored on the db...?
10:12 pm on Sept 15, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Sorry, duplicate... :\
6:51 am on Sept 16, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Apr 24, 2005
posts:697
votes: 0



I'm too much of a newbie to tell!


Then don't worry about which one is marginaly better ;) use any. It isn't important at this stage to find out which one of these two scripts is better, as long as they work fine.
11:51 am on Sept 16, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member penders is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:July 3, 2006
posts: 3147
votes: 3


But in the interests of learning it's always good to know the merits of one script over another - newbie or experienced pro. But Anyango is right, it's unlikely to make much of a difference in your case, as long as it works. However...

From the 3 scripts defined above: Sub_Seven, CyBerAliEn and Anyango. Sub_Seven's is quickest and Anyango's is the slowest (taking into account the strtotime() function call). But you have to make 100,000+ calls to notice the difference.

On my not so quick test server, processing 100,000 random date of births:
- Sub_Seven = 6.37 secs
- CyBerAliEn = 7.02 secs
- Anyango (variation of) = 8.4 secs

However, speed isn't everything. Personally I prefer a (variation of) Anyango's function as a general 'calculate age' script since it's short, easy to understand and is more flexible. Flexible in the sense it can accept many different date strings (YYYY/MM/DD or YYYY-MM-DD, etc.) without any modification.

/** 
* Variation of Anyango's script
* @param dob string|int Date string that strtotime() understands OR unix timestamp (quicker)
* @return int
*/
function calcAge_Anyango($dob) {
if (is_string($dob)) {
$dob = strtotime($dob);
}
$age = date("Y") - date("Y",$dob);
if (date("z") < date("z",$dob)) $age--;
return $age;
}


Other things to think about are what if there is no DOB? What if it's invalid?

#2 Using the age in queries... (it is correct not to store the age)

Either:
- Go back to using SQL to calculate the age :) - see my (and your) post above
- Or, calculate the appropriate date that relates to the age before executing the query and use that! eg. All records where the person is older than 50 is the same as WHERE DOB < "1960-09-16" (if executed today!)

CyBerAliEn: Due to the more lengthy computation of this situation, I would not advise trying to use a database solution. IF all you wanted is a raw difference between 2 dates, then yes, a database approach would be feasible. But in this case of calculating age, no.


I'm not sure that I agree. This could depend on the nature of the query - if you just want to display all records older than a certain age (ie. you've pre calculated the DOB) OR you wish to display everyone's age! If the later, then keeping it all in the database is probably the best approach. It's only a one-liner in the SQL query (see Sub_Seven's post above) and providing you are storing your dates as DATEs in your DB it's probably quicker.
3:43 pm on Sept 16, 2010 (gmt 0)

Junior Member

10+ Year Member

joined:Mar 19, 2009
posts:165
votes: 0


I'm not sure that I agree. This could depend on the nature of the query - if you just want to display all records older than a certain age (ie. you've pre calculated the DOB) OR you wish to display everyone's age! If the later, then keeping it all in the database is probably the best approach. It's only a one-liner in the SQL query (see Sub_Seven's post above) and providing you are storing your dates as DATEs in your DB it's probably quicker.


Some clarifications. Generally speaking, I do agree with you. If the intent is to sort/retrieve/etc individuals from the DB based on age criteria, then YES, you do want to pursue a DB solution. However, if all you want to do is a calculate the age for some given user (to display or use, on a user by user basis), then a PHP-driven approach should be preferable.

However, one must note the following about the mySQL query approaches:

SELECT DateDiff(yy,BirthDate,CURRENT_DATE())
This type of query will not work to calculate a persons age. Why? It outputs the # of days between the two input dates (birth day and current day). Additionally, this syntax doesn't appear correct... the mySQL documentation gives the input arguments as:
DATEDIFF(expr1,expr2)

Since it outputs the # of days in between the 2 input dates, you cannot readily calculate age because of leap years. Dividing the # of days by 365, 365.52, etc will all produce varying levels of errors.

What you have to do is consider the logical process of determining age by using the difference in years, and considering the current month/day to the birth month/day. As pointed out in a previous mySQL link, the following type of adjustment to a query would produce an 'age' column onto your query results, which you could then sort by/etc.

Code to get age (mySQL):
((YEAR(CURDATE())-YEAR(date_of_birth)) - (RIGHT(CURDATE(),5)<RIGHT(date_of_birth,5))) AS age

where "date_of_birth" is the name of the field (column) whose value contains the date of the birth, which should be stored as a mySQL date data type

Example of using above within a query:
SELECT name,date_of_birth,((YEAR(CURDATE())-YEAR(date_of_birth)) - (RIGHT(CURDATE(),5)<RIGHT(date_of_birth,5))) AS age,state FROM people ORDER BY age DESC;


The above would produce results such as the following:
name | date_of_birth | age | state
John , 1987-04-21, 23, New York
Bob, 1988-03-02, 22, Ohio
Mike, 1988-01-14, 22, Maine
Pat, 1988-11-24, 21, Utah

(etc)

Once you have a query result like this, then all you do is PHP like you normally would to action on it. The "age" is just like any other column from your query results, except that instead of being stored directly in the DB, mySQL calculates these values on query execution and returns the results as if it were a column in your result.

So suppose you ran a query such as the above, and you had the row representing "Mike" stored in the variable "$result" (say because you're looping results)... you would access the age of this result with code such as the following (assuming your PHP mySQL query returns results with associative array keys):
$age = $result['age'];


This above approach is sound in determining age.
4:04 pm on Sept 16, 2010 (gmt 0)

Junior Member

10+ Year Member

joined:Mar 19, 2009
posts:165
votes: 0


Ugh... additionally:

As advice from experience to a "newbie" ;)

I must stress than in any endeavor you do in coding, you should always strive to make your coding as module, general, and robust as possible.

Why?
Because if your code is done in the above manner, it allows you to re-use code from one page/site/project/etc onto another page/site/project/etc. This saves you a lot of time and resources in the end.

How?
In this case, consider a PHP function such as getting a person's age. You could create a function like CalculatePeopleAge($date) that does something like the above. But really, what you should strive for is something with the above 3 characteristics in mind, such as a simple getAge($date) function.

How would these differ?
Your function should be so module and generic that you can drop it anywhere and it should work without modification. Considering all of the age functions in this thread, there are some glaring issues that must be pointed out (which penders does slightly touch on), particularly...
(1) what if the input date isn't as expected?

Your function should be able to handle any input or errors graciously. This can be difficult but is worthwhile in the long run. For example, what if someone enters the date as "YY-MM-DD", or "MM-DD-YY", or "MM-DD-YYY", etc and you're expecting it in the format "YYYY-MM-DD"? Or suppose you expect "YYYY-MM-DD" and you get input like "YYYY/MM/DD"? <<< This last example actually happened between your code and data set, because your data was using "-" as the delimiter, not "/".

Also, what if someone entered an impossible birthday? For example, suppose someone entered July 21st, 2032. Well, today is only September 16th, 2010. So in reality, this date of birth is infeasible/impossible. Plug this into almost any of the age functions provided above, and you'll get an age out like -22. How can someone be negative 22 years old? Your function should anticipate this and resolve it. If you don't want "-22" age as a possibility, and you prefer it output "0", then program this contingency. Etc.

With these thoughts in mind, you could adjust your age function to look more like...
function getAge($date,$format="yyyymmdd",$delimiter="/")
{
//code
}


Your function code could then utilize the inputted format and delimiter as a basis for determining age. This is more complex coding, for certain, but it allows you to develop an age function that approaches "drag-and-drop" / "plug-and-play" capabilities.

Although, in practice, you might want to simply have a function such as "getAge($date)" that internally uses built in PHP functions like "strtotime($datestring)" to turn the input date into a timestamp. You can then use PHP's "date()" function to extract the year/month/etc. This is useful because it uses PHP to do the "format correcting" for you. However, you must be cautioned that in this approach, a PHP's function "strtotime()" won't always be accurate at turning a date string into the correct date.


The above is all advice and food for thought, not necessarily something that you should or have to do. But it is advice that is and should be expanded to other functions as you move forward in coding.
1:49 am on Sept 21, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Hello people,

Sorry for the late reply but I've been jammed with tons of work. Thanks for all the extra notes with all kinds of advice, I've read them and I will read them again with more patience as soon as I get rid of a few things that are huge priority right now.

I have one last question related to this topic, in an effort to finish this part of my project I was trying to finally calculate or get age statistics, for example I want to get of all people in the db those who are between 18-29, 30-39 and 40+...

penders suggestions works fine, here an example of how I did it:

$query = mysql_query("SELECT COUNT(*) FROM table WHERE status = 1 && date_of_birth < '1992-09-20' && date_of_birth > '1981-09-20'");

but this is definitely not the best way (I know the idea was to give me an example which I understood) BUT I want it to make it work in a way that you don't have to hardcode the ranges/dates like this '1981-09-20' because it wont be accurate unless you update those dates every day, anyways, after a few attempts to figure this one out too, I realized that probably I wasn't gonna so I leave you what I tried that makes more sense and probably someone can give me a hint if at all possible:

This example is what I tried for the first age range (18-29):

$query = mysql_query("SELECT COUNT(*) FROM table WHERE status = 1 && date('Y-m-d') - date_of_birth >= '18' && date('Y-m-d') - date_of_birth <= '29'");

To me it kinda makes sense but it doesn't work... :(

Something funny came out of this though... remember all three scripts used to calculate ages? The ones penders put under a scope to see which one was faster:

- Sub_Seven = 6.37 secs
- CyBerAliEn = 7.02 secs
- Anyango (variation of) = 8.4 secs

Well all of a sudden I realized I could just do this:

echo date('Y-m-d') - $result['date_of_birth'];

And I was like whatta hell!? I got the age just like all other three scripts in just one single line?

It makes sense and it also seems accurate, is there something wrong about doing that?

Allright, I'll be sitting here waiting to see that email from devnull, thanks everybody for all the help :)
3:27 am on Sept 21, 2010 (gmt 0)

Junior Member

10+ Year Member

joined:Mar 25, 2004
posts:161
votes: 0


Heres a nice class that can do all sorts of date stuff!

<?php

class Pos_Date extends DateTime
{
protected $_year;
protected $_month;
protected $_day;

public function __construct($timezone = null)
{
// call the parent constructor
if ($timezone)
{
parent::__construct('now', $timezone);
}
else
{
parent::__construct('now');
}

// assign the values to the class properties
$this->_year = (int) $this->format('Y');
$this->_month = (int) $this->format('n');
$this->_day = (int) $this->format('j');
}

public function setTime($hours, $minutes, $seconds = 0)
{
if (!is_numeric($hours) || !is_numeric($minutes) || !is_numeric($seconds))
{
throw new Exception('setTime() expects two or three numbers separated by commas in the order: hours, minutes, seconds');
}
$outOfRange = false;
if ($hours < 0 || $hours > 23)
{
$outOfRange = true;
}
if ($minutes < 0 || $minutes > 59)
{
$outOfRange = true;
}
if ($seconds < 0 || $seconds > 59)
{
$outOfRange = true;
}
if ($outOfRange)
{
throw new Exception('Invalid time.'); parent::setTime($hours, $minutes, $seconds);
}
parent::setTime($hours, $minutes, $seconds);
}

public function setDate($year, $month, $day)
{
if (!is_numeric($year) || !is_numeric($month) || !is_numeric($day))
{
throw new Exception('setDate() expects three numbers separated by commas in the order: day, month, year.');
}
if (!checkdate($month, $day, $year))
{
throw new Exception('Non-existent date.');
}
parent::setDate($year, $month, $day);
$this->_year = (int) $year;
$this->_month = (int) $month;
$this->_day = (int) $day;
}
public function modify()
{
throw new Exception('modify() has been disabled.');
}

public function setMDY($USDate)
{
$dateParts = preg_split('{[-/ :.]}', $USDate);
if (!is_array($dateParts) || count($dateParts) != 3)
{
throw new Exception('setMDY() expects a date as "MM/DD/YYYY".');
}
$this->setDate($dateParts[2], $dateParts[0], $dateParts[1]);
}

public function setDMY($EuroDate)
{
$dateParts = preg_split('{[-/ :.]}', $EuroDate);
if (!is_array($dateParts) || count($dateParts) != 3)
{
throw new Exception('setDMY() expects a date as "DD/MM/YYYY".');
}
$this->setDate($dateParts[2], $dateParts[1], $dateParts[0]);
}

public function setFromMySQL($MySQLDate)
{
$dateParts = preg_split('{[-/ :.]}', $MySQLDate);
if (!is_array($dateParts) || count($dateParts) != 3)
{
throw new Exception('setFromMySQL() expects a date as "YYYY-MM-DD".');
}
$this->setDate($dateParts[0], $dateParts[1], $dateParts[2]);
}

public function getMDY($leadingZeros = false)
{
if ($leadingZeros)
{
return $this->format('m/d/Y');
}
else
{
return $this->format('n/j/Y');
}
}

public function getDMY($leadingZeros = false)
{
if ($leadingZeros)
{
return $this->format('d/m/Y');
}
else
{
return $this->format('j/n/Y');
}
}

public function getMySQLFormat()
{
return $this->format('Y-m-d');
}

public function getFullYear()
{
return $this->_year;
}

public function getYear()
{
return $this->format('y');
}

public function getMonth($leadingZero = false)
{
return $leadingZero ? $this->format('m') : $this->_month;
}

public function getMonthName()
{
return $this->format('F');
}

public function getMonthAbbr()
{
return $this->format('M');
}

public function getDay($leadingZero = false)
{
return $leadingZero ? $this->format('d') : $this->_day;
}

public function getDayOrdinal()
{
return $this->format('jS');
}

public function getDayName()
{
return $this->format('l');
}

public function getDayAbbr()
{
return $this->format('D');
}

public function addDays($numDays)
{
if (!is_numeric($numDays) || $numDays < 1)
{
throw new Exception('addDays() expects a positive integer.');
}
parent::modify('+' . intval($numDays) . ' days');
}

public function subDays($numDays)
{
if (!is_numeric($numDays))
{
throw new Exception('subDays() expects an integer.');
}
parent::modify('-' . abs(intval($numDays)) . ' days');
}

public function addWeeks($numWeeks)
{
if (!is_numeric($numWeeks) || $numWeeks < 1)
{
throw new Exception('addWeeks() expects a positive integer.');
}
parent::modify('+' . intval($numWeeks) . ' weeks');
}

public function subWeeks($numWeeks)
{
if (!is_numeric($numWeeks))
{
throw new Exception('subWeeks() expects an integer.');
}
parent::modify('-' . abs(intval($numWeeks)) . ' weeks');
}

public function addMonths($numMonths)
{
if (!is_numeric($numMonths) || $numMonths < 1)
{
throw new Exception('addMonths() expects a positive integer.');
}
$numMonths = (int) $numMonths;
// Add the months to the current month number.
$newValue = $this->_month + $numMonths;
// If the new value is less than or equal to 12, the year
// doesn't change, so just assign the new value to the month.
if ($newValue <= 12)
{
$this->_month = $newValue;
}
else
{
// A new value greater than 12 means calculating both
// the month and the year. Calculating the year is
// different for December, so do modulo division
// by 12 on the new value. If the remainder is not 0,
// the new month is not December.
$notDecember = $newValue % 12;
if ($notDecember)
{
// The remainder of the modulo division is the new month.
$this->_month = $notDecember;
// Divide the new value by 12 and round down to get the
// number of years to add.
$this->_year += floor($newValue / 12);
}
else
{
// The new month must be December
$this->_month = 12;
$this->_year += ($newValue / 12) - 1;
}
}
$this->checkLastDayOfMonth();
parent::setDate($this->_year, $this->_month, $this->_day);
}

final protected function checkLastDayOfMonth()
{
if (!checkdate($this->_month, $this->_day, $this->_year))
{
$use30 = array(4 , 6 , 9 , 11);
if (in_array($this->_month, $use30))
{
$this->_day = 30;
}
else
{
$this->_day = $this->isLeap() ? 29 : 28;
}
}
}

public function isLeap()
{
if ($this->_year % 400 == 0 || ($this->_year % 4 == 0 && $this->_year % 100 != 0))
{
return true;
}
else
{
return false;
}
}


public function subMonths($numMonths)
{
if (!is_numeric($numMonths))
{
throw new Exception('addMonths() expects an integer.');
}
$numMonths = abs(intval($numMonths));
// Subtract the months from the current month number.
$newValue = $this->_month - $numMonths;
// If the result is greater than 0, it's still the same year,
// and you can assign the new value to the month.
if ($newValue > 0)
{
$this->_month = $newValue;
}
else
{
// Create an array of the months in reverse.
$months = range(12 , 1);
// Get the absolute value of $newValue.
$newValue = abs($newValue);
// Get the array position of the resulting month.
$monthPosition = $newValue % 12;
$this->_month = $months[$monthPosition];
// Arrays begin at 0, so if $monthPosition is 0,
// it must be December.
if ($monthPosition)
{
$this->_year -= ceil($newValue / 12);
}
else
{
$this->_year -= ceil($newValue / 12) + 1;
}
}
$this->checkLastDayOfMonth();
parent::setDate($this->_year, $this->_month, $this->_day);
}

public function addYears($numYears)
{
if (!is_numeric($numYears) || $numYears < 1)
{
throw new Exception('addYears() expects a positive integer.');
}
$this->_year += (int) $numYears;
$this->checkLastDayOfMonth();
parent::setDate($this->_year, $this->_month, $this->_day);
}

public function subYears($numYears)
{
if (!is_numeric($numYears))
{
throw new Exception('subYears() expects an integer.');
}
$this->_year -= abs(intval($numYears));
$this->checkLastDayOfMonth();
parent::setDate($this->_year, $this->_month, $this->_day);
}

static public function dateDiff(Pos_Date $startDate, Pos_Date $endDate)
{
$start = gmmktime(0, 0, 0, $startDate->_month, $startDate->_day, $startDate->_year);
$end = gmmktime(0, 0, 0, $endDate->_month, $endDate->_day, $endDate->_year);
return ($end - $start) / (60 * 60 * 24);
}

public function __toString()
{
return $this->format('l,jS F Y');
}

public function __get($name)
{
switch (strtolower($name))
{
case 'mdy':
return $this->format('n/j/Y');
case 'mdy0':
return $this->format('m/d/Y');
case 'dmy':
return $this->format('j/n/Y');
case 'dmy0':
return $this->format('d/m/Y');
case 'mysql':
return $this->format('Y-m-d');
case 'fullyear':
return $this->_year;
case 'year':
return $this->format('y');
case 'month':
return $this->_month;
case 'month0':
return $this->format('m');
case 'monthname':
return $this->format('F');
case 'monthabbr':
return $this->format('M');
case 'day':
return $this->_day;
case 'day0':
return $this->format('d');
case 'dayordinal':
return $this->format('jS');
case 'dayname':
return $this->format('l');
case 'dayabbr':
return $this->format('D');
default:
return 'Invalid property';
}
}

} //end class
8:53 am on Sept 21, 2010 (gmt 0)

Senior Member

WebmasterWorld Senior Member penders is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:July 3, 2006
posts: 3147
votes: 3


Well all of a sudden I realized I could just do this:

echo date('Y-m-d') - $result['date_of_birth'];


And I was like whatta hell!? I got the age just like all other three scripts in just one single line?


Must admit, you made me double-take! But unfortunately, this isn't doing what you think it's doing. The fact that it appeared to work in your example is just a coincidence.

PHP sees both these operands as plain old strings (not dates), these are then converted to numeric values (integers) in order to do the subtraction. So your example is equivalent to something like:

// Expected age is 29, not 30 until 1st Nov 2010 
echo '2010-09-21' - '1980-11-01';
// PHP converts these to numeric values
echo 2010 - 1980;
// Output 30 - Not the age, just the difference in numeric value (which so happens to be years)


If the date of birth occurred before the current date (ie. before 21st Sept) then the result would have still been 30 - which would have appeared to have been correct - coincidence.

NB: PHP and MySQL store dates very differently. PHP stores dates as unix timestamps (number of seconds since 1970-01-01). They are not interchangeable without some conversion.
3:19 pm on Sept 21, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


That's a lot of code delboy1978uk, I'll need some time to test it out, thanks for the help.

@penders

Thanks for the clarification, I guess that also tells me that what I was trying to do:

$query = mysql_query("SELECT COUNT(*) FROM table WHERE date('Y-m-d') - date_of_birth >= '18' && date('Y-m-d') - date_of_birth <= '29'");

Wont work this way because of the same reason...

I'm sorry to keep asking but then how can I pull only those individuals within a specific age range from the db?
10:56 am on Oct 5, 2010 (gmt 0)

Administrator

WebmasterWorld Administrator coopster is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:July 31, 2003
posts:12555
votes: 3


Here is a relative discussion from a few years back that may be helpful ...
calculating age [webmasterworld.com]
4:13 pm on Oct 5, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Thanks coopster,

I was able to calculate age just fine and thanks to this thread I've learned a lot about this, so I could say the original question was answered, but the thread (as it continued to grow) kept bringing new questions to my head and one of the things I still need to do is to be able to pull age statistics, say for example I need to be able to know what percentage of all these people are between 18 and 29 years old, I can do it like this:

<?php
$query = mysql_query("SELECT COUNT(*) FROM applications WHERE status = 1 && date_of_birth < '1992-10-05' && date_of_birth > '1981-10-05'");
list($age1number) = mysql_fetch_row($query);
$percent = number_format(($age1number * 100) / $number);
echo "$age1number / ";
echo "$percent%";
?>

And it works fine but this requires that I change the dates manually every day to maintain accuracy and I am positive there is a way to automate this but I just can figure it out, I've tried several thing but I stopped a few days ago as I need to concentrate on other things, thanks for the help, I appreciate it :)
6:29 pm on Oct 5, 2010 (gmt 0)

Administrator

WebmasterWorld Administrator coopster is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:July 31, 2003
posts:12555
votes: 3


I originally wrote that function based on a MySQL example. Here are the relative threads that should help you over the hump ...

Select age between two date format [webmasterworld.com]
Calculate age [webmasterworld.com]
10:19 pm on Oct 18, 2010 (gmt 0)

Junior Member

5+ Year Member

joined:June 18, 2010
posts: 170
votes: 1


Hey all,

Just wanted to let you all know I got it working thanks to a co-worker who turned out to be really good a this, this is the code that works to pull the age statistics in case someone ever needs something similar:

SELECT COUNT(*) FROM table WHERE status = 1 AND DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')) > 17 AND DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')) < 30
 

Join The Conversation

Moderators and Top Contributors

Hot Threads This Week

Featured Threads

Free SEO Tools

Hire Expert Members