首页 > 其他分享 >为什么现在连Date类都不建议使用了?

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

时间:2024-07-06 12:01:44浏览次数:17  
标签:为什么 建议 java date LocalDateTime Date return public

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

image.png

java.util.DateDate从现在开始)是一个糟糕的类型,这解释了为什么它的大部分内容在 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 日。” 多久有用一次?

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

二、为啥要改?

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

image.png

解决思路:避免使用java.util.Datejava.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()

原来的方式:


Java

复制代码

Date nowDate = new Date(); Date nowCalendarDate = Calendar.getInstance().getTime();

使用 java.time 改造后:


Java

复制代码

// 使用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

原来的方式


typescript

复制代码

public static String dateFormat(Date date, String dateFormat) { SimpleDateFormat formatter = new SimpleDateFormat(dateFormat); return formatter.format(date); }

使用java.time改造后


java

复制代码

public static String dateFormat(LocalDateTime date, String dateFormat) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat); return date.format(formatter); }

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

原来的方式


java

复制代码

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


java

复制代码

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

原来的方式


java

复制代码

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


java

复制代码

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

原来的方式


java

复制代码

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


java

复制代码

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

原来的方式


java

复制代码

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


Java

复制代码

public static Boolean betweenStartAndEnd(Instant nowTime, Instant beginTime, Instant endTime) { return nowTime.isAfter(beginTime) && nowTime.isBefore(endTime); }

我这里就只列了一些,如果有缺失的可以自己补充,不会写的话直接问问ChatGPT,它最会干这事了。最后把这些修改后的方法替换一下就行了。

四、小结一下

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

标签:为什么,建议,java,date,LocalDateTime,Date,return,public
From: https://blog.csdn.net/darker_jack/article/details/140226959

相关文章

  • 奇怪,同样的数据,为什么CAD、SHP、要素类的面积会有所不同
    大家应该经常会遇到这种情况,就是同样一个数据,CAD、SHP、地理数据库要素类的三个面积,竟然是不同的!!!这究竟是为啥呢???我们来分两种情况说一下:1.三类数据面积相差很大,这种时候你就要考虑下图斑的拓扑关系了;2.三类数据面积相差很小,甚至只有个位数或小数点后几位数的不同,这个......
  • string str = “中文lin”不会报错,但为什么还必须使用wstring wstr
    在C++中,字符串字面量"中文lin"默认是窄字符字符串(char类型),而不是宽字符字符串(wchar_t类型)。当你尝试将这个字符串字面量赋值给一个std::string对象时,通常不会直接报错,但前提是源文件(.cpp文件)的编码支持这些字符。如果你的源文件是以UTF-8编码保存的,并且你的编译器(......
  • 引用个数为什么会影响内存泄漏 c++例子
    在C++中,内存泄漏通常与手动管理内存有关,而不是直接由引用计数引起,因为C++标准库本身并不提供自动的引用计数功能。但是,我们可以通过一个例子来间接说明引用(或指针)管理不当如何导致内存泄漏,尤其是当涉及复杂对象结构和所有权关系时,这种管理不当往往体现在循环引用上。基本概念......
  • 字节面试 用double,1.0-0.9的结果不是0.1,为什么?
    让我详细解释一下为什么1.0-0.9在二进制中不能精确表示。1.0的二进制表示1.0在二进制中可以精确表示。它的二进制表示为:1.0=1.0(二进制)0.9的二进制表示0.9是一个无法在二进制中精确表示的小数。二进制小数是通过求和1/2,1/4,1/8,1/16,...等幂次表示的。对......
  • 为什么现在的AI编程师都是用Python来编程?
    前言: 在当今AI大火的时节,涌入了一大批AI编程师,和AI训练师!显而易见他们都是用的Python语言来编程的。当然AI也给我们的工作带来了很多便利,比如AI绘画,写文章,视频剪辑,脚本创做等等方面现在都可以来用AI来协助我高效完成工作。那么我们来看看现在的AI编程师为什么都用Python语言......
  • 养猫必看!猫咪为什么会软便?四款优质主食罐头大推荐
    铲屎官可能都经历过这样一个令人头疼的问题——猫咪软便。在和20多个宠物营养师交流过后,我想和大家分析一下猫咪软便的原因,以及如何能从根源上预防猫咪频繁软便。一.猫咪软便的原因1.寄生虫的侵扰寄生虫,如绦虫、蛔虫等不速之客会破坏肠道环境,导致猫咪消化不良,从而出现软便......
  • BeanUtil复制时,两对象中数据类型不一致导致的问题Can not set java.time.LocalDateTim
    @DatapublicclassAVo{privateLongendTime;privateStringname;privateStringid;}@DatapublicclassABVo{privateLocalDateTimeendTime;privateStringname;privateStringid;}AVoaVo=newAVo();......
  • 为什么我不建议你入行网络安全,因为99.9%的人都绕不过这三个坎
    前言我一个朋友老赵,老赵在一家大型互联网公司做高级网络安全工程师,从实习生到工程师整整呆了六年。去年他们公司为了缩减成本,做了裁员,他也在其中,取而代之的是一个只有三年工作经验的“新人”…老赵想着,自己也有多年工作经验,找工作应该不难,结果这几个月却屡次碰壁,这让老......
  • 阿里Qwen2-72B大模型已是开源榜的王者,为什么还要推出其他参数模型,被其他模型打榜?
    6月27日,全球知名的开源平台HuggingFace的联合创始人兼首席执行官Clem在社交平台激动宣布,阿里Qwen2-72B成为了开源模型排行榜的王者。这是一件大好事,说明了我们在大模型领域从先前的追赶,逐渐走向了领导,未来完全有可能会引领着全球开源模型的发展潮流,这是我们的骄傲!不......
  • Select xxx for update
    一.Mysql数据库的RR隔离级别下,如果在事务中使用SELECT...FORUPDATE,实现如下伪代码所描述的效果:“begintransactionselectidfromtwherestatus=falselimit1,1;ifselectresultisnotempty;thenupdatestatus=truewhereid=;commit;“那么能......