java学习--第三代日期时间

一、核心定位:为什么它是「第三代」& 终极方案

Java 日期时间 API 发展历经 三代java.time 包(JDK 1.8 推出)是官方最终的最优解,也被称为 JSR 310 规范,彻底解决了前两代 API 的所有痛点:

✅ 三代日期 API 对比(清晰选型)

版本 核心类 定位 致命缺陷 现状
第一代 java.util.Date 仅表示「时间瞬间」 方法大量过时、无计算能力、设计混乱 几乎弃用,仅兼容老代码
第二代 java.util.Calendar 日期计算工具 月份 0 开始、星期设计反人类、线程不安全、API 繁琐 老项目过渡用,新项目禁用
第三代 java.time 全家桶 一站式日期时间解决方案 ✅ 无缺陷 JDK8+ 开发首选,强制推荐

✅ 第三代 API 核心优势(碾压前两代)

线程安全 :所有类都是「不可变对象」,修改会生成新对象,无并发风险✅ 设计优雅 :日期、时间、日期 + 时间、时区彻底分离,语义清晰,见名知意✅ 无坑点 :月份从1开始、星期从1开始,完全符合人类认知,告别手动修正✅ 功能强大 :原生支持日期计算、格式化、解析、时区转换、闰年判断,无需工具类✅ API 简洁:支持链式调用,一行代码完成复杂日期操作,开发效率翻倍

二、核心前置知识:java.time 包核心类划分(必记)

java.time 包对 日期、时间、时区、格式化 做了极致拆分,各司其职,这是它优雅的核心。核心类按功能分为 4 大类,必须熟记用途,杜绝用错类!

✅ 1. 「无时区」核心类(开发 90% 场景使用)

💡 特点:不关心时区,仅表示「本地」的日期 / 时间,是日常开发最常用的三类核心类。

✔️ LocalDate → 仅存「日期」(年 + 月 + 日)
  • 用途:只处理年月日相关业务,比如「生日、订单日期、会员到期日」
  • 示例:2025-12-29,不含时分秒
✔️ LocalTime → 仅存「时间」(时 + 分 + 秒 + 毫秒)
  • 用途:只处理时分秒相关业务,比如「闹钟时间、营业时间、接口响应耗时」
  • 示例:18:30:59.123,不含年月日
✔️ LocalDateTime → 日期 + 时间(年 + 月 + 日 + 时 + 分 + 秒 + 毫秒)
  • 用途:处理完整的日期 + 时间业务,比如「订单创建时间、日志时间、任务执行时间」
  • 示例:2025-12-29 18:30:59.123 → ✅ 开发最高频使用!

✅ 2. 「有时区」核心类(跨时区业务专用)

💡 特点:绑定时区 / UTC 时间,精准表示「全球唯一的时间瞬间」,用于国际化、跨时区系统。

✔️ Instant → UTC 时间戳(对应 Date)
  • 用途:表示 UTC 标准时间(1970-01-01 00:00:00 到此刻的毫秒数),等价于 Date 类,常用于「时间戳存储、跨系统时间传输」
  • 示例:2025-12-29T10:30:59.123Z(Z 代表 UTC 时区)
✔️ ZonedDateTime → 带时区的完整时间
  • 用途:表示「指定时区」的日期 + 时间,比如「纽约时间、东京时间」,用于国际化业务
  • 示例:2025-12-29T18:30:59.123+08:00[Asia/Shanghai](东八区)

✅ 3. 时间间隔类(计算时间差专用)

✔️ Duration → 计算「时分秒」间隔(秒 / 毫秒级)
  • 用途:两个时间 / 日期时间的间隔,精确到秒、毫秒,比如「接口耗时、任务执行时长」
✔️ Period → 计算「年月日」间隔(天 / 月 / 年级)
  • 用途:两个日期的间隔,精确到年、月、日,比如「年龄计算、会员剩余天数」

✅ 4. 格式化 & 解析类(专属工具)

✔️ DateTimeFormatter → 格式化 + 解析工具
  • 用途:替代第一代的SimpleDateFormat,完成「日期对象 ↔ 字符串」的转换
  • 核心优势:线程安全、支持自定义格式、内置标准格式,无并发风险 → ✅ 开发首选!

三、核心类实战(按使用频率排序,全示例 + 详解)

✅ 一、高频王者:LocalDateTime(日期 + 时间,90% 场景必用)

✔️ 1. 创建 LocalDateTime 对象(4 种常用方式)
复制代码
import java.time.LocalDateTime;

public class LocalDateTimeDemo {
    public static void main(String[] args) {
        // 方式1:获取【当前系统】的日期+时间(最常用)
        LocalDateTime now = LocalDateTime.now();
        System.out.println("当前时间:" + now); // 输出:2025-12-29T18:45:30.123

        // 方式2:手动指定【年月日时分秒】创建(精准定制,常用)
        LocalDateTime target = LocalDateTime.of(2025, 12, 25, 20, 0, 0);
        System.out.println("指定时间:" + target); // 输出:2025-12-25T20:00

        // 方式3:LocalDate + LocalTime 组合创建
        LocalDate date = LocalDate.of(2025, 12, 29);
        LocalTime time = LocalTime.of(18, 50);
        LocalDateTime combine = LocalDateTime.of(date, time);
        System.out.println("组合创建:" + combine); // 输出:2025-12-29T18:50

        // 方式4:字符串解析创建(配合格式化器,后文详解)
    }
}
✔️ 2. 获取时间字段(年 / 月 / 日 / 时 / 分 / 秒,无坑!)

💡 核心亮点:月份返回1-12、星期返回1-7(周一 = 1,周日 = 7),完全符合人类认知,无需任何修正

复制代码
LocalDateTime now = LocalDateTime.now();

// 获取核心字段
int year = now.getYear(); // 年份:2025
int month = now.getMonthValue(); // 月份:12(直接返回1-12,无坑)
int day = now.getDayOfMonth(); // 日期:29
int hour = now.getHour(); // 小时:18
int minute = now.getMinute(); // 分钟:45
int second = now.getSecond(); // 秒:30
int nano = now.getNano(); // 纳秒(1毫秒=100万纳秒)
int week = now.getDayOfWeek().getValue(); // 星期:1(周一)~7(周日)

System.out.printf("当前:%d年%d月%d日 %02d:%02d:%02d 星期%d%n", 
                  year, month, day, hour, minute, second, week);
✔️ 3. 日期计算(增减操作,核心能力,支持链式调用)

💡 核心亮点:不可变对象,所有增减操作都会返回「新对象」,原对象不变;支持任意字段的增减,API 语义化极强。

复制代码
LocalDateTime now = LocalDateTime.now();
System.out.println("原始时间:" + now);

// ========== 字段增减(推荐:链式调用,一行完成) ==========
LocalDateTime newTime = now
        .plusYears(1)    // 加1年
        .minusMonths(2)  // 减2个月
        .plusDays(7)     // 加7天
        .minusHours(3)   // 减3小时
        .plusMinutes(30); // 加30分钟

System.out.println("计算后时间:" + newTime);

// ========== 单独增减(按需使用) ==========
LocalDateTime nextWeek = now.plusWeeks(1); // 加1周
LocalDateTime lastSecond = now.minusSeconds(1); // 减1秒
✔️ 4. 时间比较(isAfter/isBefore/isEqual,语义清晰)
复制代码
LocalDateTime time1 = LocalDateTime.of(2025,12,25,20,0);
LocalDateTime time2 = LocalDateTime.of(2025,12,29,18,0);

boolean isAfter = time2.isAfter(time1); // true:time2晚于time1
boolean isBefore = time2.isBefore(time1); // false:time2早于time1
boolean isEqual = time2.isEqual(time1); // false:时间相等

System.out.println("time2是否晚于time1:" + isAfter);

✅ 二、高频次类:LocalDate(仅日期)+ LocalTime(仅时间)

二者 API 与 LocalDateTime 高度一致,仅操作维度不同(一个只有日期、一个只有时间),复用性极强,快速掌握核心用法即可:

✔️ LocalDate 核心用法(仅年月日)
复制代码
import java.time.LocalDate;

public class LocalDateDemo {
    public static void main(String[] args) {
        // 1. 创建:当前日期 / 指定日期
        LocalDate nowDate = LocalDate.now(); // 2025-12-29
        LocalDate targetDate = LocalDate.of(2025, 12, 25); // 2025-12-25

        // 2. 获取字段
        int year = nowDate.getYear();
        int month = nowDate.getMonthValue();
        int day = nowDate.getDayOfMonth();
        int week = nowDate.getDayOfWeek().getValue();

        // 3. 日期计算
        LocalDate nextDay = nowDate.plusDays(1); // 次日
        LocalDate lastMonth = nowDate.minusMonths(1); // 上月今日

        // 4. 常用判断
        boolean isLeapYear = nowDate.isLeapYear(); // 判断是否闰年 ✅ 原生支持!
        boolean isBefore = targetDate.isBefore(nowDate); // true
    }
}
✔️ LocalTime 核心用法(仅时分秒)
复制代码
import java.time.LocalTime;

public class LocalTimeDemo {
    public static void main(String[] args) {
        // 1. 创建:当前时间 / 指定时间
        LocalTime nowTime = LocalTime.now(); // 18:55:30.123
        LocalTime targetTime = LocalTime.of(20, 0, 0); // 20:00:00

        // 2. 获取字段
        int hour = nowTime.getHour();
        int minute = nowTime.getMinute();
        int second = nowTime.getSecond();

        // 3. 时间计算
        LocalTime after2Hour = nowTime.plusHours(2); // 加2小时
        LocalTime before30Min = nowTime.minusMinutes(30); // 减30分钟
    }
}

✅ 三、核心工具:DateTimeFormatter(格式化 & 解析,线程安全)

💡 替代第一代的 SimpleDateFormat,解决其 线程不安全 的致命缺陷,是 java.time 包的专属格式化工具,开发强制使用 !核心能力:日期对象 → 自定义格式字符串(格式化)、字符串 → 日期对象(解析)

✔️ 格式模式符(与 SimpleDateFormat 通用,必记)

yyyy(4位年)、MM(2位月)、dd(2位日)、HH(24小时)、hh(12小时)、mm(分)、ss(秒)、SSS(毫秒)

✔️ 完整示例:格式化 + 解析
复制代码
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

public class DateTimeFormatterDemo {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        // 1. 定义格式化器(两种方式,推荐方式2:自定义格式)
        // 方式1:使用内置标准格式(无需自定义)
        DateTimeFormatter fmt1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        // 方式2:自定义格式(开发最常用,模式符大小写敏感)
        DateTimeFormatter fmt2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");

        // ========== 操作1:格式化(日期对象 → 字符串) ==========
        String str1 = fmt1.format(now); // 标准格式:2025-12-29T19:00:00.123
        String str2 = fmt2.format(now); // 自定义格式:2025-12-29 19:00:00 123
        System.out.println("标准格式:" + str1);
        System.out.println("自定义格式:" + str2);

        // ========== 操作2:解析(字符串 → 日期对象) ==========
        String timeStr = "2025-12-25 20:00:00 000";
        try {
            // 注意:字符串格式必须与格式化器模式完全匹配,否则抛DateTimeParseException
            LocalDateTime parseTime = LocalDateTime.parse(timeStr, fmt2);
            System.out.println("解析后的时间:" + parseTime);
        } catch (DateTimeParseException e) {
            e.printStackTrace();
        }
    }
}

✅ 四、时间差计算:Duration(时分秒)+ Period(年月日)

💡 前两代 API 计算时间差需要手动通过「时间戳相减」实现,极其繁琐;第三代 API 原生提供两个工具类,精准计算时间差,无需手动处理

✔️ Duration → 计算「时分秒 / 毫秒」差(时间 / 日期时间)
复制代码
import java.time.Duration;
import java.time.LocalDateTime;

public class DurationDemo {
    public static void main(String[] args) {
        LocalDateTime start = LocalDateTime.of(2025,12,25,20,0,0);
        LocalDateTime end = LocalDateTime.of(2025,12,29,18,30,59);

        // 计算两个时间的间隔
        Duration duration = Duration.between(start, end);
        
        // 获取间隔的具体值
        long days = duration.toDays(); // 总天数
        long hours = duration.toHours(); // 总小时数
        long minutes = duration.toMinutes(); // 总分钟数
        long seconds = duration.getSeconds(); // 总秒数
        long millis = duration.toMillis(); // 总毫秒数

        System.out.printf("间隔:%d天%d小时%n", days, duration.toHoursPart());
    }
}
✔️ Period → 计算「年月日」差(仅日期)
复制代码
import java.time.LocalDate;
import java.time.Period;

public class PeriodDemo {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2000, 1, 1);
        LocalDate end = LocalDate.of(2025, 12, 29);

        // 计算两个日期的间隔
        Period period = Period.between(start, end);
        
        // 获取间隔的年、月、日(单独值,非总数量)
        int years = period.getYears(); // 25年
        int months = period.getMonths(); // 11个月
        int days = period.getDays(); // 28天

        System.out.printf("间隔:%d年%d月%d日%n", years, months, days);
    }
}

✅ 五、跨代兼容:与 Date/Calendar 互转(老项目必备)

实际开发中难免遇到老代码(Date/Calendar),java.time 提供了无缝互转方案,核心桥梁是 Instant (对应 Date,均表示时间戳瞬间),配合时区 ZoneId 完成转换。

✔️ 完整互转示例(开发高频)
复制代码
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;

public class ConvertDemo {
    public static void main(String[] args) {
        ZoneId zoneId = ZoneId.systemDefault(); // 系统默认时区(东八区 Asia/Shanghai)
        LocalDateTime ldt = LocalDateTime.of(2025,12,29,19,0,0);

        // ========== 1. 第三代 ↔ Date ==========
        // LocalDateTime → Date
        Instant instant1 = ldt.atZone(zoneId).toInstant();
        Date date1 = Date.from(instant1);
        
        // Date → LocalDateTime
        Instant instant2 = date1.toInstant();
        LocalDateTime ldt2 = LocalDateTime.ofInstant(instant2, zoneId);

        // ========== 2. 第三代 ↔ Calendar ==========
        // Calendar → LocalDateTime
        Calendar cal = Calendar.getInstance();
        Date date2 = cal.getTime();
        LocalDateTime ldt3 = LocalDateTime.ofInstant(date2.toInstant(), zoneId);
        
        // LocalDateTime → Calendar(间接:先转Date)
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(Date.from(ldt.atZone(zoneId).toInstant()));
    }
}

三、扩展类:Instant(时间戳)+ ZonedDateTime(带时区)

Instant → 等价于 Date,UTC 时间戳

复制代码
import java.time.Instant;

public class InstantDemo {
    public static void main(String[] args) {
        // 1. 创建:当前UTC时间、指定时间戳
        Instant now = Instant.now(); // UTC当前时间
        Instant instant = Instant.ofEpochMilli(System.currentTimeMillis()); // 通过毫秒数创建

        // 2. 转时间戳(毫秒)
        long timestamp = now.toEpochMilli(); // 等价于 new Date().getTime()
        
        // 3. 与Date互转(直接支持)
        Date date = Date.from(now);
        Instant instant2 = date.toInstant();
    }
}

ZonedDateTime → 带时区的完整时间(国际化专用)

复制代码
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class ZonedDateTimeDemo {
    public static void main(String[] args) {
        // 1. 创建:系统时区、指定时区(纽约/东京/伦敦)
        ZonedDateTime now = ZonedDateTime.now(); // 系统默认时区(东八区)
        ZonedDateTime nyTime = ZonedDateTime.now(ZoneId.of("America/New_York")); // 纽约时间
        ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo")); // 东京时间

        System.out.println("上海时间:" + now);
        System.out.println("纽约时间:" + nyTime);
    }
}

四、核心总结 & 开发强制规范(必遵循)

✅ 核心知识点总结

  1. Java 第三代日期 API 是 java.time 包(JDK8+),又称 JSR310,是终极最优解
  2. 核心类按用途拆分:LocalDateTime(高频)、LocalDate/LocalTime(常用)、DateTimeFormatter(格式化)、Duration/Period(时间差);
  3. 所有类都是不可变对象,修改会生成新对象,天然线程安全;
  4. 无坑点:月份 1-12、星期 1-7,符合人类认知,无需修正;
  5. 支持链式调用原生计算原生格式化,API 语义化极强。

✅ 开发强制规范(直接套用)

  1. JDK8+ 新项目全程使用 java.time 包,彻底抛弃 Date/Calendar/SimpleDateFormat;
  2. 日期 + 时间业务 → 用 LocalDateTime;仅日期 → 用 LocalDate;仅时间 → 用 LocalTime
  3. 格式化 / 解析 → 强制用 DateTimeFormatter,杜绝 SimpleDateFormat
  4. 时间差计算 → 用 Duration(时分秒)/ Period(年月日);
  5. 老项目兼容 → 通过 Instant+ZoneId 实现与 Date/Calendar 互转;
  6. 跨时区业务 → 用 ZonedDateTime/Instant

✅ 一句话口诀(快速记忆)

本地用 Local 三兄弟,格式化用 DateTimeFormatter,时间差用 Duration/Period,时区用 Zoned/Instant

至此,Java 日期时间的所有知识已全部覆盖,掌握第三代 API 即可从容应对所有日期相关开发场景,告别前两代的所有坑点!

相关推荐
Yang-Never2 小时前
Android 内存泄漏 -> LiveData如何解决ViewMode和Activity/Fragment之间的内存泄漏
android·java·开发语言·kotlin·android studio
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [fs]libfs
linux·笔记·学习
ZLZQ_Yuan2 小时前
线程池使用
java
不爱吃糖的程序媛2 小时前
鸿蒙PC端Java应用开发实战:从环境适配到系统信息采集
java·华为·harmonyos
鹿角片ljp2 小时前
深入理解Java集合框架:核心接口与实现解析
java·开发语言·windows
行业探路者2 小时前
PPT生成二维码与网址跳转码及短视频二维码的应用攻略
大数据·人工智能·学习·产品运营·软件工程
大布布将军2 小时前
⚡后端安全基石:JWT 原理与身份验证实战
前端·javascript·学习·程序人生·安全·node.js·aigc
小贝IT~2 小时前
基于SpringBoot的网页时装购物系统-049
java·spring boot·后端