3275 字
16 分钟

Java日期和时间处理详解

2026-02-08
浏览量 加载中...

Java日期和时间处理详解#

什么是日期和时间处理?#

日期和时间处理是编程中的常见需求,包括获取当前时间、计算时间差、格式化日期时间等操作。Java提供了多种日期和时间处理的类和API。

日期和时间API的演进#

Java的日期和时间API经历了以下几个阶段:

  1. Java 1.0-1.1Date
  2. Java 1.2+Calendar
  3. Java 8+java.time包(新的日期和时间API)

传统日期和时间API#

1. Date类#

Date类是Java最早的日期和时间类,它表示特定的瞬间,精确到毫秒。

import java.util.Date;
public class DateDemo {
public static void main(String[] args) {
// 创建Date对象
Date now = new Date();
System.out.println("当前时间: " + now);
// 创建指定时间的Date对象
Date specificDate = new Date(1234567890123L); // 时间戳
System.out.println("指定时间: " + specificDate);
// 获取时间戳
long timestamp = now.getTime();
System.out.println("时间戳: " + timestamp);
// 比较日期
boolean before = now.before(specificDate);
boolean after = now.after(specificDate);
int compare = now.compareTo(specificDate);
System.out.println("now在specificDate之前: " + before);
System.out.println("now在specificDate之后: " + after);
System.out.println("比较结果: " + compare);
}
}

2. Calendar类#

Calendar类是一个抽象类,它提供了更多的日期和时间操作方法。

import java.util.Calendar;
import java.util.TimeZone;
public class CalendarDemo {
public static void main(String[] args) {
// 获取Calendar实例
Calendar calendar = Calendar.getInstance();
System.out.println("当前时间: " + calendar.getTime());
// 设置时区
Calendar calendarWithTimeZone = Calendar.getInstance(TimeZone.getTimeZone("America/New_York"));
System.out.println("纽约时间: " + calendarWithTimeZone.getTime());
// 获取日期和时间字段
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份从0开始
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
int millisecond = calendar.get(Calendar.MILLISECOND);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 周日是1,周六是7
System.out.println("年: " + year);
System.out.println("月: " + month);
System.out.println("日: " + day);
System.out.println("时: " + hour);
System.out.println("分: " + minute);
System.out.println("秒: " + second);
System.out.println("毫秒: " + millisecond);
System.out.println("星期: " + dayOfWeek);
// 设置日期和时间
Calendar setCalendar = Calendar.getInstance();
setCalendar.set(2023, Calendar.JANUARY, 1, 12, 0, 0); // 2023年1月1日12:00:00
System.out.println("设置的时间: " + setCalendar.getTime());
// 日期计算
Calendar addCalendar = Calendar.getInstance();
addCalendar.add(Calendar.DAY_OF_MONTH, 7); // 加7天
System.out.println("加7天后: " + addCalendar.getTime());
addCalendar.add(Calendar.MONTH, -1); // 减1个月
System.out.println("减1个月后: " + addCalendar.getTime());
}
}

3. SimpleDateFormat类#

SimpleDateFormat类用于格式化和解析日期和时间。

import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatDemo {
public static void main(String[] args) {
// 创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化日期
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后的日期: " + formattedDate);
// 解析日期
try {
String dateString = "2023-01-01 12:00:00";
Date parsedDate = sdf.parse(dateString);
System.out.println("解析后的日期: " + parsedDate);
} catch (Exception e) {
e.printStackTrace();
}
// 其他格式
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日");
SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); // ISO格式
System.out.println("中文格式: " + sdf1.format(now));
System.out.println("时间格式: " + sdf2.format(now));
System.out.println("ISO格式: " + sdf3.format(now));
}
}

新日期和时间API(Java 8+)#

Java 8引入了新的日期和时间API,它位于java.time包中,提供了更清晰、更易用的日期和时间处理功能。

1. 核心类#

1.1 LocalDate#

LocalDate类表示日期,不包含时间和时区。

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
public class LocalDateDemo {
public static void main(String[] args) {
// 获取当前日期
LocalDate now = LocalDate.now();
System.out.println("当前日期: " + now);
// 创建指定日期
LocalDate specificDate = LocalDate.of(2023, 1, 1);
LocalDate specificDate2 = LocalDate.of(2023, Month.JANUARY, 1);
System.out.println("指定日期: " + specificDate);
// 解析日期
LocalDate parsedDate = LocalDate.parse("2023-01-01");
System.out.println("解析的日期: " + parsedDate);
// 获取日期字段
int year = now.getYear();
Month month = now.getMonth();
int monthValue = now.getMonthValue();
int day = now.getDayOfMonth();
int dayOfYear = now.getDayOfYear();
int dayOfWeek = now.getDayOfWeek().getValue(); // 周一为1,周日为7
System.out.println("年: " + year);
System.out.println("月: " + month);
System.out.println("月值: " + monthValue);
System.out.println("日: " + day);
System.out.println("一年中的第几天: " + dayOfYear);
System.out.println("星期: " + dayOfWeek);
// 日期计算
LocalDate plusDays = now.plusDays(7);
LocalDate minusMonths = now.minusMonths(1);
LocalDate plusYears = now.plusYears(1);
System.out.println("加7天: " + plusDays);
System.out.println("减1个月: " + minusMonths);
System.out.println("加1年: " + plusYears);
// 日期比较
boolean isAfter = now.isAfter(specificDate);
boolean isBefore = now.isBefore(specificDate);
boolean isEqual = now.isEqual(specificDate);
System.out.println("now在specificDate之后: " + isAfter);
System.out.println("now在specificDate之前: " + isBefore);
System.out.println("now等于specificDate: " + isEqual);
// 计算两个日期之间的天数差
long daysBetween = ChronoUnit.DAYS.between(specificDate, now);
System.out.println("两个日期之间的天数差: " + daysBetween);
// 检查闰年
boolean isLeapYear = now.isLeapYear();
System.out.println("今年是闰年: " + isLeapYear);
}
}

1.2 LocalTime#

LocalTime类表示时间,不包含日期和时区。

import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
public class LocalTimeDemo {
public static void main(String[] args) {
// 获取当前时间
LocalTime now = LocalTime.now();
System.out.println("当前时间: " + now);
// 创建指定时间
LocalTime specificTime = LocalTime.of(12, 0, 0);
LocalTime specificTime2 = LocalTime.of(12, 0, 0, 123456789); // 包含纳秒
System.out.println("指定时间: " + specificTime);
// 解析时间
LocalTime parsedTime = LocalTime.parse("12:00:00");
System.out.println("解析的时间: " + parsedTime);
// 获取时间字段
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
int nano = now.getNano();
System.out.println("时: " + hour);
System.out.println("分: " + minute);
System.out.println("秒: " + second);
System.out.println("纳秒: " + nano);
// 时间计算
LocalTime plusHours = now.plusHours(1);
LocalTime minusMinutes = now.minusMinutes(30);
LocalTime plusSeconds = now.plusSeconds(45);
System.out.println("加1小时: " + plusHours);
System.out.println("减30分钟: " + minusMinutes);
System.out.println("加45秒: " + plusSeconds);
// 时间比较
boolean isAfter = now.isAfter(specificTime);
boolean isBefore = now.isBefore(specificTime);
boolean isEqual = now.equals(specificTime);
System.out.println("now在specificTime之后: " + isAfter);
System.out.println("now在specificTime之前: " + isBefore);
System.out.println("now等于specificTime: " + isEqual);
// 计算两个时间之间的分钟差
long minutesBetween = ChronoUnit.MINUTES.between(specificTime, now);
System.out.println("两个时间之间的分钟差: " + minutesBetween);
}
}

1.3 LocalDateTime#

LocalDateTime类表示日期和时间,不包含时区。

import java.time.LocalDateTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;
public class LocalDateTimeDemo {
public static void main(String[] args) {
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期时间: " + now);
// 创建指定日期时间
LocalDateTime specificDateTime = LocalDateTime.of(2023, 1, 1, 12, 0, 0);
LocalDateTime specificDateTime2 = LocalDateTime.of(2023, Month.JANUARY, 1, 12, 0, 0, 123456789);
System.out.println("指定日期时间: " + specificDateTime);
// 解析日期时间
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-01-01T12:00:00");
System.out.println("解析的日期时间: " + parsedDateTime);
// 获取日期和时间字段
int year = now.getYear();
Month month = now.getMonth();
int day = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
System.out.println("年: " + year);
System.out.println("月: " + month);
System.out.println("日: " + day);
System.out.println("时: " + hour);
System.out.println("分: " + minute);
System.out.println("秒: " + second);
// 日期时间计算
LocalDateTime plusDays = now.plusDays(7);
LocalDateTime minusMonths = now.minusMonths(1);
LocalDateTime plusHours = now.plusHours(1);
System.out.println("加7天: " + plusDays);
System.out.println("减1个月: " + minusMonths);
System.out.println("加1小时: " + plusHours);
// 日期时间比较
boolean isAfter = now.isAfter(specificDateTime);
boolean isBefore = now.isBefore(specificDateTime);
boolean isEqual = now.isEqual(specificDateTime);
System.out.println("now在specificDateTime之后: " + isAfter);
System.out.println("now在specificDateTime之前: " + isBefore);
System.out.println("now等于specificDateTime: " + isEqual);
// 计算两个日期时间之间的天数差
long daysBetween = ChronoUnit.DAYS.between(specificDateTime, now);
System.out.println("两个日期时间之间的天数差: " + daysBetween);
// 转换为LocalDate和LocalTime
LocalDate date = now.toLocalDate();
LocalTime time = now.toLocalTime();
System.out.println("转换为LocalDate: " + date);
System.out.println("转换为LocalTime: " + time);
}
}

1.4 ZonedDateTime#

ZonedDateTime类表示带时区的日期和时间。

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class ZonedDateTimeDemo {
public static void main(String[] args) {
// 获取当前带时区的日期时间
ZonedDateTime now = ZonedDateTime.now();
System.out.println("当前带时区的日期时间: " + now);
// 指定时区
ZonedDateTime nowInNewYork = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("纽约时间: " + nowInNewYork);
// 创建指定日期时间和时区
ZonedDateTime specificDateTime = ZonedDateTime.of(2023, 1, 1, 12, 0, 0, 0, ZoneId.systemDefault());
System.out.println("指定带时区的日期时间: " + specificDateTime);
// 解析带时区的日期时间
ZonedDateTime parsedDateTime = ZonedDateTime.parse("2023-01-01T12:00:00+08:00[Asia/Shanghai]");
System.out.println("解析的带时区的日期时间: " + parsedDateTime);
// 获取时区
ZoneId zoneId = now.getZone();
System.out.println("时区: " + zoneId);
// 转换时区
ZonedDateTime convertedDateTime = now.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println("转换到纽约时区: " + convertedDateTime);
// 获取偏移量
ZoneOffset offset = now.getOffset();
System.out.println("偏移量: " + offset);
}
}

1.5 Instant#

Instant类表示时间线上的一个点,精确到纳秒,类似于传统的Date类。

import java.time.Instant;
import java.time.temporal.ChronoUnit;
public class InstantDemo {
public static void main(String[] args) {
// 获取当前Instant
Instant now = Instant.now();
System.out.println("当前Instant: " + now);
// 创建指定Instant
Instant specificInstant = Instant.ofEpochMilli(1234567890123L);
Instant specificInstant2 = Instant.ofEpochSecond(1234567890);
System.out.println("指定Instant: " + specificInstant);
// 获取时间戳
long epochMilli = now.toEpochMilli();
long epochSecond = now.getEpochSecond();
System.out.println("毫秒时间戳: " + epochMilli);
System.out.println("秒时间戳: " + epochSecond);
// 时间计算
Instant plusHours = now.plus(1, ChronoUnit.HOURS);
Instant minusDays = now.minus(1, ChronoUnit.DAYS);
System.out.println("加1小时: " + plusHours);
System.out.println("减1天: " + minusDays);
// 时间比较
boolean isAfter = now.isAfter(specificInstant);
boolean isBefore = now.isBefore(specificInstant);
int compare = now.compareTo(specificInstant);
System.out.println("now在specificInstant之后: " + isAfter);
System.out.println("now在specificInstant之前: " + isBefore);
System.out.println("比较结果: " + compare);
}
}

2. 格式化和解析#

2.1 DateTimeFormatter#

DateTimeFormatter类用于格式化和解析日期和时间。

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
public class DateTimeFormatterDemo {
public static void main(String[] args) {
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
// 使用预定义的格式
DateTimeFormatter formatter1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
System.out.println("ISO格式: " + formatter1.format(now));
System.out.println("FULL格式: " + formatter2.format(now));
System.out.println("MEDIUM格式: " + formatter3.format(now));
// 使用自定义格式
DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter formatter5 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
System.out.println("自定义格式1: " + formatter4.format(now));
System.out.println("自定义格式2: " + formatter5.format(now));
// 解析日期时间
String dateTimeString = "2023-01-01 12:00:00";
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, formatter4);
System.out.println("解析的日期时间: " + parsedDateTime);
}
}

3. 时间间隔和周期#

3.1 Duration#

Duration类表示两个时间点之间的时间间隔。

import java.time.Duration;
import java.time.LocalTime;
public class DurationDemo {
public static void main(String[] args) {
// 创建两个时间点
LocalTime start = LocalTime.of(10, 0, 0);
LocalTime end = LocalTime.of(12, 30, 45);
// 计算时间间隔
Duration duration = Duration.between(start, end);
System.out.println("时间间隔: " + duration);
// 获取时间间隔的各个部分
long hours = duration.toHours();
long minutes = duration.toMinutes();
long seconds = duration.getSeconds();
long millis = duration.toMillis();
System.out.println("小时: " + hours);
System.out.println("分钟: " + minutes);
System.out.println("秒: " + seconds);
System.out.println("毫秒: " + millis);
// 创建Duration
Duration duration1 = Duration.ofHours(1);
Duration duration2 = Duration.ofMinutes(30);
Duration duration3 = Duration.ofSeconds(45);
System.out.println("1小时: " + duration1);
System.out.println("30分钟: " + duration2);
System.out.println("45秒: " + duration3);
// Duration的加减
Duration totalDuration = duration1.plus(duration2).plus(duration3);
System.out.println("总时间间隔: " + totalDuration);
}
}

3.2 Period#

Period类表示两个日期之间的时间间隔。

import java.time.LocalDate;
import java.time.Period;
public class PeriodDemo {
public static void main(String[] args) {
// 创建两个日期
LocalDate start = LocalDate.of(2020, 1, 1);
LocalDate end = LocalDate.of(2023, 6, 15);
// 计算日期间隔
Period period = Period.between(start, end);
System.out.println("日期间隔: " + period);
// 获取日期间隔的各个部分
int years = period.getYears();
int months = period.getMonths();
int days = period.getDays();
System.out.println("年: " + years);
System.out.println("月: " + months);
System.out.println("日: " + days);
// 创建Period
Period period1 = Period.ofYears(1);
Period period2 = Period.ofMonths(6);
Period period3 = Period.ofDays(15);
System.out.println("1年: " + period1);
System.out.println("6个月: " + period2);
System.out.println("15天: " + period3);
// Period的加减
Period totalPeriod = period1.plus(period2).plus(period3);
System.out.println("总日期间隔: " + totalPeriod);
}
}

日期和时间的最佳实践#

1. 优先使用新日期和时间API#

Java 8+的新日期和时间API比传统API更加清晰、易用和安全,应该优先使用。

2. 注意时区问题#

  • 在处理跨时区的日期和时间时,应该使用ZonedDateTimeOffsetDateTime
  • 存储日期和时间时,应该使用UTC时间
  • 显示日期和时间时,应该转换为用户所在时区

3. 格式化和解析#

  • 使用DateTimeFormatter进行日期和时间的格式化和解析
  • 预定义的格式器比自定义格式器更安全
  • 解析日期和时间时,应该处理可能的异常

4. 不可变性#

新日期和时间API的类都是不可变的,这意味着它们的方法不会修改对象本身,而是返回一个新的对象。

// 正确的做法
LocalDate tomorrow = LocalDate.now().plusDays(1);
// 错误的做法
LocalDate today = LocalDate.now();
today.plusDays(1); // 这不会修改today,而是返回一个新的LocalDate

5. 性能考虑#

  • 对于频繁使用的日期和时间操作,应该缓存DateTimeFormatter实例
  • 避免在循环中创建大量的日期和时间对象

6. 兼容性#

  • 当需要与传统API交互时,可以使用toInstant()from()方法进行转换
  • Java 8+提供了Date.from(Instant)date.toInstant()方法

常见陷阱#

1. 月份从0开始#

在传统的Calendar类中,月份是从0开始的,这可能会导致错误。

// 错误的做法
Calendar calendar = Calendar.getInstance();
calendar.set(2023, 1, 1); // 这会设置为2023年2月1日,而不是1月1日
// 正确的做法
calendar.set(2023, Calendar.JANUARY, 1); // 使用Calendar的常量

2. 时区问题#

  • 忽略时区会导致日期和时间的计算错误
  • 不同地区的用户可能会看到不同的时间

3. 格式化和解析的异常#

  • 解析日期和时间时,如果格式不正确,会抛出异常
  • 应该使用try-catch块来处理这些异常

4. 不可变性#

  • 新日期和时间API的类是不可变的,方法调用不会修改对象本身
  • 应该使用方法返回的新对象

5. 性能问题#

  • 频繁创建DateTimeFormatter实例会影响性能
  • 应该缓存DateTimeFormatter实例

6. 兼容性问题#

  • 新日期和时间API在Java 8+中可用,在旧版本中不可用
  • 如果需要支持旧版本,应该使用传统API或第三方库

总结#

日期和时间处理是Java编程中的常见需求,Java提供了多种日期和时间处理的类和API。Java 8引入的新日期和时间API(java.time包)比传统API更加清晰、易用和安全,应该优先使用。

本文介绍了Java的传统日期和时间API(DateCalendarSimpleDateFormat)和新日期和时间API(LocalDateLocalTimeLocalDateTimeZonedDateTimeInstant等),以及它们的使用方法和最佳实践。希望本文能够帮助你更好地理解和使用Java的日期和时间处理功能。

练习#

  1. 编写一个程序,使用新日期和时间API获取当前日期和时间。

  2. 编写一个程序,计算两个日期之间的天数差。

  3. 编写一个程序,格式化日期和时间为不同的格式。

  4. 编写一个程序,解析字符串为日期和时间。

  5. 编写一个程序,处理不同时区的日期和时间。

  6. 编写一个程序,使用Duration计算两个时间点之间的时间间隔。

  7. 编写一个程序,使用Period计算两个日期之间的时间间隔。

  8. 编写一个程序,演示新日期和时间API的不可变性。

  9. 编写一个程序,处理日期和时间的异常。

  10. 编写一个程序,在传统API和新API之间进行转换。

通过这些练习,你将更加熟悉Java的日期和时间处理,为后续的学习做好准备。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Java日期和时间处理详解
https://blog.vanilla.net.cn/posts/2026-02-05-java-date-time/
作者
鹁鸪
发布于
2026-02-08
许可协议
CC BY-NC-SA 4.0

评论区

目录