惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
云风的 BLOG
云风的 BLOG
罗磊的独立博客
C
Check Point Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Blog — PlanetScale
Blog — PlanetScale
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
宝玉的分享
宝玉的分享
Recent Announcements
Recent Announcements
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
I
InfoQ
Hugging Face - Blog
Hugging Face - Blog
T
Tailwind CSS Blog
B
Blog RSS Feed

博客园 - 五岳

JDK中使用的设计模式 Java的List.sort()排序方法源码理解 Cloud Agent 开发笔记(4):Skill 与 MCP 集成、项目后记 Cloud Agent 开发笔记(3):Web 交互与数据持久化 Cloud Agent 开发笔记(2):Agent 引擎与 Tool 体系 Cloud Agent 开发笔记(1):V1从跑通到放弃 单点登录系统思维导图与资料收集 阿里云DTS按业务场景批量迁移RDS MySQL表实战(下):迁移管理平台设计与实现 阿里云DTS按业务场景批量迁移RDS MySQL表实战(上):技术选型和API对接 分库分表数据源ShardingSphereDataSource的Connection元数据误用问题分析 Web层接口通用鉴权注解实践(基于JDK8) Feign框架中一处编码不合理导致的异常 解决Dify的Ollama插件添加模型时保存成功但模型为空的问题 深入研究使用DozerMapper复制List<Ojbect>前后元素类型不一致的问题 mybatis-config的mapUnderscoreToCamelCase配置生效方式和基本原理 封装CompletionService的并发任务分发器(优化版) 深入理解Mybatis分库分表执行原理 系统设计:消灭慢接口 使用LinkedList实现队列和栈 Collectors.toMap的暗坑与避免方式 如丝般顺滑:DDD再实践之类目树管理 阿里云数仓Dataworks数据导出到文件step by step DDD实践反思 LeetCode组合总和I~IV和背包问题小结 Akka学习笔记
写代码被大语言模型坑之使用LocalDateTime比较两个时间差了几天
五岳 · 2024-10-23 · via 博客园 - 五岳

自从去年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的,挺讽刺的是不是?