基于jdk8 LocalDate系列API的全新实用时间工具类

    技术2022-08-01  81

    基于jdk8 LocalDate系列API的实用时间工具类, 已经经过多个项目的考验与完善, 包含个人心得体会

    欢迎转载,转载请注明网址:https://blog.csdn.net/qq_41910280

    版本说明 2020-07-02 初次提交 (实际创作于2019年) 2020-08-22 更新: 1.增加灵活的时间格式 2.增加了周几的判断 3.增加了获取年、月的开始或结束时间 2020-09-10 更新: 1.优化了周几的判断 2020-11-13 更新: 1.优化获得年月日的开始/结束时间, 注意: 本次更新极个别方法不兼容历史版本, 但十分容易迁移 2.其他细节优化 2020-11-30 更新: 1.细节优化

    简介   本文提供一个全面的基于jdk8的时间工具类。Talk is cheap, let’s Getting Started.

    文章目录

    基于jdk8 LocalDate系列API的实用时间工具类, 已经经过多个项目的考验与完善, 包含个人心得体会 1. 直接上代码

    1. 直接上代码

    import java.time.*; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjusters; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import static java.time.format.ResolverStyle.STRICT; /** * <h3>时间工具类</h3> * <p> * <ul> * <li>u means year(year-proleptic) which can be negative<br/> * <li>y means year-of-era which con't be negative * </ul> * example:<br/> * 1 in "u" equal to 1 AD in "y G"<br/> * 0 in "u" equal to 1 BC in "y G"<br/> * -1 in "u" equal to 2 BC in "y G" * <p> * * @author zhouyou * @date 2019/10/28 18:18 * @email zhouyouchn@126.com * @blog https://blog.csdn.net/qq_41910280 */ public class TimeUtils { static { /** * 中国曾实行过夏令时(1986-1991) Asia/Shanghai会处理夏令时 而GMT+8不会 * 设置JVM时区 避免docker等采用UTC */ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai")); } /** * maybe we can set DEFAULT_ZONE_ID = ZoneOffset.ofHours(8); * or we can set DEFAULT_ZONE_ID = ZoneId.of("Asia/Shanghai"); */ public static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault(); /** * 东八区 并不能完全代表北京时间 * * @see #DEFAULT_ZONE_ID * @see #getDefaultZoneOffset(LocalDateTime) * @see #getDefaultZoneOffset(Instant) */ @Deprecated public static final ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.ofHours(8); public static final String DAY_BEGIN_TIME_SUFFIX = " 00:00:00"; public static final String DAY_END_TIME_SUFFIX = " 23:59:59"; // format=uuuu-MM-dd HH:mm:ss.SSS || parse日时分秒毫秒可选 public static final DateTimeFormatter ISO_ELASTIC_DATE_TIME_FORMATTER = new DateTimeFormatterBuilder().appendPattern("uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]]") .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .parseDefaulting(ChronoField.HOUR_OF_DAY, 0) .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0) .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0) .toFormatter().withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID); public static final DateTimeFormatter ISO_DATE_TIMESTAMP = ISO_ELASTIC_DATE_TIME_FORMATTER; public static final DateTimeFormatter ISO_DATE_TIME = buildDateTimeFormatter("uuuu-MM-dd HH:mm:ss"); public static final DateTimeFormatter ISO_DATE = buildDateTimeFormatter("uuuu-MM-dd"); public static final DateTimeFormatter ISO_TIME = buildDateTimeFormatter("HH:mm:ss"); public static final DateTimeFormatter ISO_MONTHDAY = buildDateTimeFormatter("MM-dd"); public static final DateTimeFormatter ISO_DATE_WITHOUT_HYPHEN = buildDateTimeFormatter("uuuuMMdd"); public static final DateTimeFormatter ISO_DATETIME_WITHOUT_HYPHEN = buildDateTimeFormatter("uuuuMMddHHmmss"); private static final String[] WEEK_DAY_STRS = {"一", "二", "三", "四", "五", "六", "日"}; public static DateTimeFormatter buildDateTimeFormatter(String pattern) { return DateTimeFormatter.ofPattern(pattern).withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID); } /** * <p> * <b>脱离时间谈ZoneOffset是错误的</b><br/> * see: 日光节约时间DST(夏令时) * example: 在一年中, 洛杉矶一段时间为"-8", 一段时间为"-7" * </p> * * @param localDateTime * @return */ private static ZoneOffset getDefaultZoneOffset(LocalDateTime localDateTime) { return DEFAULT_ZONE_ID.getRules().getOffset(localDateTime); } /** * @param instant * @return * @see #getDefaultZoneOffset(LocalDateTime) */ private static ZoneOffset getDefaultZoneOffset(Instant instant) { return DEFAULT_ZONE_ID.getRules().getOffset(instant); } /** * LocalDateTime 和 Date 的相互转换 */ public static Date toDate(LocalDateTime localDateTime) { return localDateTime == null ? null : Date.from(localDateTime.atZone(DEFAULT_ZONE_ID).toInstant()); } public static LocalDateTime toLocalDateTime(Date date) { return date == null ? null : toInstant(date).atZone(DEFAULT_ZONE_ID).toLocalDateTime(); } /** * LocalDate 和 Date 的相互转换 */ public static Date toDate(LocalDate localDate) { return localDate == null ? null : Date.from(localDate.atStartOfDay(DEFAULT_ZONE_ID).toInstant()); } public static LocalDate toLocalDate(Date date) { return date == null ? null : toInstant(date).atZone(DEFAULT_ZONE_ID).toLocalDate(); } /** * LocalDate 和 LocalDateTime 的相互转换 */ public static LocalDateTime toLocalDateTime(LocalDate localDate) { return localDate == null ? null : LocalDateTime.of(localDate, LocalTime.MIN); } public static LocalDate toLocalDate(LocalDateTime localDateTime) { return localDateTime == null ? null : localDateTime.toLocalDate(); } /** * LocalTime 和 Date 的相互转换 */ public static Date toDate(LocalTime localTime) { return localTime == null ? null : Date.from(localTime.atDate(LocalDate.now()).atZone(DEFAULT_ZONE_ID).toInstant()); } // 只要h以下单位 public static Date toTime(LocalTime localTime) { return localTime == null ? null : Date.from(localTime.atDate(LocalDate.ofEpochDay(0L)).atZone(DEFAULT_ZONE_ID).toInstant()); } public static LocalTime toLocalTime(Date date) { return date == null ? null : toInstant(date).atZone(DEFAULT_ZONE_ID).toLocalTime(); } /** * 不直接使用toInstant防止java.sql.Time或java.sql.Date抛出异常 * Instant instant; * if (date instanceof java.sql.Time || date instanceof java.sql.Date) { * Calendar calendar = Calendar.getInstance(); * calendar.setTime(date); * instant = calendar.toInstant(); * } else { * instant = date.toInstant(); * } * return instant; * * @param date * @return */ private static Instant toInstant(Date date) { return Instant.ofEpochMilli(date.getTime()); } /** * @param date * @return <b>yyyy-MM-dd HH:mm:ss</b> */ public static String format(Date date) { return format(date, null); } public static String format(Date date, DateTimeFormatter formatter) { formatter = defaultDateTimeFormatter(formatter); return formatter.format(toLocalDateTime(date)); } /** * @param localDateTime * @return <b>yyyy-MM-dd HH:mm:ss</b> */ public static String format(LocalDateTime localDateTime) { return format(localDateTime, null); } /** * @param localDateTime * @param formatter 默认yyyy-MM-dd HH:mm:ss * @return */ public static String format(LocalDateTime localDateTime, DateTimeFormatter formatter) { formatter = defaultDateTimeFormatter(formatter); return formatter.format(localDateTime); } /** * @param localDate * @return <b>yyyy-MM-dd</b> */ public static String format(LocalDate localDate) { return format(localDate, null); } /** * @param localDate * @param formatter 默认yyyy-MM-dd * @return */ public static String format(LocalDate localDate, DateTimeFormatter formatter) { formatter = defaultDateFormatter(formatter); return formatter.format(localDate); } /** * @param text uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static LocalDateTime parse2LocalDateTime(String text) { return parse2LocalDateTime(text, null); } /** * @param text * @param formatter 默认uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static LocalDateTime parse2LocalDateTime(String text, DateTimeFormatter formatter) { formatter = defaultDateTimeParser(formatter); return LocalDateTime.parse(text, formatter); } /** * @param text uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static Date parse2Date(String text) { return toDate(parse2LocalDateTime(text)); } /** * @param text * @param formatter 默认uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static Date parse2Date(String text, DateTimeFormatter formatter) { return toDate(parse2LocalDateTime(text, formatter)); } /** * @param text uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static LocalDate parse2LocalDate(String text) { return parse2LocalDate(text, null); } /** * @param text * @param formatter 默认uuuu-MM[-dd][ [HH][:mm][:ss][.SSS]] * @return */ public static LocalDate parse2LocalDate(String text, DateTimeFormatter formatter) { formatter = defaultDateTimeParser(formatter); return LocalDate.parse(text, formatter); } /** * @param text MM-dd * @return */ public static MonthDay parseMonthDay(String text) { return parseMonthDay(text, null); } /** * @param text MM-dd * @return */ public static MonthDay parseMonthDay(String text, DateTimeFormatter formatter) { formatter = defaultMonthDayFormatter(formatter); return MonthDay.parse(text, formatter); } /** * other way 1: (存在夏令时问题) * return localDateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli(); * other way 2: (Timestamp效率低于Instant) * return Timestamp.valueOf(localDateTime).getTime(); * * @param localDateTime * @return */ public static long getTime(LocalDateTime localDateTime) { return localDateTime.atZone(DEFAULT_ZONE_ID).toInstant().toEpochMilli(); } /** * 根据{@link #DEFAULT_ZONE_ID}进行时间戳解析 * * @param timeMillis ms * @return */ public static LocalDateTime parseTime(long timeMillis) { return LocalDateTime.ofInstant(Instant.ofEpochMilli(timeMillis), DEFAULT_ZONE_ID); } /** * <b>固定偏移量</b> * 根据DEFAULT_ZONE_OFFSET进行时间戳解析 * * @param timeMillis ms * @return * @see #parseTime(long) */ @Deprecated public static LocalDateTime parseTimeFast(long timeMillis) { int nanoOfSecond = (int) Math.floorMod(timeMillis, 1000) * 1000_000; long epochSecond = Math.floorDiv(timeMillis, 1000); return LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, DEFAULT_ZONE_OFFSET); } /** * <b>时间间隔</b> * <p> * 选择ChronoUnit是因为:<br/> * Duration和Period会计算各个时间差,但并不会整合, * 这意味着:如果相差2个月0天,获取的相差天数却是0 * <p/> * * @param temporal1 * @param temporal2 * @param unit * @return temporal2-temporal1的unit时间差 */ public static long between(Temporal temporal1, Temporal temporal2, ChronoUnit unit) { return unit.between(temporal1, temporal2); } /** * @return <b>yyyy-MM-dd HH:mm:ss</b> */ public static String now() { return now(null); } /** * @return <b>yyyy-MM-dd</b> */ public static String nowDate() { return LocalDate.now().format(ISO_DATE); } /** * @return <b>yyyy-MM-dd</b> */ public static String plusDate(long yearsToAdd, long monthsToAdd, long daysToAdd) { LocalDate now = LocalDate.now(); if (yearsToAdd != 0) { now = now.plusYears(yearsToAdd); } if (monthsToAdd != 0) { now = now.plusMonths(monthsToAdd); } if (daysToAdd != 0) { now = now.plusDays(daysToAdd); } return now.format(ISO_DATE); } /** * @return <b>yyyy-MM-dd</b> */ public static String plusDate(LocalDate localDate, long yearsToAdd, long monthsToAdd, long daysToAdd) { if (localDate == null) { localDate = LocalDate.now(); } if (yearsToAdd != 0) { localDate = localDate.plusYears(yearsToAdd); } if (monthsToAdd != 0) { localDate = localDate.plusMonths(monthsToAdd); } if (daysToAdd != 0) { localDate = localDate.plusDays(daysToAdd); } return localDate.format(ISO_DATE); } /** * @return <b>yyyy-MM-dd</b> */ public static String plusDate(Date date, long yearsToAdd, long monthsToAdd, long daysToAdd) { return plusDate(toLocalDate(date), yearsToAdd, monthsToAdd, daysToAdd); } /** * @param formatter 默认yyyy-MM-dd HH:mm:ss * @return */ public static String now(DateTimeFormatter formatter) { formatter = defaultDateTimeFormatter(formatter); return LocalDateTime.now().format(formatter); } /** * 获取当前时间是周几 */ public static String getDayOfWeek(Calendar calendar) { int i = calendar.get(Calendar.DAY_OF_WEEK); return WEEK_DAY_STRS[(i + 5) % 7]; } /** * 获取当前时间是周几 */ public static String getDayOfWeek(LocalDate localDate) { int value = localDate.getDayOfWeek().getValue(); return WEEK_DAY_STRS[value - 1]; } /** * 获取当前时间是周几 */ public static String getDayOfWeek(Date date) { return getDayOfWeek(toLocalDate(date)); } /** * @param text yyyy-MM-dd * @return */ public static Date getDayBegin(String text) { return toDate(LocalDateTime.of(LocalDate.parse(text, ISO_DATE), LocalTime.MIN)); } /** * @param text yyyy-MM-dd * @return */ public static Date getDayEnd(String text) { return toDate(LocalDateTime.of(LocalDate.parse(text, ISO_DATE), LocalTime.MAX)); } public static LocalDateTime getDayBegin(LocalDate localDate) { return LocalDateTime.of(localDate, LocalTime.MIN); } public static LocalDateTime getDayEnd(LocalDate localDate) { return LocalDateTime.of(localDate, LocalTime.MAX); } public static LocalDateTime getDayBegin(LocalDateTime localDateTime) { return getDayBegin(localDateTime.toLocalDate()); } public static LocalDateTime getDayEnd(LocalDateTime localDateTime) { return getDayEnd(localDateTime.toLocalDate()); } public static Date getDayBegin(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MIN)); } public static Date getDayEnd(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MAX)); } public static Date getYearBegin(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MIN) .with(TemporalAdjusters.firstDayOfYear())// 或.with(ChronoField.DAY_OF_YEAR, 1) ); } public static Date getYearEnd(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MAX).with(TemporalAdjusters.lastDayOfYear())); } public static LocalDateTime getYearBegin(LocalDateTime localDateTime) { return LocalDateTime.of(toLocalDate(localDateTime), LocalTime.MIN).with(TemporalAdjusters.firstDayOfYear()); } public static LocalDateTime getYearEnd(LocalDateTime localDateTime) { return LocalDateTime.of(toLocalDate(localDateTime), LocalTime.MAX).with(TemporalAdjusters.lastDayOfYear()); } public static LocalDate getYearBegin(LocalDate localDate) { return localDate.with(TemporalAdjusters.firstDayOfYear()); } public static LocalDate getYearEnd(LocalDate localDate) { return localDate.with(TemporalAdjusters.lastDayOfYear()); } public static Date getMonthBegin(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth())); } public static Date getMonthEnd(Date date) { return toDate(LocalDateTime.of(toLocalDate(date), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth())); } public static LocalDateTime getMonthBegin(LocalDateTime localDateTime) { return LocalDateTime.of(toLocalDate(localDateTime), LocalTime.MIN).with(TemporalAdjusters.firstDayOfMonth()); } public static LocalDateTime getMonthEnd(LocalDateTime localDateTime) { return LocalDateTime.of(toLocalDate(localDateTime), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth()); } public static LocalDate getMonthBegin(LocalDate localDate) { return localDate.with(TemporalAdjusters.firstDayOfMonth()); } public static LocalDate getMonthEnd(LocalDate localDate) { return localDate.with(TemporalAdjusters.lastDayOfMonth()); } /** * @param text yyyy-MM-dd * @return */ @Deprecated public static Date[] getDayBeginAndEnd(String text) { LocalDate localDate = LocalDate.parse(text, ISO_DATE); return getDaysByLocalDate(LocalDateTime.of(localDate, LocalTime.MIN), LocalDateTime.of(localDate, LocalTime.MAX)); } @Deprecated public static Date[] getDayBeginAndEnd(Date date) { LocalDate localDate = toLocalDate(date); return getDaysByLocalDate(LocalDateTime.of(localDate, LocalTime.MIN), LocalDateTime.of(localDate, LocalTime.MAX)); } private static Date[] getDaysByLocalDate(LocalDateTime... localDateTimes) { Date[] dates = new Date[localDateTimes.length]; for (int i = 0; i < dates.length; i++) { dates[i] = toDate(localDateTimes[i]); } return dates; } private static DateTimeFormatter defaultDateTimeParser(DateTimeFormatter formatter) { return formatter == null ? ISO_ELASTIC_DATE_TIME_FORMATTER : formatter; } private static DateTimeFormatter defaultDateTimeFormatter(DateTimeFormatter formatter) { return formatter == null ? ISO_DATE_TIME : formatter; } private static DateTimeFormatter defaultDateFormatter(DateTimeFormatter formatter) { return formatter == null ? ISO_DATE : formatter; } private static DateTimeFormatter defaultMonthDayFormatter(DateTimeFormatter formatter) { return formatter == null ? ISO_MONTHDAY : formatter; } } 神奇的小尾巴: 本人邮箱:zhouyouchn@126.com zhoooooouyou@gmail.com zhouyou@whut.edu.cn 欢迎交流,共同进步。 欢迎转载,转载请注明本网址。
    Processed: 0.015, SQL: 9