为什么现在Java连Date类都不建议使用了?
Java专栏
共 12097字,需浏览 25分钟
·
2024-04-20 12:20
有什么问题吗java.util.Date
?
java.util.Date
(Date
从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。
-
它的名称具有误导性:它并不代表 a Date
,而是代表时间的一个瞬间。所以它应该被称为Instant
——正如它的java.time
等价物一样。 -
它是非最终的:这鼓励了对继承的不良使用,例如 java.sql.Date
(这意味着代表一个日期,并且由于具有相同的短名称而也令人困惑) -
它是可变的:日期/时间类型是自然值,可以通过不可变类型有效地建模。可变的事实 Date
(例如通过setTime
方法)意味着勤奋的开发人员最终会在各处创建防御性副本。 -
它在许多地方(包括)隐式使用系统本地时区, toString()
这让许多开发人员感到困惑。有关此内容的更多信息,请参阅“什么是即时”部分 -
它的月份编号是从 0 开始的,是从 C 语言复制的。这导致了很多很多相差一的错误。 -
它的年份编号是基于 1900 年的,也是从 C 语言复制的。当然,当 Java 出现时,我们已经意识到这不利于可读性? -
它的方法命名不明确: getDate()
返回月份中的某一天,并getDay()
返回星期几。给这些更具描述性的名字有多难? -
对于是否支持闰秒含糊其辞:“秒由 0 到 61 之间的整数表示;值 60 和 61 仅在闰秒时出现,即使如此,也仅在实际正确跟踪闰秒的 Java 实现中出现。” 我强烈怀疑大多数开发人员(包括我自己)都做了很多假设,认为 for 的范围 getSeconds()
实际上在 0-59 范围内(含)。 -
它的宽容没有明显的理由:“在所有情况下,为这些目的而对方法给出的论据不必落在指定的范围内; 例如,日期可以指定为 1 月 32 日,并被解释为 2 月 1 日。” 多久有用一次?
https://t.zsxq.com/18HLAb2hI
。
为啥要改?
解决思路:避免使用 java.util.Date
与java.sql.Date
类和其提供的API,考虑使用java.time.Instant
类或java.time.LocalDateTime
类及其提供的API替代。
怎么改?
确定字段类型
Date
字段代表的是日期、时间还是时间戳。
-
如果字段代表日期和时间,则可能需要使用 LocalDateTime
。 -
如果字段仅代表日期,则可能需要使用 LocalDate
。 -
如果字段仅代表时间,则可能需要使用 LocalTime
。 -
如果字段需要保存时间戳(带时区的),则可能需要使用 Instant
或ZonedDateTime
。
更新数据对象类
Date
类型改为适当的 java.time
类型。
将DateUtil中的方法改造
替换不建议使用的 API
Date nowDate = new Date();
Date nowCalendarDate = Calendar.getInstance().getTime();
java.time
改造后:
// 使用Instant代表一个时间点,这与Date类似
Instant nowInstant = Instant.now();
// 如果需要用到具体的日期和时间(例如年、月、日、时、分、秒)
LocalDateTime nowLocalDateTime = LocalDateTime.now();
// 如果你需要和特定的时区交互,可以使用ZonedDateTime
ZonedDateTime nowZonedDateTime = ZonedDateTime.now();
// 如果你需要转换回java.util.Date,你可以这样做(假设你的代码其他部分还需要使用Date)
Date nowFromDateInstant = Date.from(nowInstant);
// 如果需要与java.sql.Timestamp交互
java.sql.Timestamp nowFromInstant = java.sql.Timestamp.from(nowInstant);
-
Instant
表示的是一个时间点,它是时区无关的,相当于旧的Date
类。它通常用于表示时间戳。 -
LocalDateTime
表示没有时区信息的日期和时间,它不能直接转换为时间戳,除非你将其与时区结合使用(例如通过ZonedDateTime
)。 -
ZonedDateTime
包含时区信息的日期和时间,它更类似于Calendar
,因为Calendar
也包含时区信息。 -
当你需要将 java.time
对象转换回java.util.Date
对象时,可以使用Date.from(Instant)
方法。这在你的代码需要与旧的API或库交互时非常有用。
dateFormat
public static String dateFormat(Date date, String dateFormat) {
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
return formatter.format(date);
}
java.time
改造后
public static String dateFormat(LocalDateTime date, String dateFormat) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
return date.format(formatter);
}
add相关方法
public static Date addSecond(Date date, int second) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(13, second);
return calendar.getTime();
}
public static Date addMinute(Date date, int minute) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(12, minute);
return calendar.getTime();
}
public static Date addHour(Date date, int hour) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(10, hour);
return calendar.getTime();
}
public static Date addDay(Date date, int day) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(5, day);
return calendar.getTime();
}
public static Date addMonth(Date date, int month) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(2, month);
return calendar.getTime();
}
public static Date addYear(Date date, int year) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(1, year);
return calendar.getTime();
}
java.time
改造后
public static LocalDateTime addSecond(LocalDateTime date, int second) {
return date.plusSeconds(second);
}
public static LocalDateTime addMinute(LocalDateTime date, int minute) {
return date.plusMinutes(minute);
}
public static LocalDateTime addHour(LocalDateTime date, int hour) {
return date.plusHours(hour);
}
public static LocalDateTime addDay(LocalDateTime date, int day) {
return date.plusDays(day);
}
public static LocalDateTime addMonth(LocalDateTime date, int month) {
return date.plusMonths(month);
}
public static LocalDateTime addYear(LocalDateTime date, int year) {
return date.plusYears(year);
}
dateToWeek
public static final String[] WEEK_DAY_OF_CHINESE = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
public static String dateToWeek(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return WEEK_DAY_OF_CHINESE[cal.get(7) - 1];
}
java.time
改造后
public static final String[] WEEK_DAY_OF_CHINESE = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
public static String dateToWeek(LocalDate date) {
DayOfWeek dayOfWeek = date.getDayOfWeek();
return WEEK_DAY_OF_CHINESE[dayOfWeek.getValue() % 7];
}
getStartOfDay和getEndOfDay
public static Date getStartTimeOfDay(Date date) {
if (date == null) {
return null;
} else {
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
}
}
public static Date getEndTimeOfDay(Date date) {
if (date == null) {
return null;
} else {
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
}
}
java.time
改造后
public static LocalDateTime getStartTimeOfDay(LocalDateTime date) {
if (date == null) {
return null;
} else {
// 获取一天的开始时间,即00:00
return date.toLocalDate().atStartOfDay();
}
}
public static LocalDateTime getEndTimeOfDay(LocalDateTime date) {
if (date == null) {
return null;
} else {
// 获取一天的结束时间,即23:59:59.999999999
return date.toLocalDate().atTime(LocalTime.MAX);
}
}
betweenStartAndEnd
public static Boolean betweenStartAndEnd(Date nowTime, Date beginTime, Date endTime) {
Calendar date = Calendar.getInstance();
date.setTime(nowTime);
Calendar begin = Calendar.getInstance();
begin.setTime(beginTime);
Calendar end = Calendar.getInstance();
end.setTime(endTime);
return date.after(begin) && date.before(end);
}
java.time
改造后
public static Boolean betweenStartAndEnd(Instant nowTime, Instant beginTime, Instant endTime) {
return nowTime.isAfter(beginTime) && nowTime.isBefore(endTime);
}
我这里就只列了一些,如果有缺失的可以自己补充,不会写的话直接问问 ChatGPT,它最会干这事了。最后把这些修改后的方法替换一下就行了。
总结
评论