JSP+Servlet+MySQL项目日期存入数据库少一天问题求助
核心错误点
时区设置未作用于实际执行更新的数据库连接
你编写的时区设置代码是单独获取一个连接执行SET time_zone,但实际执行update操作的是另一个新获取的连接,该连接并未应用时区设置,等于无效操作。日期转换冗余且未指定时区
你用SimpleDateFormat解析日期再转java.sql.Date的步骤完全多余,且SimpleDateFormat默认使用JVM时区,解析时可能引入偏移;另外java.sql.Date.valueOf()可直接接收yyyy-MM-dd格式的字符串,无需经过util.Date中转。setDate方法未明确指定时区PreparedStatement.setDate(int, java.sql.Date)默认使用JVM时区将日期转换为数据库存储格式,当JVM时区与MySQL的SYSTEM时区存在偏移时,日期会被转成UTC后存储,进而出现日期提前一天的情况。
具体修复步骤
1. 简化日期转换代码(Servlet中)
将Servlet里的日期转换逻辑替换为:
String date_start = request.getParameter("start_date"); java.sql.Date start_date = null; if(date_start != null && !date_start.isEmpty()){ // 直接用valueOf转换,避免时区问题 start_date = java.sql.Date.valueOf(date_start); }
java.sql.Date.valueOf()会严格按yyyy-MM-dd格式解析,不会引入时区偏移,默认将字符串当作本地日期直接转为对应的sql.Date对象。
2. 确保时区设置作用于执行更新的连接
方案一:在JDBC URL中指定时区(推荐)
修改数据库连接URL,添加时区参数,比如你的JVM时区是东八区(UTC+8):
jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
所有通过该URL获取的连接都会自动使用指定时区,无需每次连接后手动执行SET time_zone。
方案二:在获取连接后立即设置时区(若无法修改URL)
在dbUtil类中,获取连接后先执行时区设置,再执行update:
conn = dataSource.getConnection(); // 先设置时区,比如东八区 conn.createStatement().execute("SET time_zone = '+08:00'"); // 再执行后续的update操作 String sql = "update course_progress set start_date = ?, lecture_count = ? where course_id = ?"; stmt = conn.prepareStatement(sql); stmt.setDate(1, start_date); // ...其他参数设置 stmt.execute();
3. 显式指定setDate的时区(可选,双重保障)
若上述步骤未解决问题,可在调用setDate时显式指定时区,确保转换时使用正确时区:
// 指定东八区 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai")); stmt.setDate(1, start_date, cal);
验证方法
- 在MySQL中执行
SELECT @@time_zone;,查看当前连接的时区,确认与JVM时区一致。 - 手动执行
INSERT INTO course_progress(start_date) VALUES('2023-06-20');,查看数据库中存储的日期是否正确,排除数据库本身的问题。
内容的提问来源于stack exchange,提问作者bear bear

