JSP 日期处理(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
在 Web 开发中,日期处理是一项高频且复杂的任务。无论是用户注册时记录创建时间、电商系统中商品的保质期管理,还是数据分析时的统计周期划分,日期操作都扮演着关键角色。对于使用 JSP(JavaServer Pages)技术栈的开发者而言,掌握日期处理的核心方法与最佳实践,能够显著提升代码的健壮性和可维护性。
本文将从 Java 基础到 JSP 特性,系统性地讲解如何在 JSP 环境中实现日期的获取、格式化、计算与验证。通过实际案例与代码示例,帮助读者快速上手并解决常见问题,尤其适合编程初学者与中级开发者进阶学习。
一、Java 日期处理基础:从旧 API 到现代 API 的演变
1.1 Java 旧日期 API(java.util.Date
和 SimpleDateFormat
)
Java 的旧日期 API 存在诸多设计缺陷,例如:
Date
类本身同时包含日期和时间,且缺乏清晰的语义;SimpleDateFormat
不是线程安全的,直接使用可能导致并发问题;- 缺乏对时区、日期计算等高级功能的支持。
比喻说明:
可以将旧 API 比作一辆老式自行车——虽然能完成基础任务(如日期存储),但面对复杂路况(如跨时区计算)时,容易出现链条脱落(线程安全问题)或方向失控(格式混乱)。
// 示例:旧 API 格式化日期
Date currentDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(currentDate);
1.2 现代日期 API(java.time
包)
Java 8 引入的 java.time
包(JSR-310)彻底重构了日期处理逻辑:
- 不可变性:所有类(如
LocalDate
、LocalDateTime
)均为不可变对象,天然线程安全; - 语义清晰:
LocalDate
仅处理日期,LocalTime
仅处理时间,LocalDateTime
组合两者; - 丰富功能:支持时区转换、日期计算(如加减天数)、ISO 标准化操作等。
代码示例:
LocalDateTime now = LocalDateTime.now();
LocalDate tomorrow = now.plusDays(1).toLocalDate();
LocalDateTime specificTime = now.withHour(12).withMinute(0);
二、JSP 中日期处理的核心场景与实现方法
2.1 在 JSP 中获取当前时间
通过 EL 表达式或内置对象 pageContext
,可直接访问 Java 系统时间:
<!-- 方式1:通过 EL 表达式调用静态方法 -->
当前时间(旧 API):${java.util.Calendar.instance.time}
<!-- 方式2:通过 pageContext 获取 Java 对象 -->
<%
pageContext.setAttribute("now", LocalDateTime.now());
%>
当前时间(新 API):${now}
2.2 日期格式化:从对象到字符串的转换
2.2.1 使用 SimpleDateFormat
(旧 API)
<%
Date currentDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String formattedDate = sdf.format(currentDate);
pageContext.setAttribute("formattedDate", formattedDate);
%>
格式化后的日期:${formattedDate}
2.2.2 使用 DateTimeFormatter
(新 API)
<%
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedNow = now.format(formatter);
pageContext.setAttribute("formattedNow", formattedNow);
%>
格式化后的日期(新 API):${formattedNow}
2.3 JSP 表单中日期的提交与验证
在 Web 表单中,用户输入的日期字符串需要转换为 Java 对象,同时需处理格式错误或无效日期:
表单页面(dateForm.jsp):
<form action="processDate.jsp" method="post">
请输入日期(格式:yyyy-MM-dd):
<input type="text" name="userDate" required>
<input type="submit" value="提交">
</form>
处理页面(processDate.jsp):
<%
String inputDateStr = request.getParameter("userDate");
LocalDate userDate = null;
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
userDate = LocalDate.parse(inputDateStr, formatter);
} catch (DateTimeParseException e) {
out.println("日期格式错误,请使用 yyyy-MM-dd 格式");
}
%>
<% if (userDate != null) { %>
用户输入的日期是:${userDate}
<% } %>
三、JSP 中的日期计算与业务场景应用
3.1 计算日期间隔:如剩余天数、年龄计算
<%
// 计算当前到用户生日的剩余天数
String birthStr = "1990-05-20";
LocalDate birth = LocalDate.parse(birthStr);
LocalDate now = LocalDate.now();
Period period = Period.between(birth, now);
int age = period.getYears();
int daysToBirthday = (
birth.getMonthValue() > now.getMonthValue()
|| (birth.getMonthValue() == now.getMonthValue() && birth.getDayOfMonth() > now.getDayOfMonth())
)
? birth.withYear(now.getYear()).toLocalDate().minusDays(now.toLocalDate().toEpochDay())
: birth.withYear(now.getYear()+1).toLocalDate().minusDays(now.toLocalDate().toEpochDay());
%>
<p>年龄:${age} 岁</p>
<p>距离下一次生日剩余:${daysToBirthday} 天</p>
3.2 时区处理:应对全球化需求
<%
ZonedDateTime beijingTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime londonTime = beijingTime.withZoneSameInstant(ZoneId.of("Europe/London"));
%>
<p>北京时间:${beijingTime}</p>
<p>伦敦时间:${londonTime}</p>
四、常见问题与最佳实践
4.1 线程安全与 SimpleDateFormat
的使用
由于 SimpleDateFormat
非线程安全,直接在 JSP 中重复使用可能导致数据污染。解决方案:
- 在方法内局部变量中创建
SimpleDateFormat
; - 或改用
DateTimeFormatter
(线程安全)。
4.2 日期格式化与国际化(I18N)
通过 Locale
参数支持多语言日期显示:
<%
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.CHINA); // 中文格式:2023年10月23日 下午3时25分30秒
String formattedDate = now.format(formatter);
%>
<p>当前日期(中文):${formattedDate}</p>
五、进阶技巧:结合 JSTL 标签库简化代码
JSTL(JSP Standard Tag Library)提供了 <fmt>
标签简化日期处理:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%
pageContext.setAttribute("dateObj", LocalDateTime.now());
%>
<fmt:formatDate value="${dateObj}" pattern="yyyy-MM-dd"/>
<fmt:formatDate value="${dateObj}" type="both" dateStyle="long" timeStyle="medium"/>
通过本文的学习,读者应能掌握 JSP 环境中日期处理的完整流程:从基础的日期获取与格式化,到复杂的时区转换与业务场景应用。建议优先采用 java.time
包的现代 API,结合 JSTL 标签库提升代码简洁性,并始终关注线程安全与国际化需求。
实践建议:
- 在项目中替换所有
Date
与SimpleDateFormat
为LocalDateTime
与DateTimeFormatter
; - 使用单元测试验证日期计算逻辑(如节假日、年龄计算);
- 通过 JSTL 标签减少脚本片段(Scriptlet)的使用,提升 JSP 可维护性。
掌握 JSP 日期处理的开发者,不仅能解决基础功能需求,更能为复杂业务场景(如订单过期提醒、用户活跃度分析)奠定技术基础。