marucc
3/3/2012 - 4:18 AM

getAgeFromBirthday for php

getAgeFromBirthday for php

<?php
/**
 * getAgeFromBirthday
 *
 * @param string $birthday
 * @param string|array $format  %Y %y %M %m %D %d, string or array('year', 'month', 'day')
 * @param string $now = null
 * @return string
 */
function getAgeFromBirthday($birthday, $format = '%y', $today = null)
{
    $birthday = new DateTime($birthday);
    $birthday->setTime(0, 0, 0);
    $today = new DateTime($today);
    $today->setTime(0, 0, 0);
    if ($today <= $birthday) return false;

    $birthday_m = (int)$birthday->format('n');
    $today_m = (((int)$today->format('Y') - (int)$birthday->format('Y')) * 12)
            + (int)$today->format('n');
    $diff_m = ($today_m - $birthday_m);

    if ($today->format('d') < $birthday->format('d')) {
        $diff_m--;
        $birthday->setDate(
            $today->format('y'),
            $today->format('m') - 1,
            $birthday->format('d')
        );
    } else {
        $birthday->setDate(
            $today->format('y'),
            $today->format('m'),
            $birthday->format('d')
        );
    }

    $diff_y = ($diff_m - ($diff_m % 12)) / 12;
    $diff_m -= ($diff_y * 12);

    //(PHP 5 >= 5.3.0)
    $diff_d = (int)$birthday->diff($today)->format('%d');
    //(PHP 5 < 5.3.0)
    //$diff_d = ($birthday->format('m') == $today->format('m'))
    //    ? ((int)$today->format('j') - (int)$birthday->format('j'))
    //    : (((int)$birthday->format('t') - (int)$birthday->format('j')) + (int)$today->format('j'));

    if (!$diff_y && !$diff_m && !$diff_d) {
        return false;
    } elseif (is_null($format)) {
        return array(
            $diff_y,
            $diff_m,
            $diff_d,
        );
    }

    $formats = is_array($format) ? $format : array('', '', '', $format);
    // like DateInterval::format
    $replace_patterns = array(
        '%Y' => '%1$02d',
        '%y' => '%1$d',
        '%M' => '%2$02d',
        '%m' => '%2$d',
        '%D' => '%3$02d',
        '%d' => '%3$d',
    );
    //(PHP 5 >= 5.3.0)
    array_walk($formats, function (&$val, $key) use ($replace_patterns) {
        $val = str_replace(
            array_keys($replace_patterns),
            array_values($replace_patterns),
            $val
        );
    });
    //(PHP 5 < 5.3.0)
    //array_walk($formats,
    //    create_function('&$val, $key, $p', '$val = str_replace(array_keys($p), array_values($p), $val);'),
    //    $replace_patterns);

    $ret = '';
    if (isset($formats[0]) && $diff_y) $ret .= sprintf($formats[0], $diff_y, $diff_m, $diff_d);
    if (isset($formats[1]) && $diff_m) $ret .= sprintf($formats[1], $diff_y, $diff_m, $diff_d);
    if (isset($formats[2]) && $diff_d) $ret .= sprintf($formats[2], $diff_y, $diff_m, $diff_d);
    if (isset($formats[3])) $ret .= sprintf($formats[3], $diff_y, $diff_m, $diff_d);
    return $ret;
}


// test
if (debug_backtrace()) return;
$tests = array(
    array('2012-03-02', '2012-03-01', '%y-%m-%d', false),
    array('2012-03-02', '2012-03-02', '%y-%m-%d', false),
    array('2012-03-02', '2012-03-03', '%y-%m-%d', '0-0-1'),
    array('2007-03-12', '2012-04-11', '%y',       '5'),
    array('2001-01-10', '2012-01-11', '%y歳%mヵ月', '11歳0ヵ月'),
    array('2001-06-12', '2012-01-11', '%y歳%mヵ月', '10歳6ヵ月'),
    array('2001-01-10', '2012-01-11', array('%y歳', '%mヵ月'), '11歳'),
    array('2001-06-12', '2012-01-11', array('%y歳', '%mヵ月'), '10歳6ヵ月'),
    array('2001-01-10', '2012-01-11', array('%y歳', '%mヵ月', '%d日'), '11歳1日'),
    array('2001-06-12', '2012-01-12', array('%y歳', '%mヵ月', '%d日'), '10歳7ヵ月'),
    array('2011-06-12', '2012-01-12', array('%y歳', '%mヵ月', '%d日'), '7ヵ月'),
    array('2000-09-01', '2012-03-11', null, array(11, 6, 10)),
    array('2011-09-01', '2012-03-01', '%y-%m-%d', '0-6-0'),
    array('2011-09-10', '2012-03-10', '%y-%m-%d', '0-6-0'),
    array('2011-09-01', '2012-09-01', '%y-%m-%d', '1-0-0'),
    array('2011-09-10', '2012-09-09', '%y-%m-%d', '0-11-30'),
    array('2011-07-10', '2012-07-09', '%y-%m-%d', '0-11-29'),
    array('2010-11-30', '2012-12-31', '%y-%m-%d', '2-1-1'),
    array('2010-10-31', '2012-11-30', '%y-%m-%d', '2-0-30'),
    array('2012-02-29', '2013-02-28', '%y-%m-%d', '0-11-30'),
    array('2012-02-29', '2013-03-01', '%y-%m-%d', '1-0-0'),
    array('2011-02-28', '2012-02-29', '%y-%m-%d', '1-0-1'),
    array('2011-03-01', '2012-02-29', '%y-%m-%d', '0-11-28'),
    array('2011-02-20', '2012-03-10', '%y-%m-%d', '1-0-19'),
    array('2012-02-20', '2013-03-10', '%y-%m-%d', '1-0-18'),
    array('1996-01-20', '2012-01-19', '%y', '15'),
    array('1996-01-20', '2012-01-20', '%y', '16'),
    array('1996-02-28', '2011-02-27', '%y', '14'),
    array('1996-02-28', '2011-02-28', '%y', '15'),
    array('1996-02-28', '2011-03-01', '%y', '15'),
    array('1996-02-29', '2011-02-27', '%y', '14'),
    array('1996-02-29', '2011-02-28', '%y', '14'),
    array('1996-02-29', '2011-03-01', '%y', '15'),
    array('1997-02-28', '2012-02-27', '%y', '14'),
    array('1997-02-28', '2012-02-28', '%y', '15'),
    array('1997-02-28', '2012-02-29', '%y', '15'),
    array('1997-02-28', '2012-03-01', '%y', '15'),
);
foreach ($tests as $t)
{
    $ret = getAgeFromBirthday($t[0], $t[2], $t[1]);
    echo sprintf("%s: %s -> %s = %s%s\n",
        ($ret === $t[3] ? 'ok' : 'ng'),
        $t[0],
        $t[1],
        var_export($ret, true),
        ($ret === $t[3] ? '' : ' => ' . var_export($t[3], true))
    );
}
/*
result
ok: 2012-03-02 -> 2012-03-01 = false
ok: 2012-03-02 -> 2012-03-02 = false
ok: 2012-03-02 -> 2012-03-03 = '0-0-1'
ok: 2007-03-12 -> 2012-04-11 = '5'
ok: 2001-01-10 -> 2012-01-11 = '11歳0ヵ月'
ok: 2001-06-12 -> 2012-01-11 = '10歳6ヵ月'
ok: 2001-01-10 -> 2012-01-11 = '11歳'
ok: 2001-06-12 -> 2012-01-11 = '10歳6ヵ月'
ok: 2001-01-10 -> 2012-01-11 = '11歳1日'
ok: 2001-06-12 -> 2012-01-12 = '10歳7ヵ月'
ok: 2011-06-12 -> 2012-01-12 = '7ヵ月'
ok: 2000-09-01 -> 2012-03-11 = array (
  0 => 11,
  1 => 6,
  2 => 10,
)
ok: 2011-09-01 -> 2012-03-01 = '0-6-0'
ok: 2011-09-10 -> 2012-03-10 = '0-6-0'
ok: 2011-09-01 -> 2012-09-01 = '1-0-0'
ok: 2011-09-10 -> 2012-09-09 = '0-11-30'
ok: 2011-07-10 -> 2012-07-09 = '0-11-29'
ok: 2010-11-30 -> 2012-12-31 = '2-1-1'
ok: 2010-10-31 -> 2012-11-30 = '2-0-30'
ok: 2012-02-29 -> 2013-02-28 = '0-11-30'
ok: 2012-02-29 -> 2013-03-01 = '1-0-0'
ok: 2011-02-28 -> 2012-02-29 = '1-0-1'
ok: 2011-03-01 -> 2012-02-29 = '0-11-28'
ok: 2011-02-20 -> 2012-03-10 = '1-0-19'
ok: 2012-02-20 -> 2013-03-10 = '1-0-18'
ok: 1996-01-20 -> 2012-01-19 = '15'
ok: 1996-01-20 -> 2012-01-20 = '16'
ok: 1996-02-28 -> 2011-02-27 = '14'
ok: 1996-02-28 -> 2011-02-28 = '15'
ok: 1996-02-28 -> 2011-03-01 = '15'
ok: 1996-02-29 -> 2011-02-27 = '14'
ok: 1996-02-29 -> 2011-02-28 = '14'
ok: 1996-02-29 -> 2011-03-01 = '15'
ok: 1997-02-28 -> 2012-02-27 = '14'
ok: 1997-02-28 -> 2012-02-28 = '15'
ok: 1997-02-28 -> 2012-02-29 = '15'
ok: 1997-02-28 -> 2012-03-01 = '15'
*/
<?php
// floor((Ymd - Ymd)/10000)
// 月齢、日にちまで求めないならこれで十分
function getAge($birthday, $today)
{
    return (int)floor(((int)$today-(int)$birthday)/10000);
}


// test
if (debug_backtrace()) return;
$tests = array(
    array('19960120', '20120119', 15),
    array('19960120', '20120120', 16),
    array('19960228', '20110227', 14),
    array('19960228', '20110228', 15),
    array('19960228', '20110301', 15),
    array('19960229', '20110227', 14),
    array('19960229', '20110228', 14),
    array('19960229', '20110301', 15),
    array('19970228', '20120227', 14),
    array('19970228', '20120228', 15),
    array('19970228', '20120229', 15),
    array('19970228', '20120301', 15),
);
foreach ($tests as $t)
{
    $ret = getAge($t[0], $t[1]);
    echo sprintf("%s: %s -> %s = %s%s\n",
        ($ret === $t[2] ? 'ok' : 'ng'),
        $t[0],
        $t[1],
        var_export($ret, true),
        ($ret === $t[2] ? '' : ' => ' . var_export($t[2], true))
    );
}
/*
result
ok: 19960120 -> 20120119 = 15
ok: 19960120 -> 20120120 = 16
ok: 19960228 -> 20110227 = 14
ok: 19960228 -> 20110228 = 15
ok: 19960228 -> 20110301 = 15
ok: 19960229 -> 20110227 = 14
ok: 19960229 -> 20110228 = 14
ok: 19960229 -> 20110301 = 15
ok: 19970228 -> 20120227 = 14
ok: 19970228 -> 20120228 = 15
ok: 19970228 -> 20120229 = 15
ok: 19970228 -> 20120301 = 15
*/