基於jdk8的實用時間工具類, 已經經過多個項目的考驗與完善, 包含對"時間"的心得體會
歡迎轉載,轉載請註明網址:https://blog.csdn.net/qq_41910280
版本說明
2020-07-02 初次提交 (寫於2019年)
簡介
本文提供一個全面的基於jdk8的時間工具類。Talk is cheap, let’s Getting Started.
1. 直接上代碼
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
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 [email protected]
*/
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 = " 00:00:00";
public static final String DAY_END_TIME = " 23:59:59";
public static final DateTimeFormatter ISO_DATE_TIMESTAMP = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_DATE_TIME = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_DATE = DateTimeFormatter.ofPattern("uuuu-MM-dd").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_TIME = DateTimeFormatter.ofPattern("HH:mm:ss").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_MONTHDAY = DateTimeFormatter.ofPattern("MM-dd").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_DATE_WITHOUT_HYPHEN = DateTimeFormatter.ofPattern("uuuuMMdd").withResolverStyle(STRICT).withZone(DEFAULT_ZONE_ID);
public static final DateTimeFormatter ISO_DATETIME_WITHOUT_HYPHEN = DateTimeFormatter.ofPattern("uuuuMMddHHmmss").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();
}
/**
* 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 yyyy-MM-dd HH:mm:ss
* @return
*/
public static LocalDateTime parse2LocalDateTime(String text) {
return parse2LocalDateTime(text, null);
}
/**
* @param text
* @param formatter 默認yyyy-MM-dd HH:mm:ss
* @return
*/
public static LocalDateTime parse2LocalDateTime(String text, DateTimeFormatter formatter) {
formatter = defaultDateTimeFormatter(formatter);
return LocalDateTime.parse(text, formatter);
}
/**
* @param text yyyy-MM-dd HH:mm:ss
* @return
*/
public static Date parse2Date(String text) {
return toDate(parse2LocalDateTime(text));
}
/**
* @param text yyyy-MM-dd
* @return
*/
public static LocalDate parse2LocalDate(String text) {
return parse2LocalDate(text, null);
}
/**
* @param text
* @param formatter 默認yyyy-MM-dd
* @return
*/
public static LocalDate parse2LocalDate(String text, DateTimeFormatter formatter) {
formatter = defaultDateFormatter(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: return Timestamp.valueOf(localDateTime).getTime();
*
* @param localDateTime
* @return
*/
public static long getTime(LocalDateTime localDateTime) {
// Instant效率高於Timestamp
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
*/
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);
}
/**
* @param formatter 默認yyyy-MM-dd HH:mm:ss
* @return
*/
public static String now(DateTimeFormatter formatter) {
formatter = defaultDateTimeFormatter(formatter);
return LocalDateTime.now().format(formatter);
}
/**
* @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));
}
/**
* @param localDate
* @return
*/
public static Date getDayBegin(LocalDate localDate) {
return toDate(LocalDateTime.of(localDate, LocalTime.MIN));
}
/**
* @param localDate
* @return
*/
public static Date getDayEnd(LocalDate localDate) {
return toDate(LocalDateTime.of(localDate, LocalTime.MAX));
}
/**
* @param localDateTime
* @return
*/
public static Date getDayBegin(LocalDateTime localDateTime) {
return getDayBegin(localDateTime.toLocalDate());
}
/**
* @param localDateTime
* @return
*/
public static Date 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));
}
/**
* @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 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;
}
}
神奇的小尾巴:本人郵箱:[email protected] [email protected]
[email protected] 歡迎交流,共同進步。
歡迎轉載,轉載請註明本網址。