From 65a0ae3687c42f810d9a75d1a9da00464080fc32 Mon Sep 17 00:00:00 2001 From: tangw Date: Sat, 26 Jul 2025 21:04:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8D=B0=E5=B7=A5=E5=85=B7=E7=B1=BB?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8=E5=88=A4=E6=96=AD=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E6=96=B0=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../czlis/interfaceCommon/utils/AgeUtils.java | 460 ++++++++++++++++++ 1 file changed, 460 insertions(+) create mode 100644 lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/AgeUtils.java diff --git a/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/AgeUtils.java b/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/AgeUtils.java new file mode 100644 index 0000000..250b432 --- /dev/null +++ b/lis-interfaceCommon/src/main/java/com/czlis/interfaceCommon/utils/AgeUtils.java @@ -0,0 +1,460 @@ +package com.czlis.interfaceCommon.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 日期转年龄工具类(增强版:精确到小时) + */ +public class AgeUtils { + // 常量:1岁 = 365.25天 = 365.25×24小时 + private static final double HOURS_PER_YEAR = 365.25 * 24; // 8766.0 + // 常量:时间单位(支持岁、月、天) + private static final String UNIT_YEAR = "岁"; + private static final String UNIT_MONTH = "个月"; + private static final String UNIT_MONTH0 = "月"; + private static final String UNIT_DAY = "天"; + private static final String UNIT_HOUR= "时"; + private static final String UNIT_HOUR0= "小时"; + private static final String CODE_YEAR = "1"; + private static final String CODE_MONTH = "2"; + private static final String CODE_DAY = "3"; + private static final String CODE_HOUR= "4"; + /** + * 根据出生日期字符串(支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss)计算年龄 + * @param birthDate 出生日期(Date类型)如 "2000-03-15") + * @return 年龄(返回带单位的字符串,如 "25岁"、"3月"、"15天"、"8时") + */ + public static String getAge(Date birthDate) { + if (birthDate == null) { + return ""; + } + Map ageMap = getAgeUnitByBirthDate(birthDate); + String unit = (String) ageMap.get("nldw"); + Object value = ageMap.get("nl"); + return (value == null || unit == null) ? "" : value + unit; + } + + /** + * 根据出生日期计算精确年龄 + * @param birthStr 出生日期字符串(支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss) + * @return 年龄(返回带单位的字符串,如 "25岁"、"3月"、"15天"、"8时") + */ + public static String getAge(String birthStr) { + if (birthStr == null || birthStr.trim().isEmpty()) { + return ""; + } +// 尝试解析日期字符串(复用之前的逻辑) + Date birthDate = parseBirthDate(birthStr); + if (birthDate == null) { + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + return getAge(birthDate); + } + /** + * 根据出生日期计算精确年龄,返回Map格式 + * @return Map包含两个键: + * - "nldw":年龄单位(1、2、3、4) + * - "nl":对应的数值(如24、3、15、8) + */ + public static Map getAgeByBirthDate(Date birthDate) { + Map result = new HashMap<>(2); + if (birthDate == null) { + result.put("nldw", ""); + result.put("nl", null); + return result; + } + Map ageMap = getAgeUnitByBirthDate(birthDate); + String unit = (String) ageMap.get("nldw"); + ageMap.put("nldw", getUnitCode(unit)); + return ageMap; + } + /** + * 根据出生日期计算精确年龄,返回Map格式 + * @return Map包含两个键: + * - "nldw":年龄单位(1、2、3、4) + * - "nl":对应的数值(如24、3、15、8) + */ + public static Map getAgeByBirthDate(String birthStr) { + if (birthStr == null || birthStr.trim().isEmpty()) { + Map emptyResult = new HashMap<>(2); + emptyResult.put("nldw", ""); + emptyResult.put("nl", null); + return emptyResult; + } + // 尝试解析日期字符串(复用之前的逻辑) + Date birthDate = parseBirthDate(birthStr); + if (birthDate == null) { + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + return getAgeByBirthDate(birthDate); + } + + /** + * 根据出生日期(Date)计算年龄(按小时折算,精确到4位小数) + * @return 带4位小数的年龄(如1.5=1岁6个月,0.25=3个月) + */ + public static double getDecimalAge(Date birthDate) { + if (birthDate == null) { + return 0.0000; + } + + // 1. 计算当前时间与出生日期的毫秒差 + long currentTimeMillis = System.currentTimeMillis(); + long birthTimeMillis = birthDate.getTime(); + long diffMillis = currentTimeMillis - birthTimeMillis; + + // 2. 出生日期在未来:返回0.0000 + if (diffMillis <= 0) { + return 0.0000; + } + // 3. 转换为总小时数(精确到毫秒级) + double totalHours = diffMillis / (1000.0 * 60 * 60); // 除以毫秒→秒→分→小时 + // 4. 计算年龄(总小时数 ÷ 一年的小时数) + double age = totalHours / HOURS_PER_YEAR; + // 5. 精确到4位小数(四舍五入) + return new BigDecimal(age) + .setScale(4, RoundingMode.HALF_UP) + .doubleValue(); + } + /** + * 根据出生日期(字符串)计算年龄(按小时折算,精确到4位小数) + * @return 带4位小数的年龄(如1.5=1岁6个月,0.25=3个月) + */ + public static double getDecimalAge(String birthStr) { + Date birthDate = parseBirthDate(birthStr); // 复用之前的日期解析方法 + if (birthDate == null) { + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + return getDecimalAge(birthDate); + } + /** + * 根据出生日期(Date类型)计算年龄 + * @param birthDate 出生日期(不为null) + * @return 年龄(如 25) + */ + public static int getIntAge(Date birthDate) { + if (birthDate == null) { + throw new IllegalArgumentException("出生日期不能为空"); + } + + // 1. 获取当前日期和出生日期的日历对象 + Calendar currentCal = Calendar.getInstance(); // 当前日期 + Calendar birthCal = Calendar.getInstance(); // 出生日期 + birthCal.setTime(birthDate); + + // 2. 计算年份差 + int currentYear = currentCal.get(Calendar.YEAR); + int birthYear = birthCal.get(Calendar.YEAR); + int age = currentYear - birthYear; + + // 3. 处理未过当年生日的情况(年龄减1) + // 比较月份:当前月份 < 出生月份 → 未过生日 + int currentMonth = currentCal.get(Calendar.MONTH); + int birthMonth = birthCal.get(Calendar.MONTH); + if (currentMonth < birthMonth) { + age--; + } + // 月份相同,比较日期:当前日期 < 出生日期 → 未过生日 + else if (currentMonth == birthMonth) { + int currentDay = currentCal.get(Calendar.DAY_OF_MONTH); + int birthDay = birthCal.get(Calendar.DAY_OF_MONTH); + if (currentDay < birthDay) { + age--; + } + } + + // 4. 确保年龄不为负数(出生日期在未来的情况) + return Math.max(age, 0); + } + + /** + * 根据出生日期字符串计算年龄 + * @param birthStr 出生日期字符串(支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss) + * @return 年龄(如 25) + */ + public static int getIntAge(String birthStr) { + if (birthStr == null || birthStr.trim().isEmpty()) { + throw new IllegalArgumentException("出生日期字符串不能为空"); + } + Date birthDate = parseBirthDate(birthStr); + if (birthDate == null) { + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + return getIntAge(birthDate); + } + + /** + * 核心算法:根据出生日期计算精确年龄,返回Map格式 + * @return Map包含两个键: + * - "nldw":年龄单位(岁、月、天、小时) + * - "nl":对应的数值(如24、3、15、8) + */ + public static Map getAgeUnitByBirthDate(Date birthDate) { + Map result = new HashMap<>(2); + + if (birthDate == null) { + result.put("nldw", ""); + result.put("nl", null); + return result; + } + + Calendar currentCal = Calendar.getInstance(); + Calendar birthCal = Calendar.getInstance(); + birthCal.setTime(birthDate); + + // 1. 计算总毫秒差 + long diffMillis = currentCal.getTimeInMillis() - birthCal.getTimeInMillis(); + if (diffMillis <= 0) { + result.put("nldw", "岁"); + result.put("nl", 0); + return result; + } + + // 2. 按不同时间单位计算 + long totalHours = diffMillis / (1000 * 60 * 60); // 总小时数 + + if (totalHours < 24) { // 不足1天:返回小时 + result.put("nldw", "时"); + result.put("nl", (int) totalHours); + return result; + } + + long totalDays = totalHours / 24; // 总天数 + if (totalDays < 30) { // 不足1月:返回天数 + result.put("nldw", "天"); + result.put("nl", (int) totalDays); + return result; + } + + // 计算月数差(考虑月份天数不同) + int currentYear = currentCal.get(Calendar.YEAR); + int currentMonth = currentCal.get(Calendar.MONTH); + int currentDay = currentCal.get(Calendar.DAY_OF_MONTH); + int birthYear = birthCal.get(Calendar.YEAR); + int birthMonth = birthCal.get(Calendar.MONTH); + int birthDay = birthCal.get(Calendar.DAY_OF_MONTH); + + // 计算总月数 + int months = (currentYear - birthYear) * 12 + (currentMonth - birthMonth); + // 如果当前日期 < 出生日期,月数减1(未满月) + if (currentDay < birthDay) { + months--; + } + + if (months < 12) { // 不足1岁:返回月数 + result.put("nldw", "月"); + result.put("nl", months); + return result; + } + + // 计算年数(复用之前的逻辑) + int years = currentYear - birthYear; + if (currentMonth < birthMonth || (currentMonth == birthMonth && currentDay < birthDay)) { + years--; + } + + result.put("nldw", "岁"); + result.put("nl", years); + return result; + } + + /** + * 根据出生日期计算精确年龄,返回Map格式 + * @return Map包含两个键: + * - "nldw":年龄单位(岁、月、天、小时) + * - "nl":对应的数值(如24、3、15、8) + */ + public static Map getAgeUnitByBirthDate(String birthStr) { + if (birthStr == null || birthStr.trim().isEmpty()) { + Map emptyResult = new HashMap<>(2); + emptyResult.put("nldw", ""); + emptyResult.put("nl", null); + return emptyResult; + } + + // 尝试解析日期字符串(复用之前的逻辑) + Date birthDate = parseBirthDate(birthStr); + if (birthDate == null) { + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + + return getAgeUnitByBirthDate(birthDate); + } + /** + * 根据年龄和年龄单位估算出生日期(入参格式与getAgeMapByBirthDate返回值一致) + * @param value 年龄Map(格式:{value: 5, unit: "岁"} 或 {value: 3, unit: "个月"}) + * @param unit + * @return 估算的出生日期 + */ + public static Date getBirthDateByAge(Integer value,String unit) { + // 3. 获取当前时间(基于Calendar) + Calendar calendar = Calendar.getInstance(); // 当前时间 + // 4. 根据单位推算出生日期 + switch (unit) { + case CODE_YEAR: + case UNIT_YEAR: + // 岁:>1岁按当年1月1日,≤1岁按实际月数 + if (value > 1) { + calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - value); + calendar.set(Calendar.MONTH, Calendar.JANUARY); // 1月(0表示1月) + calendar.set(Calendar.DAY_OF_MONTH, 1); // 1日 + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + } else { + // ≤1岁:按月份推算(1岁=12个月) + calendar.add(Calendar.MONTH, -value * 12); + } + break; + case CODE_MONTH: + case UNIT_MONTH: + case UNIT_MONTH0: + // 个月:忽略小时,按整天推算 + calendar.add(Calendar.MONTH, -value); + // 重置时间为00:00:00 + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + break; + case CODE_DAY: + case UNIT_DAY: + // 天:忽略小时,按整天推算 + calendar.add(Calendar.DAY_OF_MONTH, -value); + // 重置时间为00:00:00 + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + break; + case CODE_HOUR: + case UNIT_HOUR: + case UNIT_HOUR0: + // 小时:保留精确时间 + calendar.add(Calendar.HOUR_OF_DAY, -value); + break; + + default: + throw new IllegalArgumentException("不支持的单位:" + unit); + } + + // 5. 返回推算的出生日期 + return calendar.getTime(); + } + + /** + * 单参数估算出生日期(支持"5岁"、"3个月"、"5小时"格式) + */ + /** + * 根据年龄Map估算出生日期(入参格式与getAgeMapByBirthDate返回值一致) + * @param ageMap 年龄Map(格式:{value: 5, unit: "岁"} 或 {value: 3, unit: "个月"}) + * @return 估算的出生日期 + */ + public static Date getBirthDateByAgeMap(Map ageMap) { + // 1. 校验入参格式(与getAgeMapByBirthDate返回格式一致) + validateAgeMap(ageMap); + + // 2. 提取数值和单位 + int value = (Integer) ageMap.get("nl"); + String unit = (String) ageMap.get("nldw"); + + + // 5. 返回推算的出生日期 + return getBirthDateByAge(value,unit); + } + + /** + * 单参数估算出生日期(支持"5岁"、"3月"、"5时"格式) + */ + public static Date getBirthDateByAge(String ageStr) { + // 解析年龄数值和单位(复用之前的逻辑) + int value = 0; + String unit = ""; + try { + int unitStartIndex = 0; + while (unitStartIndex < ageStr.length() && Character.isDigit(ageStr.charAt(unitStartIndex))) { + unitStartIndex++; + } + value = Integer.parseInt(ageStr.substring(0, unitStartIndex).trim()); + unit = ageStr.substring(unitStartIndex).trim(); + } catch (Exception e) { + throw new IllegalArgumentException("年龄格式错误(示例:5岁、3个月、5小时),输入:" + ageStr); + } + // 调用核心估算方法 + return getBirthDateByAge(value, unit); + } + + + /** + * 校验年龄Map格式(确保与getAgeMapByBirthDate返回格式一致) + */ + private static void validateAgeMap(Map ageMap) { + if (ageMap == null || ageMap.isEmpty()) { + throw new IllegalArgumentException("年龄Map不能为空"); + } + // 校验必须包含"nl"和"nldw"键 + if (!ageMap.containsKey("nl") || !ageMap.containsKey("nldw")) { + throw new IllegalArgumentException("年龄Map必须包含'nl'和'nldw'键(格式:{nl: 5, nldw: '岁'})"); + } + // 校验value为整数 + Object valueObj = ageMap.get("nl"); + if (!(valueObj instanceof Integer)) { + throw new IllegalArgumentException("'value'必须是整数(格式:{nl: 5, nldw: '岁'})"); + } + // 校验unit为有效单位 + Object unitObj = ageMap.get("nldw"); + if (!(unitObj instanceof String) || + !(UNIT_YEAR.equals(unitObj) || UNIT_MONTH.equals(unitObj) ||UNIT_MONTH0.equals(unitObj) || UNIT_HOUR0.equals(unitObj) || + UNIT_DAY.equals(unitObj) || UNIT_HOUR.equals(unitObj))) { + throw new IllegalArgumentException("'unit'必须是'岁'/'月'/'天'/'时'(格式:{nl: 5, nldw: '岁'})"); + } + } + // 私有方法:解析日期字符串(复用逻辑) + private static Date parseBirthDate(String birthStr) { + if (birthStr == null || birthStr.trim().isEmpty()) { + return null; + } + + SimpleDateFormat[] formats = { + new SimpleDateFormat("yyyy-MM-dd"), + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), + new SimpleDateFormat("yyyy/MM/dd"), + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss") + }; + + for (SimpleDateFormat format : formats) { + try { + return format.parse(birthStr); + } catch (ParseException ignored) { + // 尝试下一个格式 + } + } + + throw new IllegalArgumentException("出生日期格式错误,支持:yyyy-MM-dd、yyyy-MM-dd HH:mm:ss"); + } + // 私有方法:获取年龄单位代码 + private static String getUnitCode(String unitName) { + String unitCode=""; + if(UNIT_YEAR.equals(unitName))unitCode=CODE_YEAR; + else if (UNIT_MONTH.equals(unitName)) unitCode=CODE_MONTH; + else if (UNIT_MONTH0.equals(unitName)) unitCode=CODE_MONTH; + else if (UNIT_DAY.equals(unitName)) unitCode=CODE_DAY; + else if (UNIT_HOUR.equals(unitName)) unitCode=CODE_HOUR; + else if (UNIT_HOUR0.equals(unitName)) unitCode=CODE_HOUR; + return unitCode; + } + // 私有方法:获取年龄单位代码 + private static String getUnitName(String unitCode) { + String unitName=""; + if(CODE_YEAR.equals(unitCode))unitName=UNIT_YEAR; + else if (CODE_MONTH.equals(unitCode)) unitName=UNIT_MONTH; + else if (CODE_DAY.equals(unitCode)) unitName=UNIT_DAY; + else if (CODE_HOUR.equals(unitCode)) unitName=UNIT_HOUR; + return unitName; + } +} \ No newline at end of file