目录
在 Java 中,处理日期和时间的类随着版本的发展有不同的体系。早期版本主要使用 java.util.Date
、java.util.Calendar
等类,Java 8 及以后引入了新的日期和时间 API(JSR 310),包含在 java.time
包中。
甲骨文官方文档
Overview (Java SE 21 & JDK 21)
JDK中文文档。https://java.cunzaima.cn/jdk21/doc-zh/api/index.html
旧的日期时间 API
1. java.util.Date
- 概述:
Date
类表示特定的瞬间,精确到毫秒。不过它的很多方法在 Java 1.1 之后已经被弃用,因为其设计存在一些问题,比如线程不安全、缺乏时区支持等。 - 常用方法
Date()
:创建一个表示当前时间的Date
对象。Date(long date)
:根据给定的毫秒数创建Date
对象,该毫秒数是从 1970 年 1 月 1 日 00:00:00 GMT 开始计算的。getTime()
:返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此Date
对象表示的毫秒数。equals(Object obj)
:比较两个Date
对象是否相等。
import java.util.Date;
public class DateExample {
public static void main(String[] args) {
// 创建表示当前时间的 Date 对象
Date currentDate = new Date();
System.out.println("当前时间: " + currentDate);
// 根据毫秒数创建 Date 对象
long milliseconds = 1609459200000L;
Date specificDate = new Date(milliseconds);
System.out.println("指定时间: " + specificDate);
// 获取毫秒数
long timeInMillis = currentDate.getTime();
System.out.println("当前时间的毫秒数: " + timeInMillis);
// 比较两个 Date 对象
boolean isEqual = currentDate.equals(specificDate);
System.out.println("两个日期是否相等: " + isEqual);
}
}
2. java.util.Calendar
- 概述:
Calendar
是一个抽象类,用于在 Java 中进行日期和时间的计算。它提供了一些方法来获取和设置年、月、日、时、分、秒等信息,并且支持时区和本地化。 - 常用方法
Calendar.getInstance()
:获取一个Calendar
实例,该实例使用默认时区和语言环境。get(int field)
:获取指定字段的值,例如Calendar.YEAR
、Calendar.MONTH
等。set(int field, int value)
:设置指定字段的值。add(int field, int amount)
:对指定字段进行加减操作。
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
// 获取 Calendar 实例
Calendar calendar = Calendar.getInstance();
// 获取年、月、日
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 月份从 0 开始,所以要加 1
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("当前日期: " + year + "-" + month + "-" + day);
// 设置日期
calendar.set(Calendar.YEAR, 2025);
calendar.set(Calendar.MONTH, Calendar.JUNE);
calendar.set(Calendar.DAY_OF_MONTH, 15);
System.out.println("设置后的日期: " + calendar.getTime());
// 日期加减操作
calendar.add(Calendar.DAY_OF_MONTH, 5);
System.out.println("加 5 天后的日期: " + calendar.getTime() +"\t"
+ calendar.getTime().getTime()+"\t"+ calendar.getTimeInMillis() +"\t"
+ calendar.getTimeZone().getOffset(calendar.getTimeInMillis()));
// 设置时区
TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
calendar.setTimeZone(timeZone);
System.out.println("美国纽约的日期: " + calendar.getTime() +"\t"
+ calendar.getTime().getTime() +"\t"+ calendar.getTimeInMillis() +"\t"
+ calendar.getTimeZone().getOffset(calendar.getTimeInMillis()));
}
}
SimpleDateFormat
:用于将Date
对象格式化为指定的字符串格式,或者将字符串解析为Date
对象。它通过模式字符串来定义日期和时间的格式,常用的模式字符有:y
:年,如yyyy
表示四位年份,yy
表示两位年份。M
:月,MM
表示两位数字的月份,MMM
表示月份的缩写(如 Jan、Feb 等),MMMM
表示月份的全称。d
:日,dd
表示两位数字的日。H
:小时(24 小时制),HH
表示两位数字的小时。h
:小时(12 小时制)。m
:分钟,mm
表示两位数字的分钟。s
:秒,ss
表示两位数字的秒。S
:毫秒。z
:时区,如CST
。
例如,SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
可以将Date
对象格式化为2024-05-08 14:34:56
这样的字符串。
java.util.Calendar
:Calendar
类主要用于对日期和时间进行操作和计算,它本身没有直接的日期格式表示。但可以通过SimpleDateFormat
将Calendar
对象转换为指定格式的字符串,例如:
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = sdf.format(calendar.getTime());
String dateString = "2024-10-01 14:30:00";
try {
Date date = sdf.parse(dateString);
System.out.println("解析后的日期: " + date);
} catch (ParseException e) {
System.out.println("解析日期时出错: " + e.getMessage());
}
新的日期时间 API(Java 8+)
1. java.time.LocalDate
- 概述:
LocalDate
表示一个不可变的日期对象,只包含日期信息(年、月、日),不包含时间和时区信息。 - 常用方法
LocalDate.now()
:获取当前日期。LocalDate.of(int year, int month, int dayOfMonth)
:根据指定的年、月、日创建LocalDate
对象。getYear()
、getMonth()
、getDayOfMonth()
:获取年、月、日信息。plusDays(long daysToAdd)
、minusDays(long daysToSubtract)
:进行日期的加减操作。
import java.time.LocalDate;
public class LocalDateExample {
public static void main(String[] args) {
// 获取当前日期
LocalDate currentDate = LocalDate.now();
System.out.println("当前日期: " + currentDate);
// 根据指定的年、月、日创建 LocalDate 对象
LocalDate specificDate = LocalDate.of(2025, 6, 15);
System.out.println("指定日期: " + specificDate);
// 获取日期信息
int year = specificDate.getYear();
int month = specificDate.getMonthValue();
int day = specificDate.getDayOfMonth();
System.out.println("指定日期的年: " + year + ", 月: " + month + ", 日: " + day);
// 日期加减操作
LocalDate newDate = specificDate.plusDays(5);
System.out.println("加 5 天后的日期: " + newDate);
}
}
2. java.time.LocalTime
- 概述:
LocalTime
表示一个不可变的时间对象,只包含时间信息(时、分、秒、纳秒),不包含日期和时区信息。 - 常用方法
LocalTime.now()
:获取当前时间。LocalTime.of(int hour, int minute)
:根据指定的时、分创建LocalTime
对象。getHour()
、getMinute()
、getSecond()
:获取时、分、秒信息。plusHours(long hoursToAdd)
、minusMinutes(long minutesToSubtract)
:进行时间的加减操作。
import java.time.LocalTime;
public class LocalTimeExample {
public static void main(String[] args) {
// 获取当前时间
LocalTime currentTime = LocalTime.now();
System.out.println("当前时间: " + currentTime);
// 根据指定的时、分创建 LocalTime 对象
LocalTime specificTime = LocalTime.of(14, 30);
System.out.println("指定时间: " + specificTime);
// 获取时间信息
int hour = specificTime.getHour();
int minute = specificTime.getMinute();
System.out.println("指定时间的时: " + hour + ", 分: " + minute);
// 时间加减操作
LocalTime newTime = specificTime.plusHours(2);
System.out.println("加 2 小时后的时间: " + newTime);
}
}
3. java.time.LocalDateTime
- 概述:
LocalDateTime
表示一个不可变的日期和时间对象,包含日期和时间信息(年、月、日、时、分、秒、纳秒),不包含时区信息。 - 常用方法:结合了
LocalDate
和LocalTime
的方法,可进行日期和时间的操作。
import java.time.LocalDateTime;
public class LocalDateTimeExample {
public static void main(String[] args) {
// 获取当前日期和时间
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("当前日期和时间: " + currentDateTime);
// 根据指定的日期和时间创建 LocalDateTime 对象
LocalDateTime specificDateTime = LocalDateTime.of(2025, 6, 15, 14, 30);
System.out.println("指定日期和时间: " + specificDateTime);
// 日期和时间加减操作
LocalDateTime newDateTime = specificDateTime.plusDays(2).plusHours(3);
System.out.println("加 2 天 3 小时后的日期和时间: " + newDateTime);
}
}
4. java.time.ZonedDateTime
- 概述:
ZonedDateTime
表示一个带时区的日期和时间对象,包含日期、时间和时区信息。 - 常用方法
ZonedDateTime.now()
:获取当前带时区的日期和时间。ZonedDateTime.of(LocalDateTime localDateTime, ZoneId zone)
:根据LocalDateTime
和ZoneId
创建ZonedDateTime
对象。getZone()
:获取时区信息。
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ZonedDateTimeExample {
public static void main(String[] args) {
// 获取当前带时区的日期和时间
ZonedDateTime currentZonedDateTime = ZonedDateTime.now();
System.out.println("当前带时区的日期和时间: " + currentZonedDateTime);
// 根据 LocalDateTime 和 ZoneId 创建 ZonedDateTime 对象
LocalDateTime localDateTime = LocalDateTime.of(2025, 6, 15, 14, 30);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime specificZonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
System.out.println("指定带时区的日期和时间: " + specificZonedDateTime);
// 获取时区信息
ZoneId zone = specificZonedDateTime.getZone();
System.out.println("时区: " + zone);
}
}
Instant
对象
now
方法:可以通过Instant.now()
获取当前时间的Instant
对象。例如,Instant instant = Instant.now();
,这将返回当前时刻的Instant
,精确到纳秒。
获取时间戳
toEpochMilli
方法:Instant
提供了toEpochMilli
方法来获取从 1970 年 1 月 1 日 00:00:00 UTC 到该Instant
所表示的时间点的毫秒数。例如,long millis = instant.toEpochMilli();
,可以将Instant
对象转换为时间戳,方便与其他需要时间戳的系统或 API 进行交互。getEpochSecond
方法:获取从 1970 年 1 月 1 日 00:00:00 UTC 到该Instant
所表示的时间点的秒数。例如,long seconds = instant.getEpochSecond();
,如果需要以秒为单位获取时间戳,可以使用该方法。
时间计算
Instant
可以进行时间的加减运算,通过plus
和minus
方法来实现。例如,要获取当前时间 5 秒后的Instant
,可以使用Instant futureInstant = Instant.now().plusSeconds(5);
;要获取 10 分钟前的Instant
,可以使用Instant pastInstant = Instant.now().minusMinutes(10);
。
与其他日期时间类型的转换
- 与
LocalDateTime
转换:可以通过atZone
方法将Instant
转换为指定时区的LocalDateTime
。例如,Instant instant = Instant.now(); LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
,这将把当前的Instant
转换为系统默认时区的LocalDateTime
。反之,也可以通过toInstant
方法将LocalDateTime
转换为Instant
,例如,LocalDateTime ldt = LocalDateTime.now(); Instant instant = ldt.toInstant(ZoneOffset.UTC);
,将当前的LocalDateTime
转换为 UTC 时区的Instant
。 - 与
ZonedDateTime
转换:Instant
可以直接通过atZone
方法转换为ZonedDateTime
,例如,Instant instant = Instant.now(); ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
,将当前的Instant
转换为系统默认时区的ZonedDateTime
。而ZonedDateTime
也可以通过toInstant
方法转换为Instant
,例如,ZonedDateTime zdt = ZonedDateTime.now(); Instant instant = zdt.toInstant();
。
DateTimeFormatter
java.time
包中的格式化类:新日期时间 API 提供了DateTimeFormatter
类来进行日期和时间的格式化与解析。它的模式定义与SimpleDateFormat
有一些相似之处,但更加灵活和强大。常用的模式字符与SimpleDateFormat
类似,例如yyyy-MM-dd
、HH:mm:ss
等。LocalDate
、LocalTime
和LocalDateTime
:LocalDate
:表示日期,默认格式为yyyy-MM-dd
,例如2024-05-08
。可以使用DateTimeFormatter
进行格式化,如LocalDate.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy")) //会将当前日期格式化为08/05/2024。
LocalTime
:表示时间,默认格式为HH:mm:ss.SSS
,例如14:34:56.123
。同样可以通过DateTimeFormatter
进行自定义格式化。LocalDateTime
:表示日期和时间,默认格式为yyyy-MM-dd HH:mm:ss.SSS
,例如2024-05-08 14:34:56.123
。也能使用DateTimeFormatter
按照需求进行格式化。
- 综合案例:
-
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class DateTimeFormatterExample { public static void main(String[] args) { // 1. 通过模式字符串创建DateTimeFormatter DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 2. 格式化当前日期时间 LocalDateTime now = LocalDateTime.now(); String formattedDateTime1 = formatter1.format(now); System.out.println("Formatted DateTime 1: " + formattedDateTime1); // 3. 使用预定义的格式创建DateTimeFormatter DateTimeFormatter formatter2 = DateTimeFormatter.ISO_LOCAL_DATE_TIME; String formattedDateTime2 = formatter2.format(now); System.out.println("Formatted DateTime 2: " + formattedDateTime2); // 4. 解析字符串为日期时间对象 String dateTimeStr = "2024-05-08 12:30:00"; LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, formatter1); System.out.println("Parsed DateTime: " + parsedDateTime); // 5. 基于本地化创建DateTimeFormatter DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL) .withLocale(Locale.CHINA); String formattedDateTime3 = formatter3.format(now); System.out.println("Formatted DateTime 3: " + formattedDateTime3); } }
Duration
Duration
类用于以秒和纳秒的方式表示时间间隔,它主要处理基于时间(小时、分钟、秒、纳秒)的时间量,适用于处理诸如程序执行时间、两个时间点之间的时间差等场景。
创建 Duration
对象
Duration.between(Temporal startInclusive, Temporal endExclusive)
:根据两个Temporal
对象(如LocalTime
、LocalDateTime
或Instant
)计算它们之间的时间间隔。
import java.time.Duration;
import java.time.LocalTime;
public class DurationExample {
public static void main(String[] args) {
LocalTime startTime = LocalTime.of(9, 0);
LocalTime endTime = LocalTime.of(12, 30);
Duration duration = Duration.between(startTime, endTime);
System.out.println("时间间隔: " + duration);
}
}
Duration.of(long amount, TemporalUnit unit)
:通过指定数量和时间单位来创建Duration
对象。
Duration duration = Duration.of(2, java.time.temporal.ChronoUnit.HOURS);
System.out.println("自定义时间间隔: " + duration);
获取 Duration
中的值
可以使用 getSeconds()
方法获取 Duration
中的总秒数,使用 toHours()
、toMinutes()
等方法将其转换为不同的时间单位
Duration duration = Duration.of(2, java.time.temporal.ChronoUnit.HOURS);
System.out.println("总秒数: " + duration.getSeconds());
System.out.println("总小时数: " + duration.toHours());
对 Duration
进行操作
Duration duration1 = Duration.of(1, java.time.temporal.ChronoUnit.HOURS);
Duration duration2 = Duration.of(2, java.time.temporal.ChronoUnit.HOURS);
Duration sumDuration = duration1.plus(duration2);
Duration diffDuration = duration1.minus(duration2);
System.out.println("相加后的间隔: " + sumDuration);
System.out.println("相减后的间隔: " + diffDuration);
Period
Period
类用于以年、月、日的方式表示日期之间的间隔,它主要处理基于日期(年、月、日)的时间量,适用于处理诸如人的年龄、两个事件之间的日期差等场景。
创建 Period
对象
Period.between(LocalDate startDate, LocalDate endDate)
:根据两个LocalDate
对象计算它们之间的日期间隔。
import java.time.LocalDate;
import java.time.Period;
public class PeriodExample {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2020, 1, 1);
LocalDate endDate = LocalDate.of(2023, 12, 31);
Period period = Period.between(startDate, endDate);
System.out.println("日期间隔: " + period);
}
}
Period.of(int years, int months, int days)
:通过指定年、月、日的值来创建Period
对象。
Period period = Period.of(2, 3, 10);
System.out.println("自定义日期间隔: " + period);
获取 Period
中的值
可以使用 getYears()
、getMonths()
和 getDays()
方法分别获取 Period
中的年、月、日部分
Period period = Period.of(2, 3, 10);
System.out.println("年: " + period.getYears());
System.out.println("月: " + period.getMonths());
System.out.println("日: " + period.getDays());
对 Period
进行操作
plus(Period other)
:将两个Period
对象相加。minus(Period other)
:从当前Period
中减去另一个Period
对象。Duration.between(Temporal startInclusive, Temporal endExclusive)
:根据两个Temporal
对象(如LocalTime
、LocalDateTime
或Instant
)计算它们之间的时间间隔。Duration.of(long amount, TemporalUnit unit)
:通过指定数量和时间单位来创建Duration
对象。plus(Duration other)
:将两个Duration
对象相加。minus(Duration other)
:从当前Duration
中减去另一个Duration
对象。
总结
Period
用于处理基于日期的时间间隔,以年、月、日为单位。Duration
用于处理基于时间的时间间隔,以秒和纳秒为单位。
新旧日期时间 API 对比
- 线程安全性:旧的
Date
和Calendar
类不是线程安全的,而新的日期时间 API 中的类都是不可变的,是线程安全的。 - 易用性:新的日期时间 API 提供了更丰富的方法和更清晰的设计,使用起来更加方便。
- 功能完整性:新的 API 对时区、日期计算等功能的支持更加完善。