专栏名称: Java知音
专注于Java,推送技术文章,热门开源项目等。致力打造一个有实用,有情怀的Java技术公众号!
目录
相关文章推荐
独角兽智库  ·  中期震荡上行,留意结构交易过热 ·  2 天前  
辽宁发布  ·  新闻发布会丨2024年全省经济运行情况及20 ... ·  2 天前  
辽宁发布  ·  新闻发布会丨2024年全省经济运行情况及20 ... ·  2 天前  
济南都市频道  ·  女子酒店泡澡遭无人机偷拍?刚刚,三亚警方通报 ·  3 天前  
济南都市频道  ·  女子酒店泡澡遭无人机偷拍?刚刚,三亚警方通报 ·  3 天前  
51好读  ›  专栏  ›  Java知音

公司空降一个 CTO:禁止在项目中使用 Date 类,发现立即走人!!!

Java知音  · 公众号  ·  · 2024-05-11 10:05

正文

戳上方蓝字“ Java知音 ”关注我

一、java.util.Date有什么问题吗?

java.util.Date (Date从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 Java 1.1 中被弃用(但不幸的是仍在使用)。

设计缺陷包括:

  • 它的名称具有误导性: 它并不代表一个日期,而是代表时间的一个瞬间。所以它应该被称为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 日。” 多久有用一次?

关键原因如下:

原文如下:为什么要避免使用Date类?

https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/

二、为啥要改?

我们要改的原因很简单,我们的代码缺陷扫描规则认为这是一个必须修改的缺陷,否则不给发布,不改不行,服了。

解决思路:避免使用 java.util.Date java.sql.Date 类和其提供的API,考虑使用 java.time.Instant 类或 java.time.LocalDateTime 类及其提供的API替代。

三、怎么改?

只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。

由于我们还是微服务架构,业务服务依赖于基础服务的API,所以必须要一起改否则就会报错。这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。

1. 耐心比对数据库日期字段和DO的映射

1)确定字段类型

首先你需要确定数据对象中的 Date 字段代表的是日期、时间还是时间戳。

  • 如果字段代表日期和时间,则可能需要使用 LocalDateTime。

  • 如果字段仅代表日期,则可能需要使用 LocalDate。

  • 如果字段仅代表时间,则可能需要使用 LocalTime。

  • 如果字段需要保存时间戳(带时区的),则可能需要使用 Instant 或 ZonedDateTime。

2)更新数据对象类

更新数据对象类中的字段,把 Date 类型改为适当的 java.time 类型。

2. 将DateUtil中的方法改造

1)替换原来的new Date()和Calendar.getInstance().getTime()

原来的方式:

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或库交互时非常有用。

2)一些基础的方法改造

a. 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);  
}  

b. addSecond、addMinute、addHour、addDay、addMonth、addYear

原来的方式

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);  
}  

c. 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 改造后







请到「今天看啥」查看全文