JDK 8 日期时间 API,常用的方法列举出来,写一篇 CSDN 博客
JDK 8 日期时间 API:告别混乱,拥抱优雅
引言
在 Java 8 之前,处理日期和时间是许多开发者的“噩梦”。java.util.Date、java.util.Calendar和java.text.SimpleDateFormat等类存在诸多设计缺陷,例如线程不安全、API 设计混乱(月份从0开始)、可变对象导致状态难以预测等问题。
Java 8 引入了全新的日期时间 API(java.time包),它基于 JSR-310 规范,参考了优秀的 Joda-Time 库,为我们提供了一套线程安全、设计清晰、功能强大的现代化解决方案。本文将带你快速掌握 JDK 8 日期时间 API 的核心用法。
为什么选择 Java 8 的新 API?
- 不可变性与线程安全:所有核心类(如
LocalDate,ZonedDateTime)都是不可变的,这意味着它们天生就是线程安全的,可以在多线程环境中放心使用,无需额外的同步措施。 - 清晰的职责分离:API 将日期、时间、日期时间、时区、时间戳等概念清晰地分离到不同的类中,语义明确,避免了混淆。
- 流畅的 API 设计:提供了大量语义化的方法(如
plusDays(),minusMonths()),并支持链式调用,使代码读起来像自然语言,可读性极高。 - 完善的时区支持:内置了对时区处理的完整支持,让跨时区应用开发变得简单。
核心类一览
java.time包下的核心类各司其职,以下是几个最常用的:
LocalDate:仅包含日期部分(年、月、日),例如2026-04-24。适用于生日、节假日等场景。LocalTime:仅包含时间部分(时、分、秒、纳秒),例如08:42:57。适用于记录每天的营业时间等场景。LocalDateTime:日期和时间的组合,但不包含时区信息,例如2026-04-24T08:42:57。这是最常用的类之一。ZonedDateTime:包含时区信息的完整日期时间,例如2026-04-24T08:42:57+08:00[Asia/Shanghai]。适用于需要精确表示全球时刻的场景。Instant:时间戳,代表自 1970-01-01 00:00:00 UTC 以来的一个瞬间,精度可达纳秒。常用于性能分析、日志记录和分布式系统。DateTimeFormatter:用于格式化和解析日期时间对象的线程安全替代品,用以替代老旧的SimpleDateFormat。Period:用于计算两个LocalDate之间的日期差距(多少年、多少月、多少天)。Duration:用于计算两个时间点之间的时间差距(多少天、多少小时、多少秒)。
常用方法实战
接下来,我们将通过代码示例来展示这些类的常用操作。
获取当前时间
importjava.time.LocalDate;importjava.time.LocalTime;importjava.time.LocalDateTime;importjava.time.ZonedDateTime;importjava.time.Instant;importjava.time.ZoneId;publicclassDateTimeNow{publicstaticvoidmain(String[]args){// 获取当前日期LocalDatedate=LocalDate.now();System.out.println("当前日期: "+date);// 获取当前时间LocalTimetime=LocalTime.now();System.out.println("当前时间: "+time);// 获取当前日期和时间LocalDateTimedateTime=LocalDateTime.now();System.out.println("当前日期时间: "+dateTime);// 获取指定时区的日期时间 (例如上海)ZonedDateTimezonedDateTime=ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));System.out.println("当前北京时间: "+zonedDateTime);// 获取当前时间戳Instantinstant=Instant.now();System.out.println("当前时间戳: "+instant);}}创建指定时间
importjava.time.LocalDate;importjava.time.LocalTime;importjava.time.LocalDateTime;importjava.time.Month;publicclassDateTimeOf{publicstaticvoidmain(String[]args){// 创建指定日期LocalDatedate=LocalDate.of(2026,Month.APRIL,24);System.out.println("指定日期: "+date);// 也可以直接用数字表示月份LocalDatedate2=LocalDate.of(2026,4,24);System.out.println("指定日期2: "+date2);// 创建指定时间LocalTimetime=LocalTime.of(14,30,0);System.out.println("指定时间: "+time);// 创建指定日期时间LocalDateTimedateTime=LocalDateTime.of(2026,4,24,14,30,0);System.out.println("指定日期时间: "+dateTime);}}格式化与解析DateTimeFormatter是线程安全的,可以定义为常量重复使用。
importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;importjava.util.Locale;publicclassDateTimeFormat{// 推荐定义为静态常量privatestaticfinalDateTimeFormatterFORMATTER=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");privatestaticfinalDateTimeFormatterCHINESE_FORMATTER=DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分",Locale.CHINA);publicstaticvoidmain(String[]args){LocalDateTimenow=LocalDateTime.now();// 格式化:日期时间 -> 字符串Stringformatted=now.format(FORMATTER);System.out.println("格式化后: "+formatted);StringchineseFormatted=now.format(CHINESE_FORMATTER);System.out.println("中文格式: "+chineseFormatted);// 解析:字符串 -> 日期时间LocalDateTimeparsed=LocalDateTime.parse("2026-04-24 15:30:00",FORMATTER);System.out.println("解析后: "+parsed);}}时间计算与调整
这是新 API 最强大的地方之一,操作非常直观。
importjava.time.LocalDate;importjava.time.LocalDateTime;importjava.time.temporal.TemporalAdjusters;importjava.time.DayOfWeek;publicclassDateTimeArithmetic{publicstaticvoidmain(String[]args){LocalDateTimenow=LocalDateTime.now();System.out.println("基准时间: "+now);// --- plus/minus 系列:增加或减少时间 ---LocalDateTimetomorrow=now.plusDays(1);System.out.println("明天此时: "+tomorrow);LocalDateTimetwoHoursLater=now.plusHours(2);System.out.println("两小时后: "+twoHoursLater);LocalDateTimelastMonth=now.minusMonths(1);System.out.println("上个月: "+lastMonth);// --- with 系列:直接修改某个字段 ---LocalDateTimefirstMinuteOfHour=now.withMinute(0).withSecond(0);System.out.println("本小时的第1分钟: "+firstMinuteOfHour);LocalDateTimeyear2030=now.withYear(2030);System.out.println("2030年的今天: "+year2030);// --- TemporalAdjusters:高级时间调整器 ---// 获取本月第一天LocalDatefirstDayOfMonth=LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());System.out.println("本月第一天: "+firstDayOfMonth);// 获取本月最后一天LocalDatelastDayOfMonth=LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());System.out.println("本月最后一天: "+lastDayOfMonth);// 获取下一个周一LocalDatenextMonday=LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));System.out.println("下个周一: "+nextMonday);// 获取本年第一个周日LocalDatefirstSundayOfYear=LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));System.out.println("本月第一个周日: "+firstSundayOfYear);}}计算时间间隔
importjava.time.LocalDate;importjava.time.LocalTime;importjava.time.Duration;importjava.time.Period;importjava.time.temporal.ChronoUnit;publicclassDateTimeInterval{publicstaticvoidmain(String[]args){// --- Period: 计算日期间隔 ---LocalDatestartDate=LocalDate.of(2025,1,1);LocalDateendDate=LocalDate.of(2026,4,24);Periodperiod=Period.between(startDate,endDate);System.out.printf("相隔 %d 年 %d 月 %d 天%n",period.getYears(),period.getMonths(),period.getDays());// --- Duration: 计算时间间隔 ---LocalTimestartTime=LocalTime.of(9,0);LocalTimeendTime=LocalTime.of(17,30);Durationduration=Duration.between(startTime,endTime);System.out.printf("会议时长: %d 小时 %d 分钟%n",duration.toHours(),duration.toMinutesPart());// --- ChronoUnit: 更简单的单位计算 ---longdaysBetween=ChronoUnit.DAYS.between(startDate,endDate);System.out.println("总天数差: "+daysBetween);longhoursBetween=ChronoUnit.HOURS.between(startTime,endTime);System.out.println("总小时数差: "+hoursBetween);}}总结
JDK 8 的日期时间 API 彻底改变了 Java 中处理时间的方式。它通过清晰的类设计、不可变的对象模型和丰富的操作方法,解决了旧 API 的所有痛点。强烈建议所有 Java 开发者在新项目中全面采用java.time包,它将让你的代码更加健壮、清晰和易于维护。