Java Date#compareTo()中遇到的坑

    技术2024-10-21  57

    今天遇到一个日期比较的bug,打断点跟进代码一看之后发现,在比较两个完全一样的日期时,尽然判断不相等。仔细看了下这2个日期后,发现他们一个是正常的date,另一个虽然也是一个date,但是是指向的timestamp。像下面这段代码这样:

    @Test public void dateCompareTest01() throws ParseException { String DateStr = "2020-07-03 23:59:59.999"; Timestamp ts = Timestamp.valueOf(DateStr); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); Date date1 = format.parse(DateStr); Date date2 = ts; System.out.println(date1.compareTo(date2)); }

    我们看看这两个日期长啥样: 可以看到这两个日期的格式不太一样,其根本原因在于一个是正常的date,一个是指向timestamp的date,而date与timestamp的结构又不一样导致的。 在date中,fastTime和cdate都包含有毫秒,而timestamp里,毫秒被拆了出来,用nanos来存,所以fastTime和cdate里都不包含毫秒。

    解决方法:调用getTime()去比较。因为timestamp的getTime()会把毫秒拼接上来

    我们再来了解下Date的compareTo()方法:

    public int compareTo(Date anotherDate) { long thisTime = getMillisOf(this); long anotherTime = getMillisOf(anotherDate); return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1)); }

    getMillisOf()方法:

    static final long getMillisOf(Date date) { /* * 由cdate字段的注解可知: * 1.如果cdate为null时,fastTime精确到毫秒。 * 2.如果isNormalized()为true时,cdate和fastTime同步、保持一致,否则fastTime不生效,用cdate表示时间。 * 所以当cdate为null或者isNormalized()为true时,直接取fastTime就好。 * 关于normalized字段,默认是true,如果有set/add操作的话,就会改为false。 * */ if (date.cdate == null || date.cdate.isNormalized()) { return date.fastTime; } BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone(); return gcal.getTime(d); }

    date1和date2在比较时,会根据cdate和isNormalized()的值来判断用fastTime还是用cdate来比较。但是不管用哪个,比较时都会判断不相等。

    Processed: 0.010, SQL: 9