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.DateSimpleDateFormat

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)彻底重构了日期处理逻辑:

  • 不可变性:所有类(如 LocalDateLocalDateTime)均为不可变对象,天然线程安全;
  • 语义清晰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 标签库提升代码简洁性,并始终关注线程安全与国际化需求。

实践建议

  1. 在项目中替换所有 DateSimpleDateFormatLocalDateTimeDateTimeFormatter
  2. 使用单元测试验证日期计算逻辑(如节假日、年龄计算);
  3. 通过 JSTL 标签减少脚本片段(Scriptlet)的使用,提升 JSP 可维护性。

掌握 JSP 日期处理的开发者,不仅能解决基础功能需求,更能为复杂业务场景(如订单过期提醒、用户活跃度分析)奠定技术基础。

最新发布