读书@IT·互联网

为什么现在连Date类都不建议使用了?

2024-04-23  本文已影响0人  sum墨

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

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

设计缺陷包括:

关键原因如下:

image.png

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

二、为啥要改?

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


image.png

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

三、怎么改?

只能说这种基础的类改起来牵一发动全身,需要从DO实体类看起,然后就是各种Converter,最后是DTO。由于我们还是微服务架构,业务服务依赖于基础服务的API,所以必须要一起改否则就会报错。这里就不细说修改流程了,主要说一下我们在改造的时候遇到的一些问题。

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

(1)确定字段类型

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

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

一些注意点:

  1. Instant 表示的是一个时间点,它是时区无关的,相当于旧的 Date 类。它通常用于表示时间戳。
  2. LocalDateTime 表示没有时区信息的日期和时间,它不能直接转换为时间戳,除非你将其与时区结合使用(例如通过 ZonedDateTime)。
  3. ZonedDateTime 包含时区信息的日期和时间,它更类似于 Calendar,因为 Calendar 也包含时区信息。
  4. 当你需要将 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改造后

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

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

e. 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,它最会干这事了。最后把这些修改后的方法替换一下就行了。

四、小结一下

这个改造难度不高,但是复杂度非常高,一个地方没改好,轻则接口报错,重则启动失败,非常耗费精力,真不想改。

上一篇下一篇

猜你喜欢

热点阅读