逻辑思路
以出生日期对比当前时间,计算时间差,然后转换为天数时间戳(秒),再分别计算年份,月份,天数(注:以时间差按年月日递减格式化时间);其他语言也可采用此逻辑思路;
注意关键点
因为年份按四年一闰(365 * 4)+ 1=365.25(一年份);均衡月份:365.25/12=30.4375;天份=86400;才能精确计算具体的年龄,若是要计算时分秒,可继续设定对应单位;附上代码示例
代码示例
代码方法采用PHP8版本,低版本修改入参即可,其他语言可借用此逻辑,修改一下语法即可
/**
* 计算年龄
*
* @param string|int $birthday 生日
* @param int $type 类型:0默认年岁,1年月,2年月日
* @param bool $is_fm 是否格式年月日:false默认格式化,true不格式化返回(岁数,不返月份和天数)
* @return int|string
*/
function age(string|int $birthday, int $type=0, bool $is_fm=false): int|string
{
$birthday = is_numeric($birthday) ? $birthday : strtotime($birthday);
$d_unit = 86400; // 一天
// 时间差:当前时间和出生日期之差
$day_time = time() - $birthday;
if ($day_time < $d_unit && $type < 3) {
return 0;
}
// 年月日时间戳单位
$units = [
365.25 * $d_unit, // 一年:四年一闰=365 * 4 + 1
30.4375 * $d_unit, // 一月:均衡每月月份=365.25 / 12
$d_unit, // 一天:24 * 3600
3600, // 一小时: 60 * 60
60 // 一分
];
$ages = [];
foreach ($units as $key=>$unit) {
$age = floor($day_time / $unit);
if ($is_fm === true) {
return $age; // 不允许格式化,只能返回年龄(一年以内直接返回0,若要计算虚岁,则向上取一)
}
// 指定类型计算设定类型,截断后续操作
if ($key === $type) {
break;
}
// 计算出当前等于0,不操作
if ($age == 0) {
continue;
}
// 递减去当前等级的时间戳
$day_time -= $age * $unit;
// 拼接时间格式单位
$age .= match ($key) {
0=> '岁',
1=> '月',
2=> '天',
3=> '小时',
4=> '分',
default=> ''
};
$ages[] = $age;
}
return implode('', $ages);
}
# 调用示例
$birthday = '1990-07-01'; # 当前时间:2023-07-12
echo age($birthday); # 输出结果:33岁11天
运算逻辑解析
$birthday = is_numeric($birthday) ? $birthday : strtotime($birthday);
// 年-月-日-单位
$y_unit = 365.25; // 一年:四年一闰=365 * 4 + 1;
$m_unit = 30.4375; // 一月:均衡每月月份=365.25 / 12
$d_unit = 86400; // 一天
// 时间差:当前时间和出生日期之差
$day_time = time() - $birthday;
if ($day_time < $d_unit) {
return 0;
}
// 计算年份
$y_age = bcdiv($day_time, $y_unit * $d_unit);
if ($is_fm === true) {
return $y_age; // 不允许格式化,只能返回年龄(一年以内直接返回0,若要计算虚岁,则向上取一)
}
// 计算月份
$day_time -= $y_age * ($y_unit * $d_unit); // 减去年份,剩余月份
$m_age = bcdiv($day_time , $m_unit * $d_unit);
// 计算天数
$day_time -= $m_age * ($m_unit * $d_unit); // 减去月份,剩余天份
$d_age = bcdiv($day_time , $d_unit);
// 格式化:年月日
$fy_age = $y_age == 0 ? '' : $y_age.'岁';
$fm_age = $m_age == 0 ? '' : $m_age.'月';
$fd_age = $d_age == 0 ? '' : $d_age.'天';
return match ($type) {
1=> $fy_age . $fm_age,
2=> $fy_age . $fm_age . $fd_age,
default=> $fy_age
};
反馈
若有疑问不解,欢迎留言讨论