日期类工具 DataUtil
public class DateUtils {
/**
* 北京时区
*/
public static final ZoneOffset BJ_ZONE = ZoneOffset.of("+8");
/**
* 秒、毫秒转换单位
*/
public static final long MILLI_SECOND_EXCHANGE_TIME_BASE = 1000L;
/**
* 获取当前距离第二天还有多少秒
*
* @return 当前距离第二天还有多少秒
*/
public static Long getSecondsNextEarlyMorning() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
return (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
}
/**
* data转string
*
* @param date 时间
* @return 年月日
*/
public static String dateToString(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(date);
}
/**
* 获取当天开始时间
*
* @return 当天开始时间
*/
public static Date getDayBegin() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);// 0点
cal.set(Calendar.MINUTE, 0);// 0分
cal.set(Calendar.SECOND, 0);// 0秒
cal.set(Calendar.MILLISECOND, 0);// 0毫秒
return cal.getTime();
}
/**
* 获取某段时间内的所有日期开始时间的秒级时间戳
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 段时间内的所有日期开始时间的秒级时间戳
*/
public static List<Long> findDates(Date startTime, Date endTime) {
Calendar cStart = Calendar.getInstance();
cStart.setTime(startTime);
cStart.set(Calendar.HOUR_OF_DAY, 0);
cStart.set(Calendar.SECOND, 0);
cStart.set(Calendar.MINUTE, 0);
cStart.set(Calendar.MILLISECOND, 0);
List<Long> dateList = new ArrayList<>();
//起始日期加上
dateList.add(cStart.getTime().getTime() / 1000L);
// 此日期是否在指定日期之后
while (endTime.after(cStart.getTime())) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
cStart.add(Calendar.DAY_OF_MONTH, 1);
dateList.add(cStart.getTime().getTime() / 1000L);
}
if (!CollectionUtils.isEmpty(dateList)){
dateList.remove(dateList.size()-1);
}
return dateList;
}
/**
* 获取昨天开始时间
*
* @return date 格式时间
*/
public static Date getBeginDayOfYesterday() {
Calendar cal = Calendar.getInstance();
cal.setTime(getDayBegin());// 当天开始时间
cal.add(Calendar.DAY_OF_MONTH, -1);// 当天月份天数减1
return cal.getTime();
}
/**
* 获取昨天结束时间
*
* @return 获取昨天结束时间 date 类型
*/
public static Date getEndDayOfYesterday() {
Calendar cal = Calendar.getInstance();
cal.setTime(getDayEnd());// 当天结束时间
cal.add(Calendar.DAY_OF_MONTH, -1);// 当天月份天数减1
return cal.getTime();
}
/**
* 获取明天开始时间
*
* @return 明天开始时间
*/
public static Date getBeginDayOfTomorrow() {
Calendar cal = Calendar.getInstance();
cal.setTime(getDayBegin());// 当天开始时间
cal.add(Calendar.DAY_OF_MONTH, 1);// 当天月份天数加1
return cal.getTime();
}
/**
* 获取明天结束时间
*
* @return 明天结束时间
*/
public static Date getEndDayOfTomorrow() {
Calendar cal = Calendar.getInstance();
cal.setTime(getDayEnd());// 当天结束时间
cal.add(Calendar.DAY_OF_MONTH, 1);// 当天月份天数加1
return cal.getTime();
}
/**
* 获取当天结束时间
*
* @return 当天结束时间
*/
public static Date getDayEnd() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 23);// 23点
cal.set(Calendar.MINUTE, 59);// 59分
cal.set(Calendar.SECOND, 59);// 59秒
return cal.getTime();
}
private final static DateTimeFormatter YYYY_MM = DateTimeFormatter.ofPattern("yyyyMM");
public static Date localDateToDate(@NonNull LocalDate localDate) {
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
return Date.from(instant);
}
public static LocalDate dateToLocalDate(@NonNull Date date) {
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
return localDateTime.toLocalDate();
}
/**
* 获取当前月份的第一天
*
* @return
*/
public static LocalDate firstDayOfCurrentMonth() {
LocalDate localDate = LocalDate.now();
return LocalDate.of(localDate.getYear(), localDate.getMonthValue(), 1);
}
/**
* 获取下个月的今天
*
* @param target
* @return
*/
public static LocalDate nextMonthToday(LocalDate target) {
return target.plusMonths(1L);
}
/**
* 获取上个月的今天
*
* @param target
* @return
*/
public static LocalDate lastMonthToday(LocalDate target) {
return target.plusMonths(-1L);
}
/**
* 获取第二天
*
* @param target
* @return
*/
public static LocalDate nextDay(LocalDate target) {
return target.plusDays(1L);
}
/**
* 获取当前月份的最后那天
*
* @return
*/
public static LocalDate lastDayOfCurrentMonth() {
return lastDayOfTargetMonth(LocalDate.now());
}
/**
* 获取指定日期所在月份的第一天
*
* @param targetDate
* @return
*/
public static LocalDate firstDayOfTargetMonth(LocalDate targetDate) {
return LocalDate.of(targetDate.getYear(), targetDate.getMonthValue(), 1);
}
/**
* 获取指定日期所在月份的最后那天
*
* @param targetDate
* @return
*/
public static LocalDate lastDayOfTargetMonth(LocalDate targetDate) {
return targetDate.with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 获取指定日期所在月份的第一天
*
* @param targetDate
* @return
*/
public static LocalDate firstDayOfNextMonth(LocalDate targetDate) {
targetDate = targetDate.plusMonths(1L);
return LocalDate.of(targetDate.getYear(), targetDate.getMonthValue(), 1);
}
/**
* 获取指定日期所在月份的最后那天
*
* @param targetDate
* @return
*/
public static LocalDate lastDayOfNextMonth(LocalDate targetDate) {
return targetDate.plusMonths(1L).with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 获取指定月份的总天数
*
* @param localDate
* @return
*/
public static int totalDaysOfMonth(LocalDate localDate) {
return lastDayOfTargetMonth(localDate).getDayOfMonth();
}
/**
* 两个日期之间间隔的天数(含开始日期当天)
*
* @param start
* @param end
* @return
*/
public static int intervalDays(LocalDate start, LocalDate end) {
return Period.between(start, end).plusDays(1L).getDays();
}
/**
* 是否同一个月份
*
* @param source
* @param target
* @return
*/
public static boolean isSameMonth(LocalDate source, LocalDate target) {
return YearMonth.from(source).equals(YearMonth.from(target));
}
/**
* 格式化日期
*
* @param localDate
* @return
*/
public static String formatYYYYMM(LocalDate localDate) {
return localDate.format(YYYY_MM);
}
/**
* 转换
*
* @param str
* @return
*/
public static YearMonth toYearMonth(String str) {
return YearMonth.parse(str, YYYY_MM);
}
public static void main(String[] args) {
LocalDate start = LocalDate.of(2021, 8, 10);
LocalDate end = LocalDate.of(2021, 9, 1);
System.out.println(lastDayOfCurrentMonth());
System.out.println(firstDayOfTargetMonth(start));
System.out.println(totalDaysOfMonth(LocalDate.now()));
System.out.println(totalDaysOfMonth(start));
System.out.println(totalDaysOfMonth(end));
System.out.println(LocalDate.now().getMonth() == start.getMonth());
System.out.println(LocalDate.now().plusMonths(1L));
System.out.println(intervalDays(start, end));
System.out.println(Period.between(start, end).getMonths());
System.out.println(YearMonth.from(start).equals(YearMonth.from(end)));
System.out.println(formatYYYYMM(LocalDate.now()));
System.out.println(toYearMonth(formatYYYYMM(LocalDate.now())));
System.out.println(toYearMonth(formatYYYYMM(LocalDate.now())).atDay(1));
}
}
手机号码正则校验
正则表达式
package com.ruqimobility.user.constant;
import java.util.regex.Pattern;
public abstract class RegularConst {
/**
* 手机号校验正则
*/
private static final String TELEPHONE = "^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$";
/**
* 手机号正则校验匹配器
*/
public static final Pattern PHONE_PATTERN = Pattern.compile(TELEPHONE);
}
实体类字段贴上@phone注解, 会进行自动校验
package com.ruqimobility.user.request;
import com.ruqimobility.user.annotation.Phone;
import com.ruqimobility.user.dtos.TripShareSetting;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CreateEmergencyContactRequest {
/**
* 用户编号,必选
*/
@NotNull(message = "用户ID必填")
@ApiModelProperty(value = "用户ID", required = true)
private Long userId;
/**
* 联系人手机号码,必选
*/
@Phone(ignoreEmpty = false)
@ApiModelProperty(value = "联系人手机号码", required = true)
private String phone;
/**
* 联系人姓名,必选
*/
@NotBlank(message = "联系人姓名必填")
@ApiModelProperty(value = "联系人姓名", required = true)
private String name;
/**
* 操作者名称,可选
*/
@ApiModelProperty(value = "操作者名称")
private String operator;
/**
* 是否自动分享行程,1分享,0不分享(默认值,兼容旧版本)
*/
@NotNull(message = "必须设置自动分享行程参数")
@ApiModelProperty(value = "是否自动分享行程,1分享,0不分享", required = true)
private Boolean enableTripShare = false;
/**
* 行程分享设置内容
*/
@ApiModelProperty(value = "行程分享设置内容")
private TripShareSetting tripShareSetting;
}
使用phone注解的方式
package com.ruqimobility.user.annotation;
import com.ruqimobility.user.constant.RegularConst;
import org.springframework.util.StringUtils;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;
import java.util.regex.Matcher;
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {Phone.PhoneValidator.class})
public @interface Phone {
/**
* 提示信息
*
* @return
*/
String message() default "手机号码不正确";
/**
* 校验组
*
* @return
*/
Class<?>[] groups() default {};
/**
* 载体
*
* @return
*/
Class<? extends Payload>[] payload() default {};
/**
* 是否忽略空值,默认忽略
*/
boolean ignoreEmpty() default true;
/**
* 校验器实现逻辑
*/
class PhoneValidator implements ConstraintValidator<Phone, String> {
private Phone annotation;
@Override
public void initialize(Phone annotation) {
this.annotation = annotation;
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//如果配置忽略空值且传的是空值,则默认通过校验
if (annotation.ignoreEmpty() && StringUtils.isEmpty(value)) {
return true;
}
if (!annotation.ignoreEmpty() && StringUtils.isEmpty(value)) {
return false;
}
Matcher matcher = RegularConst.PHONE_PATTERN.matcher(value);
return matcher.matches();
}
}
}
身份证校验工具类IdCardUtils
public class IdCardUtil {
/**
* 15位身份证号
*/
private static final Integer FIFTEEN_ID_CARD = 15;
/**
* 18位身份证号
*/
private static final Integer EIGHTEEN_ID_CARD = 18;
/**
* 根据身份证号获取性别
*
* @param idCard
* @return
*/
public static String getSex(String idCard) {
String sex = "";
if (!StringUtils.isEmpty(idCard)) {
//15位身份证号
if (idCard.length() == FIFTEEN_ID_CARD) {
if (Integer.parseInt(idCard.substring(14, 15)) % 2 == 0) {
sex = "女";
} else {
sex = "男";
}
//18位身份证号
} else if (idCard.length() == EIGHTEEN_ID_CARD) {
// 判断性别
if (Integer.parseInt(idCard.substring(16).substring(0, 1)) % 2 == 0) {
sex = "女";
} else {
sex = "男";
}
}
}
return sex;
}
/**
* 获取身份证有效期
*
* @param validDate
* @return
*/
public static Date getExpireDate(String validDate) {
if (Objects.nonNull(validDate)) {
if (RegularConst.isIdCardValidPeriod(validDate)) {
String expire = validDate.substring(9);
return DateUtil.getDayEndTime(DateUtils.parseDate(expire));
}
if (validDate.contains("长期") || validDate.contains("永久")) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 50);
return calendar.getTime();
}
}
return null;
}
/**
* 获取身份证上的出生日期
*
* @param birth
* @return
*/
public static Date getBirthDate(String birth) {
if (Objects.nonNull(birth) && RegularConst.isIdCardBirth(birth)) {
return DateUtils.parseDate(birth);
}
return null;
}
/**
* 根据身份证号获取年龄
*
* @param idCard
* @return
*/
public static Integer getAge(String idCard) {
int age = 0;
// 当前年份
int nowYear = LocalDate.now().getYear();
// 当前月份
int nowMonth = LocalDate.now().getMonthValue();
if (!StringUtils.isEmpty(idCard) && isValid(idCard)) {
//15位身份证号
if (idCard.length() == FIFTEEN_ID_CARD) {
// 身份证上的年份(15位身份证为1980年前的)
String idCardYear = "19" + idCard.substring(6, 8);
// 身份证上的月份
String idCardYue = idCard.substring(8, 10);
// 当前用户还没过生
if (Integer.parseInt(idCardYue) <= nowMonth) {
age = nowYear - Integer.parseInt(idCardYear) + 1;
} else {
age = nowYear - Integer.parseInt(idCardYear);
}
//18位身份证号
} else if (idCard.length() == EIGHTEEN_ID_CARD) {
// 身份证上的年份
String idCardYear = idCard.substring(6).substring(0, 4);
// 身份证上的月份
String idCardYue = idCard.substring(10).substring(0, 2);
// 当前月份大于用户出身的月份表示已过生日
if (Integer.parseInt(idCardYue) <= nowMonth) {
age = nowYear - Integer.parseInt(idCardYear) + 1;
// 当前用户还没过生日
} else {
age = nowYear - Integer.parseInt(idCardYear);
}
}
}
return age;
}
/**
* 获取出生日期 yyyyMMdd
*
* @param idCard
* @return
*/
public static String getBirth(String idCard) {
if (!StringUtils.isEmpty(idCard)) {
//15位身份证号
if (idCard.length() == FIFTEEN_ID_CARD) {
// 身份证上的年份(15位身份证为1980年前的)
return "19" + idCard.substring(6, 12);
//18位身份证号
} else if (idCard.length() == EIGHTEEN_ID_CARD) {
return idCard.substring(6, 14);
}
}
return null;
}
/**
* 获取出生日期 yyyy年MM月dd日
*
* @param idCard
* @return
*/
public static String getBirthday(String idCard) {
String[] birth = getBirthArr(idCard);
return birth.length == 3 ? birth[0] + "年" + birth[1] + "月" + birth[2] + "日" : "";
}
private static String[] getBirthArr(String idCard) {
if (!StringUtils.isEmpty(idCard)) {
String[] arr = new String[3];
//15位身份证号
if (idCard.length() == FIFTEEN_ID_CARD) {
// 身份证上的年份(15位身份证为1980年前的)
arr[0] = "19" + idCard.substring(6, 8);
//身份证上的月份
arr[1] = idCard.substring(8, 10);
//身份证上的日期
arr[2] = idCard.substring(10, 12);
//18位身份证号
} else if (idCard.length() == EIGHTEEN_ID_CARD) {
// 身份证上的年份
arr[0] = idCard.substring(6, 10);
// 身份证上的月份
arr[1] = idCard.substring(10, 12);
//身份证上的日期
arr[2] = idCard.substring(12, 14);
}
return arr;
}
return new String[0];
}
/**
* 身份证验证
*
* @param id 号码内容
* @return 是否有效
*/
public static boolean isValid(String id) {
boolean validResult = true;
//校验长度只能为15或18
int len = id.length();
if (len != FIFTEEN_ID_CARD && len != EIGHTEEN_ID_CARD) {
validResult = false;
}
//校验生日
if (!validDate(id)) {
validResult = false;
}
return validResult;
}
/**
* 校验生日
*
* @param idCard
* @return
*/
private static boolean validDate(String idCard) {
try {
String birth = idCard.length() == 15 ? "19" + idCard.substring(6, 12) : idCard.substring(6, 14);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Date birthDate = sdf.parse(birth);
if (!birth.equals(sdf.format(birthDate))) {
return false;
}
} catch (ParseException e) {
return false;
}
return true;
}
}