為什么阿里開發(fā)手冊(cè)不建議使用Date類?
在日常編碼中,基本上99%的項(xiàng)目都會(huì)有一個(gè)DateUtil工具類,而時(shí)間工具類里用的最多的就是java.util.Date。
大家都這么寫,這還能有問題??
當(dāng)你的“默認(rèn)常識(shí)”出現(xiàn)問題,這個(gè)打擊,就是毀滅性的。
但是,在進(jìn)行安全掃描的時(shí)候,提示java.util.Date存在安全漏洞。
public class DateUtil {
/**
* 日期格式化
*/
public static String formatDate(Date date, String format) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
/**
* 字符串轉(zhuǎn)Date
*/
public static Date parseDate(String dateStr, String format) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.parse(dateStr);
}
/**
* 獲取指定格式的當(dāng)前時(shí)間
*/
public static String getCurrentDate(String format) {
// 獲取當(dāng)前時(shí)間
Date currentDate = new Date();
// 定義日期格式
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.format(currentDate);
}
}
把組件風(fēng)險(xiǎn)列表截圖+DateUtil工具類發(fā)給我的編程小助手ChatGPT4o。
Prompt:在進(jìn)行安全掃描的時(shí)候,提示java.util.Date存在安全漏洞,有什么漏洞,如何解決?
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Date;
public class DateUtil {
// 日期格式化
public static String formatDate(LocalDateTime dateTime, String format) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
return dateTime.format(formatter);
}
// 字符串轉(zhuǎn)Date
public static LocalDateTime parseDate(String dateStr, String format) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
return LocalDateTime.parse(dateStr, formatter);
}
// 獲取指定格式的當(dāng)前時(shí)間
public static String getCurrentDate(String format) {
// 獲取當(dāng)前時(shí)間
LocalDateTime currentDate = LocalDateTime.now();
// 定義日期格式
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(format);
return currentDate.format(dateFormat);
}
// 將 java.util.Date 轉(zhuǎn)為 java.time.LocalDateTime
public static LocalDateTime convertToLocalDateTime(Date date) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
// 將 java.time.LocalDateTime 轉(zhuǎn)為 java.util.Date
public static Date convertToDate(LocalDateTime dateTime) {
return Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
}
}
以下是Date設(shè)計(jì)上的主要缺陷:
- Date 這個(gè)名稱本身就具有誤導(dǎo)性。它實(shí)際上表示的是一個(gè)時(shí)間點(diǎn),而非日期。因此,更為恰當(dāng)?shù)拿Q應(yīng)為 Instant,這與 java.time 中的對(duì)應(yīng)類型相符。
- 它不是一個(gè)最終類,這導(dǎo)致了諸如 java.sql.Date 等不良的繼承使用。java.sql.Date 旨在表示一個(gè)日期,但由于名稱相同而常常引起混淆。
- Date 是可變的,而日期/時(shí)間類型通常是自然值,適合用不可變類型進(jìn)行建模。Date 的可變性(例如通過 setTime 方法)迫使開發(fā)人員不得不創(chuàng)建大量防御性副本,以確保代碼的安全性。
- Date 在許多地方(包括 toString() 方法)隱式使用系統(tǒng)本地時(shí)區(qū),這常常讓開發(fā)人員感到困惑。更多細(xì)節(jié)可以參見“時(shí)間點(diǎn)是什么”部分。
- Date 的月份編號(hào)從 0 開始,這是借鑒自 C 語言的設(shè)計(jì)。這種設(shè)計(jì)導(dǎo)致了大量的“偏一”錯(cuò)誤。同樣,年份編號(hào)從 1900 開始,也是借鑒自 C 語言。顯然,當(dāng) Java 出現(xiàn)時(shí),我們已經(jīng)意識(shí)到這種設(shè)計(jì)不利于代碼的可讀性。
- Date 的方法命名也不清晰。getDate() 方法返回的是月中的某一天,而 getDay() 方法返回的是星期幾。給這些方法起更具描述性的名稱并不會(huì)很困難,但遺憾的是,這并未實(shí)現(xiàn)。
- 對(duì)于是否支持閏秒,Date 的表現(xiàn)也不明確。文檔中指出“一秒鐘由一個(gè) 0 到 61 的整數(shù)表示;60 和 61 僅在實(shí)際正確跟蹤閏秒的 Java 實(shí)現(xiàn)中出現(xiàn)?!?我強(qiáng)烈懷疑,大多數(shù)開發(fā)人員(包括我自己)都默認(rèn)認(rèn)為 getSeconds() 方法的返回值范圍是 0-59。
- Date 類的方法對(duì)參數(shù)范圍的要求非常寬松,這沒有明顯的理由。例如,方法允許日期參數(shù)為 1 月 32 日,并解釋為 2 月 1 日。這種寬松的參數(shù)范圍在實(shí)際應(yīng)用中并不常見,反而增加了使用的復(fù)雜性和出錯(cuò)的風(fēng)險(xiǎn)。
盡管還能找到更多的問題,但那會(huì)顯得過于挑剔。