寫程式碼被大語言模型坑之使用LocalDateTime比較兩個時間差了幾天

五岳發表於2024-10-23

自從去年ChatGPT3.5釋出後使用了幾次,現在寫程式碼基本上離不開它和它的衍生產品們了。一方面查資料很方便,快速提煉要點總結;另一方面想寫什麼樣的程式碼一問就能生成出來,功能大差不差,稍微改改就能用,大大減少使用搜尋引擎的時間,是新時代高階版的Ctrl+C/V。

不過大語言模型歸根揭底是靠訓練集訓練出來的,它給出的程式碼還是要自己測試一下用起來才放心,比如這次就被它坑了一把。

注:因種種原因,本文僅測試了一些國內的大語言模型,沒有測試ChatGPT。

原始需求

某列表查詢功能,入參包含一組起止日期,需要校驗起止日期跨度小於等於200天。

前端傳參現狀

將使用者選擇的起止日期(yyyy-MM-dd)轉換成"yyyy-MM-dd HH:mm:ss"格式的字串,且起始時間是"yyyy-MM-dd 00:00:00",終止時間是"yyyy-MM-dd 23:59:59"。
比如,頁面上選擇從2024-09-01到2024-09-30,實際的入參是"2024-09-01 00:00:00"和"2024-09-30 23:59:59"。而且對於這組引數,時間跨度是30天,也就是說包括首尾的當天。

需求簡化

為了便於測試,我先把時間跨度的要求改為2天,比如"2024-09-01 00:00:00"到"2024-09-02 23:59:59"的時間跨度正好是2天。需求可以簡化為:

String sendDateBegin="2024-09-01 00:00:00"
String sendDateEnd="2024-09-02 23:59:59"
Java程式碼判斷兩個天數是否小於等於2天

kimi給的結果:

程式碼提取出來:

    public static void main(String[] args) {
        String sendDateBegin = "2024-09-01 00:00:00";
        String sendDateEnd = "2024-09-04 23:59:59";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime beginDate = LocalDateTime.parse(sendDateBegin, formatter);
        LocalDateTime endDate = LocalDateTime.parse(sendDateEnd, formatter);

        // 計算時間差
        Duration duration = Duration.between(beginDate, endDate);

        // 獲取天數差
        long daysBetween = duration.toDays();

        // 判斷天數是否小於等於2
        if (daysBetween <= 2) {
            System.out.println("兩個日期之間的天數小於或等於2天。");
        } else {
            System.out.println("兩個日期之間的天數超過2天。");
        }
    }
}

發現問題

使用2024-09-01 00:00:00~2024-09-02 23:59:59這組資料,返回結果如下,看上去一切正常:

換一組輸入2024-09-01 00:00:00~2024-09-03 23:59:59,居然也告訴我小於等於2天,是哪裡出現了問題?

分析

debug一下程式碼,發現duration.toDays()的實際處理方式是:
將兩個時間的秒數差,除以一天包含的秒數(86400),兩個引數都是long型。

那麼在這個例子裡,超過2天但不足3天的資料,由於long的除法,會將小數部分拋棄,再與2比較:2.999≈2,2≤2為true。這就是為什麼看似正確的程式碼實際引入了一個bug。
而且,即使提醒kimi這段程式碼有bug並告知對應的輸入,給出的答案仍然是錯的。

同樣的問題通義千問給了另一種解法,但是答案仍然是錯的:

再看看文心一言,半斤八兩:

解決

既然按天比較因為精度丟失而有誤差,那麼把日期轉成毫秒比較就不會丟失精度了,使用如下的判斷即可。
Duration.between(beginDate, endDate).toMillis() <= Duration.ofDays(2).toMillis();

這個例子生動的展示,寫程式碼不能完全依賴大語言模型,該做的測試還是要做的。當然,如果你把測試用例的編寫工作也交給了大語言模型,或許是能夠測出來bug的,挺諷刺的是不是?

相關文章