package com.apobates.forum.utils; import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.TimeZone; import java.util.TreeMap; /** * java.time包工具类 * * @author xiaofanku * @since 20190331 */ public final class DateTimeUtils { public final static String Y = "Year"; public final static String M = "Month"; public final static String D = "Day"; private final static String YMDHMS_L = "yyyy-MM-dd HH:mm:ss"; private final static String YMDHMS = "yyyyMMddHHmmssSSS"; private DateTimeUtils() throws Exception { throw new Exception("不需要实化公共工具类"); } /** * 格式化当前日期为yyyy-MM-dd HH:mm:ss<14> https://tools.ietf.org/html/rfc3339 示例: * 1985-04-12T23:20:50.52Z 1996-12-19T16:39:57-08:00 * * @param date * 要求不为null,反之返回空字符串 * @return */ public static String getRFC3339(LocalDateTime date) { if (null == date) { return ""; } return date.format(DateTimeFormatter.ofPattern(YMDHMS_L).withZone(ZoneId.systemDefault())); } /** * 使用指定的时区进行格式化 * * @param date * 要求不为null,反之返回空字符串 * @param zone * 时区 * @return */ public static String getRFC3339(LocalDateTime date, ZoneId zone) { if (null == date) { return ""; } return date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(zone)); } /** * 格式化当前日期为yyyy-MM-ddTHH:mm:ss<15> * https://www.iso.org/iso-8601-date-and-time-format.html 示例: * 2015-12-14T12:00:29.3387979-05:00 2008-09-15T15:53:00+05:00 * * @param date * 要求不为null,反之返回空字符串 * @return */ public final static String getISO8601(LocalDateTime date) { if (null == date) { return ""; } return date.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); } /** * 格式化当前日期为yyyyMMdd<16> * * @return */ public static String getYMD() { return getYMDByLine().replaceAll("-", ""); } /** * 格式化日期 * * @param date * @return */ public static String formatClock(LocalDateTime date) { if (null == date) { return "-"; } LocalDateTime n = LocalDateTime.now(); if (!isSameYear(date, n)) { // 不是同一年 return date.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")); } if (!isSameMonth(date, n)) { // 是同一年 // 不是同一个月{return m-d} return date.format(DateTimeFormatter.ofPattern("MM月dd日")); } if (!isSameDay(date, n)) { // 同一个月 // 不是同一天 long dd = diffDays(n, date); return (dd <= 1) ? "昨天" : dd + "天前"; } // 同一天 long diffMin = diffMinutes(n, date); if (diffMin <= 1) { // 一分钟以内 return "刚刚"; } if (diffMin > 1 && diffMin < 60) { // 一小时以内 return diffMin + "分钟前"; } return Math.round(diffMin / 60) + "小时前"; } /** * 格式化指定日期为yyyyMMdd * * @param date * 要求不为null,反之返回空字符串 * @return */ public static String getYMD(LocalDateTime date) { if (null == date) { return ""; } return getYMDByLine(date.toLocalDate()).replaceAll("-", ""); } /** * 格式化当前日期为yyyy-MM-dd<17> * * @return */ public static String getYMDByLine() { return getYMDByLine(LocalDate.now()); } /** * 格式化指定日期为yyyy-MM-dd * * @param date * 要求不为null,反之返回空字符串 * @return */ public static String getYMDByLine(LocalDate date) { if (null == date) { return ""; } return date.toString(); } /** * 计算昨天的日期 * * @return */ public static LocalDateTime getYesterDay() { return LocalDateTime.now().minusDays(1); } /** * 格式化当前日期为HH:mm:ss<18> * * @return */ public static String getTimeString() { return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); } /** * 格式化当前日期为yyyyMMddHHmmssSSS<19> * * @return */ public static String getDateFullFormatString() { return LocalDateTime.now().format(DateTimeFormatter.ofPattern(YMDHMS)); } /** * 指定的日期是否与当前日期是同一天<11> * * @param date * 要求不为null,反之返回false * @return */ public static boolean isSameDay(LocalDateTime date) { if (null == date) { return false; } return isSameDay(date, LocalDateTime.now()); } /** * 两个指定的日期是否是同一天 * * @param date1 * 要求不为null,反之返回false * @param date2 * 要求不为null,反之返回false * @return */ public static boolean isSameDay(LocalDateTime date1, LocalDateTime date2) { if (null == date1 || null == date2) { return false; } // LocalDate ld1 = date1.toLocalDate(); LocalDate ld2 = date2.toLocalDate(); return ld1.getYear() == ld2.getYear() && ld1.getMonthValue() == ld2.getMonthValue() && ld1.getDayOfMonth() == ld2.getDayOfMonth(); } /** * 指定的日期是否与当前日期是同一月<12> * * @param date * 要求不为null,反之返回false * @return */ public static boolean isSameMonth(LocalDateTime date) { if (null == date) { return false; } return isSameMonth(date, LocalDateTime.now()); } /** * 两个指定的日期是否是同一月 * * @param date1 * 要求不为null,反之返回false * @param date2 * 要求不为null,反之返回false * @return */ public static boolean isSameMonth(LocalDateTime date1, LocalDateTime date2) { if (null == date1 || null == date2) { return false; } LocalDate ld1 = date1.toLocalDate(); LocalDate ld2 = date2.toLocalDate(); return ld1.getYear() == ld2.getYear() && ld1.getMonthValue() == ld2.getMonthValue(); } /** * 指定的日期是否与当前日期是同一年<13> * * @param date * 要求不为null,反之返回false * @return */ public static boolean isSameYear(LocalDateTime date) { if (null == date) { return false; } return isSameYear(date, LocalDateTime.now()); } /** * 两个指定的日期是否是同一年
* * @param date1 * 要求不为null,反之返回false * @param date2 * 要求不为null,反之返回false * @return */ public static boolean isSameYear(LocalDateTime date1, LocalDateTime date2) { if (null == date1 || null == date2) { return false; } return date1.toLocalDate().getYear() == date2.toLocalDate().getYear(); } /** * 使用默认的时区格式化日期 * * @param date * 要求不为null,反之返回空字符串 * @param formatString * 日期格式字符串 * @return */ public static String formatDateString(LocalDateTime date, String formatString) { if (null == date) { return ""; } try { return date.format(DateTimeFormatter.ofPattern(formatString)); } catch (Exception e) { } return "-"; } /** * 获取上月的第一天凌晨日期(00:00:00)<20> * * @return */ public static LocalDateTime getPreviousMonthFirstDayEarlyMorning() { return LocalDate.now().minusMonths(1).atStartOfDay(); } /** * 获取上月的第后一天午夜日期(23:59:59)<21> * * @return */ public static LocalDateTime getPreviousMonthLastDayMidnight() { LocalDateTime prevMonthFirstDay = getPreviousMonthFirstDayEarlyMorning(); return prevMonthFirstDay.withHour(23).withMinute(59).withSecond(29); } /** * 获取本月的第一天凌晨日期(00:00:00)<2> * * @return */ public static LocalDateTime getCurrentMonthFirstDayEarlyMorning() { return LocalDate.now().withDayOfMonth(1).atStartOfDay(); } /** * 获取今天的凌晨(00:00:00)<1> 适用的范围广 * * @return */ public static LocalDateTime getTodayEarlyMorning() { return LocalDate.now().atStartOfDay(); } /** * 获取今天的午夜日期(23:59:59) * * @return */ public static LocalDateTime getTodayMidnight() { LocalDate date = LocalDate.now(); return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 23, 59, 59); } /** * 将指定日期设置为凌晨(00:00:00)<3> 用在几个作业(cron)类上 * * @param date * 要求不为null,否则抛出NPE * @return */ public static LocalDateTime setDateEarlyMorning(LocalDateTime date) { Objects.requireNonNull(date); return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 0, 0, 0); } /** * 将指定日期设置为午夜(23:59:59)<4> * * @param date * 要求不为null,否则抛出NPE * @return */ public static LocalDateTime setDateMidnight(LocalDateTime date) { Objects.requireNonNull(date); return LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 23, 59, 59); } /** * 昨天午夜的日期(23:59:59)<5> * * @return */ public static LocalDateTime getYesterdayMidnight() { LocalDateTime yesDay = getYesterDay(); return LocalDateTime.of(yesDay.getYear(), yesDay.getMonthValue(), yesDay.getDayOfMonth(), 23, 59, 59); } /** * 获得指定月份第一天凌晨(00:00:00)<6> * * @param year * 年 * @param month * 月 * @return */ public static LocalDateTime getFirstDayEarlyMorningOfMonth(int year, int month) { LocalDate ld = LocalDate.of(year, month, 1); return ld.atStartOfDay(); } /** * 获得指定月份最后一天午夜(23:59:59)<7> * * @param year * 年 * @param month * 月 * @return */ public static LocalDateTime getLastDayMidnightOfMonth(int year, int month) { LocalDate monthOneDay = getFirstDayEarlyMorningOfMonth(year, month).toLocalDate(); int lastDay = monthOneDay.lengthOfMonth(); return LocalDateTime.of(year, month, lastDay, 23, 59, 59); } /** * 两个日期之间天数差<8> * * @param date1 * 要求不为null,反之返回-1 * @param date2 * 要求不为null,反之返回-1 * @return 最近的为date1,返回正值;反之返回负值 */ public static long diffDays(LocalDateTime date1, LocalDateTime date2) { if (null == date1 || null == date2) { return -1; } return date2.until(date1, ChronoUnit.DAYS); } /** * 两个日期之间分钟数差<9> * * @param date1 * 要求不为null,反之返回-1 * @param date2 * 要求不为null,反之返回-1 * @return 最近的为date1,返回正值;反之返回负值 */ public static long diffMinutes(LocalDateTime date1, LocalDateTime date2) { if (null == date1 || null == date2) { return -1; } return date2.until(date1, ChronoUnit.MINUTES); } /** * 指定的日期在{limit}{calendarUnit}后,是否小于当前日期 例: c1在5小时后,是否小于当前日期<10> * * @param c1 * 要求不为null,反之返回false * @param unit * TemporalUnit单位,例:年:ChronoUnit.YEARS,月:ChronoUnit.MONTHS,日:ChronoUnit.DAYS,小时:ChronoUnit.HOURS,分钟:ChronoUnit.MINUTES,秒:ChronoUnit.SECONDS * @param limit * 单位值 * @return 如果当前日期大于c1累加后的值返回true */ public static boolean isFeatureDate(LocalDateTime c1, TemporalUnit unit, int limit) { if (null == c1) { return false; } LocalDateTime ldt = c1.plus(limit, unit); return LocalDateTime.now().isBefore(ldt); } /** * 判断指定的日期是否是未来时 * * @param dateTime * 要求不为null,反之返回false * @return */ public static boolean isFeatureDate(LocalDateTime dateTime) { if (null == dateTime) { return false; } return LocalDateTime.now().isBefore(dateTime); } /** * 使用yyyy-MM-dd HH:mm:ss格式解析日期 * * @param timeString * 日期字符串.要求不为null,否则抛出NPE * @return */ public static LocalDateTime parseDate(String timeString) { Objects.requireNonNull(timeString); return parseDate(timeString, YMDHMS_L); } /** * 使用指定的格式解析日期
* * @param timeString * 日期字符串.要求不为null,否则抛出NPE * @param formatString * 日期格式字符串 * @return */ public static LocalDateTime parseDate(String timeString, String formatString) { Objects.requireNonNull(timeString); return LocalDateTime.parse(timeString, DateTimeFormatter.ofPattern(formatString)); } /** * 当前日期在指定分钟后的日期
* * @param minutelimit * 分钟数 * @return */ public static LocalDateTime addMinuteForDate(int minutelimit) { return LocalDateTime.now().plusMinutes(minutelimit); } /** * 将指定的日期加上指定的分钟
* * @param date * 要求不为null,否则抛出NPE * @param minutelimit * 分钟数 * @return */ public static LocalDateTime addMinuteForDate(LocalDateTime date, int minutelimit) { Objects.requireNonNull(date); return date.plusMinutes(minutelimit); } /** * 当前日期在指定小时后的日期
* * @param hourlimit * 小时数 * @return */ public static LocalDateTime addHourForDate(int hourlimit) { return LocalDateTime.now().plusHours(hourlimit); } /** * 将指定的日期加上指定的小时
* * @param date * 要求不为null,否则抛出NPE * @param hourlimit * 小时数 * @return */ public static LocalDateTime addHourForDate(LocalDateTime date, int hourlimit) { Objects.requireNonNull(date); return date.plusHours(hourlimit); } /** * 当前日期在指定天后的日期
* * @param daylimit * 天数 * @return */ public static LocalDateTime addDayForDate(int daylimit) { return LocalDateTime.now().plusDays(daylimit); } /** * 将指定的日期加上指定的天
* * @param date * 要求不为null,否则抛出NPE * @param daylimit * 天数 * @return */ public static LocalDateTime addDayForDate(LocalDateTime date, int daylimit) { Objects.requireNonNull(date); return date.plusDays(daylimit); } /** * 当前日期在指定月后的日期
* * @param monthlimit * 月数 * @return */ public static LocalDateTime addMonthForDate(int monthlimit) { return LocalDateTime.now().plusMonths(monthlimit); } /** * 将指定的日期加上指定的月
* * @param date * 要求不为null,否则抛出NPE * @param monthlimit * 月数 * @return */ public static LocalDateTime addMonthForDate(LocalDateTime date, int monthlimit) { Objects.requireNonNull(date); return date.plusMonths(monthlimit); } /** * 当前日期在指定年后的日期
* * @param yearlimit * 年数 * @return */ public static LocalDateTime addYearForDate(int yearlimit) { return LocalDateTime.now().plusYears(yearlimit); } /** * 将指定的日期加上指定的年
* * @param date * 要求不为null,否则抛出NPE * @param yearlimit * 年数 * @return */ public static LocalDateTime addYearForDate(LocalDateTime date, int yearlimit) { Objects.requireNonNull(date); return date.plusYears(yearlimit); } /** * 指定日期的前几天日期
* * @param date * 要求不为null,否则抛出NPE * @param day * 天数 * @return */ public static LocalDateTime beforeDayForDate(LocalDateTime date, int day) { Objects.requireNonNull(date); return date.minusDays(day); } /** * 指定日期的前几分钟日期
* * @param date * 要求不为null,否则抛出NPE * @param minute * 分钟数 * @return */ public static LocalDateTime beforeMinuteForDate(LocalDateTime date, int minute) { Objects.requireNonNull(date); return date.minusMinutes(minute); } /** * 将指定的日期转成unix timestamp * * @param date * 要求不为null,反之返回0 * @return */ public static Integer covertTimestamp(LocalDateTime date) { if (null == date) { return 0; } Long d = Timestamp.valueOf(date).getTime() / 1000L; return d.intValue(); } /** * 将指定的unix timestamp转成util.LocalDateTime * * @param timestamp * 要求不为null,否则抛出NPE.unix 时间戳,例:1589316 时间戳是自 1970 年 1 月 1 * 日(00:00:00 GMT)以来的秒数。它也被称为 Unix 时间戳(Unix Timestamp)。 * @return */ public static LocalDateTime getDateTimeByUnixTimestamp(Integer timestamp) { Objects.requireNonNull(timestamp); return new Timestamp(timestamp * 1000L).toLocalDateTime(); } /** * 获得当前的unix timestamp * * @return */ public static Integer getUnixTimestamp() { Long d = Timestamp.valueOf(LocalDateTime.now()).getTime() / 1000L; return d.intValue(); } /** * 输出当前日期所在年(yyyy)和月(MM) * * @return key=CommonUtils.Y(ear)|M(onth), Y对应四位数字的年,M对应两位数的月 */ public static Map getCurrentY4M2() { return getYearAndMonth(LocalDate.now()); } /** * 输出指定日期所在年(yyyy)和月(MM) * * @param date * java.time.LocalDate 日期,要求不为null,反之返回空集合 * @return key=DateTimeUtils.Y(ear)|M(onth), Y对应四位数字的年,M对应两位数的月 */ public static Map getYearAndMonth(LocalDate date) { if (null == date) { return Collections.emptyMap(); } String[] ymArray = date.toString().split("-"); Map data = new HashMap<>(); data.put(DateTimeUtils.Y, ymArray[0]); data.put(DateTimeUtils.M, ymArray[1]); return data; } /** * 将java.util.Calendar 转为java.time.LocalDateTime * 注意:Jdk8和以上的环境都不要使用java.util.Calendar,java.util.Date,java.text.SimpleDateFormat * * @param calendar * 要求不为null,否则抛出NPE * @return */ public static LocalDateTime toLocalDateTime(Calendar calendar) { Objects.requireNonNull(calendar); TimeZone tz = calendar.getTimeZone(); ZoneId zid = (null == tz) ? ZoneId.systemDefault() : tz.toZoneId(); return LocalDateTime.ofInstant(calendar.toInstant(), zid); } /** * 将 java.time.LocalDateTime 转为java.util.Date * 注意:Jdk8和以上的环境都不要使用java.util.Calendar,java.util.Date,java.text.SimpleDateFormat * * @param dateTime * 要求不为null,否则抛出NPE * @return */ public static Date toDate(LocalDateTime dateTime) { Objects.requireNonNull(dateTime); ZoneId systemZone = ZoneId.systemDefault(); ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(Instant.now()); Instant instant = dateTime.toInstant(currentOffsetForMyZone); return Date.from(instant); } /** * 以时区ID参照转化为java.util.Date * * @param dateTime * 时间.要求不为null,否则抛出NPE * @param zone * 时区ID * @return */ public static Date toZoneDate(LocalDateTime dateTime, ZoneId zone) { Objects.requireNonNull(dateTime); Instant instant = dateTime.atZone(zone).toInstant(); return Date.from(instant); } /** * 填充数据源中时间的空值,主要用于连续日期的统计 * * @param start 开始日期 * @param finish 结束日期 * @param rawdata 数据源,要求Key=YYYY-MM-DD * @return */ public static TreeMap fillEmptyResult(LocalDateTime start, LocalDateTime finish, TreeMap rawdata){ TreeMap data = new TreeMap<>(); LocalDateTime loopDate=start; do{ String loopKey = DateTimeUtils.getYMDByLine(loopDate.toLocalDate()); try{ Long size = rawdata.get(loopKey); if(size==null){ size = 0L; } data.put(loopKey, size); }catch(NullPointerException e){ data.put(loopKey, 0L); } loopDate = DateTimeUtils.addDayForDate(loopDate, 1); }while(!DateTimeUtils.isSameDay(loopDate, finish)); return data; } }