如下未特別說明, 均指jdk1.8實現版本.
功能列表:
- 解決多線程下使用SimpleDateFormat(非線程安全類), 導致的如下問題:
java.lang.NumberFormatException: multiple points
- 多線程環境下,將 dateStr 轉化爲 Date 形式.
- 多線程環境下,將 dateTimeStr 轉化爲 Date 形式.
- 對象轉爲JSON字符串, 序列化格式由自己自定義指定(如: 空list,空string,null數字,null布爾值,nullMap).
- 根據步長(step)來向前或向後獲取某一天的日期字符串(date形式).
- 根據步長(step)來向前或向後獲取某一天的日期字符串(datetime形式).
- 根據給定參照日期(baseDate), 和步長(step)來向前或向後獲取某一天的日期字符串(datetime形式).
- 字符串轉Long類型.
- 根據指定的如下格式的字符串, 格式化爲Date類型.
private static final String DATE_FORMAT = “yyyy-MM-dd
”;
private static final String DATETIME_FORMAT = “yyyy-MM-dd HH:mm:ss
”;- 判斷某一年份是否閏年.
- 根據步長返回N年前或N年後的年份數字.
- 根據步長返回N年前或N年後的年份數字.
- JDK8之前版本: 獲取當前時間的整點時刻.
- JDK8中 : 獲取當前時間的整點時刻.
- 通過如下枚舉類型
* ①: LOCAL_DATE獲取當日日期
: 格式爲 “yyyy-MM-dd”
* ②: LOCAL_DATETIME獲取當日整點時間:
格式爲 “yyyy-MM-dd HH:00:00”.- 獲取兩個日期間隔的所有日期.
MyDateUtils.java代碼清單:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Stream;
/**
* User: DavidTest
* Date:
* Time:
* Desc: Java日期處理工具類
*/
@Slf4j
public class MyDateUtils {
private static DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static DateTimeFormatter DTF_OF_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
//對於每一個( Date | Datetime ) 類型的線程
private static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL_SDF = new ThreadLocal<>();
//日期類型枚舉:①:LOCAL_DATE,格式 "yyyy-MM-dd" ;②:LOCAL_DATETIME,格式: "yyyy-MM-dd HH:mm:ss".
public enum MY_DATE_TYPE {
LOCAL_DATE, LOCAL_DATETIME
}
/**
* 多線程環境下,將 dateStr 轉化爲 Date 形式.
* 避免多線程下使用不安全的 SimpleDateFormat,
* 拋出: java.lang.NumberFormatException: multiple points 異常.
*
* @param dateStr
* @return
*/
public static Date parseBySDF(String dateStr) throws ParseException {
SimpleDateFormat sdf = THREAD_LOCAL_SDF.get();
if (sdf == null) {
sdf = new SimpleDateFormat(DATE_FORMAT);
}
log.info(">>>> 當前線程爲: " + Thread.currentThread().getName());
Date date = sdf.parse(dateStr);
return date;
}
/**
* 多線程環境下,將 dateTimeStr 轉化爲 Date 形式.
* 避免多線程下使用不安全的 SimpleDateFormat,
* 拋出: java.lang.NumberFormatException: multiple points 異常.
*
* @param dateTimeStr
* @return
*/
public static Date parseBySDFLong(String dateTimeStr) throws ParseException {
SimpleDateFormat sdfLong = THREAD_LOCAL_SDF.get();
if (sdfLong == null) {
sdfLong = new SimpleDateFormat(DATETIME_FORMAT);
}
log.info(">>>> 當前線程爲: " + Thread.currentThread().getName());
Date date = sdfLong.parse(dateTimeStr);
return date;
}
public static String toJSONStr(Object obj) {
String msg = JSON.toJSONString(obj,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.WriteMapNullValue);
return msg;
}
public static String getDate(Long daysToAdd) {
LocalDate daysBefore = LocalDate.now().plusDays(daysToAdd);
return daysBefore.format(DTF);
}
public static String getDateTime(Long daysToAdd) {
LocalDateTime daysBefore = LocalDateTime.now().plusDays(daysToAdd);
return daysBefore.format(DTF_OF_TIME);
}
public static String getDate(String baseDate, Long daysToAdd) {
LocalDate daysBefore = LocalDate.parse(baseDate).plusDays(daysToAdd);
return daysBefore.format(DTF);
}
public static Long getLong(String x) {
Long r = null;
try {
r = new Long(x.trim());
} catch (NumberFormatException e) {
log.error("", e);
}
return r;
}
public static Date getDate(String dateStr) {
try {
return new SimpleDateFormat(DATE_FORMAT).parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
public static String getDateStr(Date date) {
return new SimpleDateFormat(DATETIME_FORMAT).format(date);
}
/**
* 判斷某一年份是否閏年
*
* @param year
* @return
*/
public static Boolean isLeapYear(Integer year) {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
return true;
} else {
return false;
}
}
/**
* 根據步長返回N年前或N年後的年份數字
*
* @param step
* @return
*/
public static Integer getSpecificYearByStep(Integer step) {
LocalDate localDate = LocalDate.now();
return localDate.plusYears(step).getYear();
}
/**
* 根據步長返回N年前或N年後的年份數字
*
* @param baseDateTime 日期時間格式, 如"2020-04-20 00:00:00"
* @param step 向前後向後的時間間隔,由正負值確定是向前或向後變更小時數(如 step=1, 表示"2020-04-20 01:00:00
* @return
*/
public static String getSpecificDateHourByStep(String baseDateTime, Integer step) {
if (baseDateTime != null && 19 == baseDateTime.length()) {
LocalDateTime localDate = LocalDateTime.parse(baseDateTime, DTF_OF_TIME);
return localDate.plusHours(step).format(DTF_OF_TIME);
} else {
throw new RuntimeException("Parameter baseDateTime's formatter invalid, please check!");
}
}
/**
* 獲取2個日期之間相差的天數.
* 如果:
* 1: localDate1 > localDate2, 值爲正.
* 2: localDate1 < localDate2, 值爲負.
*
* @param localDate1 起始日
* @param localDate2 終止日
* @return
*/
public static Integer getPeriodDays(LocalDate localDate1, LocalDate localDate2) {
return (int) (localDate1.toEpochDay() - localDate2.toEpochDay());
}
/**
* JDK8之前: 獲取當前時間的整點時刻
*
* @return
*/
public static Date getCurrentHourTimeBeforeJDK8() {
Calendar ca = Calendar.getInstance();
ca.set(Calendar.MINUTE, 0);
ca.set(Calendar.SECOND, 0);
ca.set(Calendar.MILLISECOND, 0);
return ca.getTime();
}
/**
* JDK8中 : 獲取當前時間的整點時刻
*
* 如下兩種實現方式都可以.
* @return
*/
public static Date getCurrentHourTimeOfJDK8() {
LocalDateTime time = LocalDateTime.now();
return Date.from(time.minusMinutes(time.getMinute()).minusSeconds(time.getSecond()).atZone(ZoneId.systemDefault()).toInstant());
//return Date.from(time.withMinute(0).withSecond(0).atZone(ZoneId.systemDefault()).toInstant());
}
/**
* 通過如下枚舉類型
* ①: LOCAL_DATE 獲取當日日期 : 格式爲 "yyyy-MM-dd"
* ②: LOCAL_DATETIME 獲取當日整點時間: 格式爲 "yyyy-MM-dd HH:00:00"
*
* @return
*/
public static String getCurrentDateOrTimeByType(MY_DATE_TYPE date_type) {
LocalDateTime time = LocalDateTime.now();
switch (date_type) {
case LOCAL_DATE:
return (time.withMinute(0).withSecond(0).withNano(0)).format(DTF);
case LOCAL_DATETIME:
return (time.withMinute(0).withSecond(0).withNano(0)).format(DTF_OF_TIME);
default:
return null;
}
}
/**
* 獲取兩個日期間隔的所有日期
*
* @param start 格式必須爲'2019-01-01'
* @param end 格式必須爲'2019-02-01'
* @return
*/
public static List<String> getBetweenDate(String start, String end) {
List<String> list = new ArrayList<>();
LocalDate startDate = LocalDate.parse(start);
LocalDate endDate = LocalDate.parse(end);
long distance = ChronoUnit.DAYS.between(startDate, endDate);
System.out.println("distance = " + distance);
Stream.iterate(startDate, localDate -> localDate.plusDays(1))
.limit(distance + 1)
.forEach(f -> {
list.add(f.toString());
});
return list;
}
public static void main(String[] args) {
// System.out.println(getSpecificYearByStep(-1));
// System.out.println(MyDateUtils.getSpecificYearByStep(0));
// System.out.println(MyDateUtils.getDate("2020-02-29", -366L));
// System.out.println(MyDateUtils.getDate("2019-01-01", 0L));
// System.out.println(MyDateUtils.getDate("2020-02-28", -365L));
// System.out.println(MyDateUtils.getDateTime(0L));
// System.out.println(getCurrentDateOrTimeByType(MY_DATE_TYPE.LOCAL_DATE));
// System.out.println(getCurrentDateOrTimeByType(MY_DATE_TYPE.LOCAL_DATETIME));
// System.out.println((int)((double)297/54*2));
System.out.println(getBetweenDate("2019-05-01", "2020-05-20").size());
System.out.println(getSpecificDateHourByStep("2020-05-21 00:00:00", -1));
}
}