该工具类只支持18位长度的二代身份证号码,主要功能包含:身份证号码格式校验、根据身份证号码获取生日、根据身份证号码获取年龄、根据身份证号码获取指定时间点的年龄、根据身份证号获取性别。
import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * 身份证工具类,由于现在使用的是二代身份证,所以只验证18位 * 身份证号码中涉及到行政区划代码,代码不能验证其是否真实存在,所以我们只能验证身份号码逻辑正确性, 并不能验证身份证号码是否真实存在 * * 身份证组成: * 地址码:(前6位)所在县(市、旗、区)的行政区划代码 * 出生日期码:(第7位到第14位) * 顺序码:(第15位到17位)县、区级政府所辖派出所的分配码 * 校验码:(最后1位) **/ public class IDCardUtils { /** * 基础正则格式:首位非0数字,末位数字或“X”,年份前两位19或20(第7、8位),其他位为数字 */ private final static String REGEX = "^[1-9]\\d{5}(19|20)\\d{9}[\\d|X]$"; /** * 省、直辖市代码表,身份证号的前6位为地址信息,我们只验证前两位 */ private final static Map<String, String> ZONE = new HashMap<String, String>(); static { ZONE.put("11", "北京"); ZONE.put("12", "天津"); ZONE.put("13", "河北"); ZONE.put("14", "山西"); ZONE.put("15", "内蒙古"); ZONE.put("21", "辽宁"); ZONE.put("22", "吉林"); ZONE.put("23", "黑龙江"); ZONE.put("31", "上海"); ZONE.put("32", "江苏"); ZONE.put("33", "浙江"); ZONE.put("34", "安徽"); ZONE.put("35", "福建"); ZONE.put("36", "江西"); ZONE.put("37", "山东"); ZONE.put("41", "河南"); ZONE.put("42", "湖北"); ZONE.put("43", "湖南"); ZONE.put("44", "广东"); ZONE.put("45", "广西"); ZONE.put("46", "海南"); ZONE.put("50", "重庆"); ZONE.put("51", "四川"); ZONE.put("52", "贵州"); ZONE.put("53", "云南"); ZONE.put("54", "西藏"); ZONE.put("61", "陕西"); ZONE.put("62", "甘肃"); ZONE.put("63", "青海"); ZONE.put("64", "宁夏"); ZONE.put("65", "新疆"); ZONE.put("71", "台湾"); ZONE.put("81", "香港"); ZONE.put("82", "澳门"); ZONE.put("91", "国外"); } /** * 每位加权因子 */ private static final int POWER[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; /** * 第18位校检码 */ private static final String VERIFY_CODE[] = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" }; /** * 验证身份证格式 * * @param idCardNo * @return */ public static boolean verify(String idCardNo) { // 1.基础正则格式:首位非0数字,末位数字或“X”,年份前两位19或20(第7、8位),其他位为数字 if (idCardNo == null || !idCardNo.matches(REGEX)) { return false; } // 2.前两位区域代码校验 if (!ZONE.containsKey(idCardNo.substring(0, 2))) { return false; } // 3.验证生日 String birthdayStr = idCardNo.substring(6, 14); Date birthday = toBirthDay(birthdayStr); SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd"); // 转换失败或不相等(生日可能存在输入20187890这种情况)或者大于当前时间都返回false if (birthday == null || !birthdayStr.equals(df.format(birthday)) || birthday.after(new Date())) { return false; } // 4.顺序码不作验证,没有规则限制,数字即可 // 5.验证位验证,计算规则为:身份证前17位数字,对应乘以每位的权重因子,然后相加得到数值X,与11取模获得余数,得到数值Y,通过Y得到校验码。 if (!idCardNo.substring(17, 18).equals(calcVerifyCode(idCardNo))) { return false; } return true; } /** * 从身份证号码中获取生日 * * @param idCardNo * @return */ public static Date getBirthDay(String idCardNo) { if (verify(idCardNo)) { return toBirthDay(idCardNo.substring(6, 14)); } return null; } /** * 从身份证号码中获取当前时间年龄,-1:获取失败 * * @param idCardNo * @return age */ public static int getAge(String idCardNo) { return getAge(idCardNo,new Date()); } /** * 从身份证号码中获取指定时间点的年龄,-1:获取失败 * * @param idCardNo * @param time * @return age */ public static int getAge(String idCardNo,Date time) { Date birthdate = getBirthDay(idCardNo); if (null != birthdate) { Calendar calendar = Calendar.getInstance(); calendar.setTime(time); int yearNow = calendar.get(Calendar.YEAR); int monthNow = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以加1 int dayNow = calendar.get(Calendar.DAY_OF_MONTH); calendar.setTime(birthdate); int yearBirth = calendar.get(Calendar.YEAR); int monthBirth = calendar.get(Calendar.MONTH) + 1; // 月份从0开始,所以加1 int dayBirth = calendar.get(Calendar.DAY_OF_MONTH); int age = yearNow - yearBirth; if (monthNow <= monthBirth) { if (monthNow == monthBirth) { if (dayNow < dayBirth) { age--; } } else { age--; } } return age; } return -1; } /** * 从身份证号中获取性别 0:获取失败,1:男,2:女 * * @param idCardNo * @return */ public static int getGender(String idCardNo) { if (verify(idCardNo)) { // 奇数为男,偶数为女 return (Integer.parseInt(idCardNo.substring(16, 17)) % 2) == 0 ? 2 : 1; } return 0; } // 生日字符串转换为日期 private static Date toBirthDay(String birthdayStr) { try { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, Integer.parseInt(birthdayStr.substring(0, 4))); calendar.set(Calendar.MONTH, Integer.parseInt(birthdayStr.substring(4, 6)) - 1);// 月份从0开始,所以减1 calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(birthdayStr.substring(6, 8))); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar.getTime(); } catch (Exception e) { return null; } } // 计算验证位。规则为:身份证前17位数字,对应乘以每位的权重因子,然后相加得到数值x,与11取模获得余数y,通过y得到校验码。 private static String calcVerifyCode(String idCardNo) { int sum = 0; // 身份证前17位 char[] fix17 = idCardNo.substring(0, 17).toCharArray(); for (int i = 0; i < 17; i++) { sum += (Integer.parseInt(fix17[i] + "") * POWER[i]); // 每位的权重因子然后求和 } return VERIFY_CODE[sum % 11]; // 与11取模然后得到校验码 } }