遵循正确格式时SimpleDateFormat仍抛出ParseException的原因?
解决JSP/Servlet中日期解析的ParseException问题
嘿,我来帮你排查这个头疼的ParseException问题!虽然看起来格式完全符合yyyy-MM-dd,但还是有几个容易忽略的点会导致解析失败,咱们一步步来分析:
最可能的原因:日期字符串有隐藏问题
你打印出来的是2018-05-24,但实际传过来的字符串可能藏着看不见的“小尾巴”或者特殊字符:
- 前后有空格/制表符:前端表单提交时可能不小心带了空格,比如实际字符串是
" 2018-05-24"或者"2018-05-24 ",肉眼打印看不出来,但解析时会失败。 - 全角横杠替代半角:有时候输入的横杠是全角的
-(中文输入法下的减号),而不是半角的-,格式字符串里的是半角,自然匹配不上。
解决方案:先清洗字符串
在解析前先对字符串做预处理,同时打印带边界标记的内容,方便排查:
String dateStr = p.getFromDate(); // 先判断是否为空 if (dateStr == null || dateStr.trim().isEmpty()) { // 处理空值情况,比如抛错或设默认值 throw new IllegalArgumentException("日期参数不能为空"); } // 去除前后空格,替换全角横杠为半角 dateStr = dateStr.trim().replace('-', '-'); // 用方括号包裹打印,看是否有隐藏字符 System.out.println("待解析的日期字符串:[" + dateStr + "]"); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); java.util.Date ufromdate = sdf1.parse(dateStr);
第二个可能:SimpleDateFormat的线程安全问题
如果你的SimpleDateFormat是定义为静态变量(比如在类级别声明private static SimpleDateFormat sdf1 = ...),那在Servlet这种多线程环境下,多个请求同时调用parse方法会破坏它的内部状态,导致随机的ParseException。
解决方案:避免静态实例
要么每次使用都新建一个SimpleDateFormat实例(就像你现在代码里做的那样,这是安全的),要么用ThreadLocal给每个线程分配独立的实例:
private static ThreadLocal<SimpleDateFormat> sdfThreadLocal = ThreadLocal.withInitial( () -> new SimpleDateFormat("yyyy-MM-dd") ); // 使用时 SimpleDateFormat sdf1 = sdfThreadLocal.get(); java.util.Date ufromdate = sdf1.parse(dateStr);
第三个可能:Locale本地化影响
某些默认Locale会影响日期解析逻辑,比如中文Locale下,可能对格式的解析有细微差异。可以强制指定美式Locale来避免:
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
更推荐的替代方案:用Java 8+新日期API
如果你的项目用的是Java 8及以上,强烈建议换成java.time包下的日期类,它天生线程安全,而且解析yyyy-MM-dd这种ISO标准格式不需要手动指定格式,代码更简洁:
String dateStr = p.getFromDate().trim(); // 直接解析ISO格式的日期字符串 LocalDate localDate = LocalDate.parse(dateStr); // 转换为sql.Date java.sql.Date sqlfromdate = java.sql.Date.valueOf(localDate); ps.setDate(5, sqlfromdate);
如果格式不对,它会抛出DateTimeParseException,异常信息会更明确地告诉你哪里出了问题。
内容的提问来源于stack exchange,提问作者HayreFkru
相关产品推荐
相关产品推荐

