深入掌握 Java 日期时间 API:从基础使用到高级实战(全解析)

在 Java 开发中,日期时间处理是必备核心技能,但早期的java.util.Datejava.util.Calendar存在线程不安全、设计混乱、API 难用等痛点,极易引发生产 bug。
Java 8 正式推出了全新的日期时间 API(java.time 包),遵循 ISO-8601 标准,线程安全、设计清晰、功能强大,彻底解决了旧 API 的弊端。
本文将从基础概念、核心类使用、格式化解析、日期计算、时区处理、新旧 API 转换六大维度,带你彻底吃透 Java 日期时间 API,轻松应对所有开发场景。

一、旧日期 API 的痛点(为什么要弃用 Date/Calendar)

在学习新 API 之前,先了解旧 API 的缺陷,才能明白新 API 的设计优势:
  1. 线程不安全DateCalendarSimpleDateFormat都是可变类,多线程环境下使用会引发数据错乱、格式化异常。
  2. 设计混乱:月份从 0 开始(1 月 = 0)、年份从 1900 开始,API 命名不规范,可读性极差。
  3. 功能缺失:缺乏对日期时间的精细化操作(如计算两个日期相差天数、获取下周几),代码冗余。
  4. 时区支持差:时区处理繁琐,容易出错。
反例(旧 API 坑点)
java
运行
// 旧API创建2026年3月20日,月份必须写2(0=1月)
Date date = new Date(2026-1900, 2, 20); 
// SimpleDateFormat多线程下直接报错
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
正是这些缺陷,Java 8 推出了不可变、线程安全、语义清晰java.time核心 API。

二、Java 8+ 日期时间 API 核心类概览

新 API 所有类都在java.time包下,核心类全是不可变类(final 修饰),线程安全,分工明确:
表格
类名 作用 格式示例
LocalDate 本地日期(年月日) 2026-03-20
LocalTime 本地时间(时分秒毫秒) 15:30:25.123
LocalDateTime 本地日期时间(年月日时分秒) 2026-03-20T15:30:25
ZonedDateTime 带时区的日期时间 2026-03-20T15:30:25+08:00[Asia/Shanghai]
Instant 时间戳(UTC 时间戳) 1742446225123
Duration 时间间隔(时分秒毫秒) 2 天 3 小时 15 分钟
Period 日期间隔(年月日) 1 年 2 个月 3 天
DateTimeFormatter 日期格式化 / 解析(线程安全) yyyy-MM-dd HH:mm:ss

三、核心 API 基础使用(必学)

1. LocalDate:本地日期(仅年月日)

LocalDate表示不带时区的本地日期,适用于生日、节假日、合同日期等场景。
java
运行
import java.time.LocalDate;

public class LocalDateDemo {
    public static void main(String[] args) {
        // 1. 获取当前日期(系统默认时区)
        LocalDate now = LocalDate.now();
        System.out.println("当前日期:" + now);

        // 2. 指定日期(年、月、日),月份直接写数字,无需减1
        LocalDate指定日期 = LocalDate.of(2026, 3, 20);
        System.out.println("指定日期:" + 指定日期);

        // 3. 获取日期的年、月、日、星期
        int year = now.getYear(); // 年
        int month = now.getMonthValue(); // 月
        int day = now.getDayOfMonth(); // 日
        // 星期:MONDAY、TUESDAY...SUNDAY
        String week = now.getDayOfWeek().toString(); 

        // 4. 日期判断:是否闰年、是否在指定日期之前/之后
        boolean isLeapYear = now.isLeapYear(); // 是否闰年
        boolean isBefore = now.isBefore(LocalDate.of(2025, 1, 1));
    }
}

2. LocalTime:本地时间(仅时分秒)

LocalTime表示不带时区的本地时间,精确到纳秒,适用于打卡时间、定时任务等场景。
java
运行
import java.time.LocalTime;

public class LocalTimeDemo {
    public static void main(String[] args) {
        // 1. 获取当前时间
        LocalTime now = LocalTime.now();
        System.out.println("当前时间:" + now);

        // 2. 指定时间(时、分、秒、纳秒)
        LocalTime 指定时间 = LocalTime.of(15, 30, 25);
        System.out.println("指定时间:" + 指定时间);

        // 3. 获取时间的时、分、秒
        int hour = now.getHour();
        int minute = now.getMinute();
        int second = now.getSecond();
    }
}

3. LocalDateTime:本地日期时间(最常用)

LocalDateTime = LocalDate + LocalTime,是开发中最常用的类,表示不带时区的日期时间。
java
运行
import java.time.LocalDateTime;

public class LocalDateTimeDemo {
    public static void main(String[] args) {
        // 1. 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前日期时间:" + now);

        // 2. 指定日期时间
        LocalDateTime 指定时间 = LocalDateTime.of(2026, 3, 20, 15, 30, 25);
        System.out.println("指定日期时间:" + 指定时间);

        // 3. 拆分:转LocalDate / LocalTime
        LocalDate date = now.toLocalDate();
        LocalTime time = now.toLocalTime();
    }
}

4. Instant:时间戳(UTC 标准)

InstantUTC 时区的时间戳,对应旧 API 的System.currentTimeMillis(),适用于日志记录、分布式系统时间统一。
java
运行
import java.time.Instant;

public class InstantDemo {
    public static void main(String[] args) {
        // 1. 获取当前时间戳(UTC时间)
        Instant now = Instant.now();
        System.out.println("当前UTC时间戳:" + now);

        // 2. 转毫秒值(等价于System.currentTimeMillis())
        long milli = now.toEpochMilli();
        System.out.println("毫秒值:" + milli);

        // 3. 毫秒值转Instant
        Instant ofEpochMilli = Instant.ofEpochMilli(milli);
    }
}

四、日期格式化与解析(DateTimeFormatter)

旧 API 的SimpleDateFormat线程不安全,新 API 的DateTimeFormatter不可变、线程安全,直接在多线程中使用。

1. 日期格式化(LocalDateTime → String)

java
运行
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class FormatDemo {
    public static void main(String[] args) {
        // 1. 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();

        // 2. 创建格式化器(常用格式:yyyy-MM-dd HH:mm:ss)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 3. 格式化:日期 → 字符串
        String formatTime = now.format(formatter);
        System.out.println("格式化后:" + formatTime);
    }
}

2. 日期解析(String → LocalDateTime)

java
运行
public class ParseDemo {
    public static void main(String[] args) {
        // 待解析的字符串
        String timeStr = "2026-03-20 15:30:25";
        // 格式化器(必须与字符串格式一致)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        
        // 解析:字符串 → 日期时间
        LocalDateTime parseTime = LocalDateTime.parse(timeStr, formatter);
        System.out.println("解析后:" + parseTime);
    }
}

常用格式化模板

表格
模板 含义 示例输出
yyyy-MM-dd 年月日 2026-03-20
yyyy-MM-dd HH:mm:ss 年月日时分秒 2026-03-20 15:30:25
yyyy/MM/dd HH:mm 年月日时分(斜杠) 2026/03/20 15:30
E 星期 星期五

五、日期时间计算(加减、比较、间隔)

新 API 提供了极简的日期计算方法,无需手动处理闰年、大小月,一行代码搞定。

1. 日期加减(plus /minus)

java
运行
LocalDateTime now = LocalDateTime.now();

// 加1天
LocalDateTime plusDays = now.plusDays(1);
// 减2小时
LocalDateTime minusHours = now.minusHours(2);
// 加1个月
LocalDateTime plusMonths = now.plusMonths(1);
// 加1年
LocalDateTime plusYears = now.plusYears(1);

2. 日期比较(isBefore /isAfter/isEqual)

java
运行
LocalDate date1 = LocalDate.of(2026, 3, 20);
LocalDate date2 = LocalDate.of(2025, 12, 31);

// date1是否在date2之前
boolean before = date1.isBefore(date2); 
// date1是否在date2之后
boolean after = date1.isAfter(date2);  
// 日期是否相等
boolean equal = date1.isEqual(date2);  

3. 时间间隔计算(Duration / Period)

  • Period:计算年月日间隔(适用于 LocalDate)
  • Duration:计算时分秒毫秒间隔(适用于 LocalTime/LocalDateTime)
java
运行
import java.time.Duration;
import java.time.Period;

public class IntervalDemo {
    public static void main(String[] args) {
        // 1. 日期间隔(年月日)
        LocalDate startDate = LocalDate.of(2025, 1, 1);
        LocalDate endDate = LocalDate.of(2026, 3, 20);
        Period period = Period.between(startDate, endDate);
        System.out.println("间隔:" + period.getYears() + "年" + period.getMonths() + "月" + period.getDays() + "日");

        // 2. 时间间隔(时分秒)
        LocalTime startTime = LocalTime.of(10, 0, 0);
        LocalTime endTime = LocalTime.of(15, 30, 0);
        Duration duration = Duration.between(startTime, endTime);
        System.out.println("间隔小时:" + duration.toHours()); // 5小时
        System.out.println("间隔分钟:" + duration.toMinutes()); // 330分钟
    }
}

六、时区处理(ZonedDateTime)

ZonedDateTime带时区的日期时间,适用于跨境电商、国际业务、跨时区系统对接。

1. 常用时区 ID

  • 亚洲 / 上海:Asia/Shanghai(东八区,北京时间)
  • 美国纽约:America/New_York
  • 英国伦敦:Europe/London

2. 时区使用示例

java
运行
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDemo {
    public static void main(String[] args) {
        // 1. 获取当前时区的日期时间
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println("当前时区时间:" + now);

        // 2. 指定时区(北京时间)
        ZonedDateTime 北京时间 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println("北京时间:" + 北京时间);

        // 3. 时区转换(纽约时间 → 北京时间)
        ZonedDateTime 纽约时间 = ZonedDateTime.now(ZoneId.of("America/New_York"));
        ZonedDateTime 转换北京时间 = 纽约时间.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
    }
}

七、新旧日期 API 转换(兼容旧项目)

实际开发中,难免需要与旧 API(Date、Calendar)转换,新 API 提供了便捷的转换方法:
表格
新 API 转换为旧 API 旧 API 转新 API
LocalDateTime ↔ Date Date → Instant → LocalDateTime
Instant ↔ Date Date → Instant
ZonedDateTime ↔ GregorianCalendar Calendar → ZonedDateTime

核心转换代码

java
运行
import java.util.Date;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

public class ConvertDemo {
    public static void main(String[] args) {
        // 1. Date → LocalDateTime
        Date date = new Date();
        LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

        // 2. LocalDateTime → Date
        LocalDateTime now = LocalDateTime.now();
        Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
        Date newDate = Date.from(instant);
    }
}

八、实战:开发中常用工具类(直接复制使用)

封装日常开发最常用的日期工具方法,线程安全、开箱即用
java
运行
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 日期时间工具类(Java 8+ 线程安全)
 */
public class DateUtils {

    // 标准日期格式:yyyy-MM-dd
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    // 标准日期时间格式:yyyy-MM-dd HH:mm:ss
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    /**
     * LocalDateTime 转 字符串
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return dateTime.format(formatter);
    }

    /**
     * 字符串 转 LocalDateTime
     */
    public static LocalDateTime parse(String dateStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(dateStr, formatter);
    }

    /**
     * 获取当前日期字符串(yyyy-MM-dd)
     */
    public static String getNowDate() {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(YYYY_MM_DD));
    }

    /**
     * 获取当前日期时间字符串(yyyy-MM-dd HH:mm:ss)
     */
    public static String getNowDateTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
    }
}

九、总结与避坑指南

1. 核心总结

  1. 优先使用新 API:Java 8+ 强制使用java.time包下的类,抛弃Date/Calendar/SimpleDateFormat
  2. 线程安全:新 API 所有核心类都是不可变类,多线程环境直接使用,无需加锁。
  3. 分工明确
    • 仅日期:LocalDate
    • 仅时间:LocalTime
    • 日期时间:LocalDateTime
    • 时间戳:Instant
    • 格式化:DateTimeFormatter
  4. 时区必备:国际业务使用ZonedDateTime

2. 避坑指南

  1. 格式化 / 解析时,字符串格式必须与模板一致,否则抛DateTimeParseException
  2. Instant是 UTC 时间,直接转北京时间需要 + 8 小时。
  3. 新旧 API 转换时,必须指定时区,否则时间偏差 8 小时。
  4. 不要手动计算日期加减(如闰年、大小月),直接使用plus/minus方法。

结语

Java 日期时间 API 是后端开发的基础核心技能,新 API 设计优雅、功能强大、线程安全,彻底解决了旧 API 的所有痛点。
本文从基础到实战,覆盖了开发中所有日期时间场景,建议收藏备用,熟练掌握后能大幅提升开发效率,避免日期相关 bug。
如果本文对你有帮助,欢迎点赞、收藏、关注,后续持续更新 Java 实战干货!

购买须知/免责声明
1.本文部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。
2.若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
3.如果本站有侵犯、不妥之处的资源,请在网站右边客服联系我们。将会第一时间解决!
4.本站所有内容均由互联网收集整理、网友上传,仅供大家参考、学习,不存在任何商业目的与商业用途。
5.本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
6.不保证任何源码框架的完整性。
7.侵权联系邮箱:aliyun6168@gail.com / aliyun666888@gail.com
8.若您最终确认购买,则视为您100%认同并接受以上所述全部内容。

小璐导航资源站 后端编程 深入掌握 Java 日期时间 API:从基础使用到高级实战(全解析) https://o789.cn/25258.html

相关文章

猜你喜欢