在Java 8中,JDK引入了全新的时间日期API(java.time
包),目的是替代旧的java.util.Date
、java.util.Calendar
等类,提供更安全、更高效、更易用的方式来处理日期和时间。LocalDate
、LocalTime
和LocalDateTime
是其中三个非常重要的类,它们是java.time
包中的核心类,分别用来表示日期、时间和日期时间。
java.time
包中的核心类
Instant
和LocalDateTime
互相转换的规则LocalDate类表示没有时间部分的日期,精确到年、月、日。它不包含时区信息,也不包括具体的时间部分。
public class LocalDateTest {
public static void main(String[] args) {
// 1. 使用now()方法获取当前日期(默认使用系统时区)
LocalDate currentDate = LocalDate.now();
System.out.println("Current date: " + currentDate);
// 2. 使用指定的年月日创建日期
LocalDate date = LocalDate.of(2024, 10, 13);
System.out.println("Specific date: " + date);
// 3. 从字符串解析日期(字符串格式必须符合ISO-8601标准,如yyyy-MM-dd)
LocalDate dateFromString = LocalDate.parse("2024-11-13");
System.out.println("Parsed date: " + dateFromString);
}
}
Current date: 2024-11-13
Specific date: 2024-10-13
Parsed date: 2024-11-13
public class LocalDateTest {
public static void main(String[] args) {
// 1. 使用now()方法获取当前日期(默认使用系统时区)
LocalDate currentDate = LocalDate.now();
System.out.println("Current date: " + currentDate);
// 2. 常用方法
// 获取日期的各个部分
System.out.println("当前日期所属年份:" + currentDate.getYear());
System.out.println("当前日期所属月份(英文):" + currentDate.getMonth());
System.out.println("当前日期所属月份(数字):" + currentDate.getMonthValue());
System.out.println("当前日期是本年第几天:" + currentDate.getDayOfYear());
System.out.println("当前日期是本月第几天:" + currentDate.getDayOfMonth());
System.out.println("当前日期是本周第几天(英文星期几):" + currentDate.getDayOfWeek());
// ...
}
}
Current date: 2024-11-13
当前日期所属年份:2024
当前日期所属月份(英文):NOVEMBER
当前日期所属月份(数字):11
当前日期是本年第几天:318
当前日期是本月第几天:13
当前日期是本周第几天(英文星期几):WEDNESDAY
和LocalDate的创建类似
// 1. 使用now()方法获取当前时间(默认使用系统时区)
LocalTime currentTime = LocalTime.now();
System.out.println("Current time: " + currentTime);
// 2. 使用指定的 时分秒 创建时间
LocalTime time = LocalTime.of(16, 10, 13);
System.out.println("Specific time: " + time);
// 3. 从字符串解析时间(字符串格式必须符合ISO-8601标准,如HH:mm:ss)
LocalTime timeFromString = LocalTime.parse("16:10:13");
System.out.println("Parsed time: " + timeFromString);
Current time: 16:31:54.965
Specific time: 16:10:13
Parsed time: 16:10:13
public static void main(String[] args) {
// 1. 使用now()方法获取当前时间(默认使用系统时区)
LocalTime currentTime = LocalTime.now();
System.out.println("Current time: " + currentTime);
// 2. 常用方法
// 获取时间的各个部分
System.out.println("获取当前时间的小时:" + currentTime.getHour());
System.out.println("获取当前时间的分钟:" + currentTime.getMinute());
System.out.println("获取当前时间的秒:" + currentTime.getSecond());
System.out.println("获取当前时间的纳秒:" + currentTime.getNano());
// ...
}
Current time: 16:31:54.965
获取当前时间的小时:16
获取当前时间的分钟:31
获取当前时间的秒:54
获取当前时间的纳秒:965000000
创建方法和前面的大同小异
public class LocalDateTimeTest {
public static void main(String[] args) {
// 1. 使用now()方法获取当前日期时间(默认使用系统时区)
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current dateTime: " + currentDateTime); // 2024-11-13T16:40:59.697
// 2. 使用指定的 年月日 时分秒 创建日期时间
LocalDateTime dateTime = LocalDateTime.of(2024,11,13,16, 10, 13);
System.out.println("Specific dateTime: " + dateTime); // 2024-11-13T16:10:13
// 3. 从字符串解析时间(字符串格式必须符合ISO-8601标准,如HH:mm:ss)
LocalDateTime dateTimeFromString = LocalDateTime.parse("2024-11-13T10:15:30");
System.out.println("Parsed dateTime: " + dateTimeFromString); // 2024-11-13T10:15:30
// 4. 常用方法
// 获取日期时间的各个部分
System.out.println("当前日期所属年份:" + currentDateTime.getYear()); // 2024
System.out.println("当前日期所属月份(英文):" + currentDateTime.getMonth()); // NOVEMBER
System.out.println("当前日期所属月份(数字):" + currentDateTime.getMonthValue()); // 11
System.out.println("当前日期是本年第几天:" + currentDateTime.getDayOfYear()); // 318
System.out.println("当前日期是本月第几天:" + currentDateTime.getDayOfMonth()); // 13
System.out.println("当前日期是本周第几天(英文星期几):" + currentDateTime.getDayOfWeek()); // WEDNESDAY
System.out.println("获取当前日期时间的小时:" + currentDateTime.getHour()); // 16
System.out.println("获取当前日期时间的分钟:" + currentDateTime.getMinute()); // 40
System.out.println("获取当前日期时间的秒:" + currentDateTime.getSecond()); // 59
System.out.println("获取当前日期时间的纳秒:" + currentDateTime.getNano()); // 697000000
}
}
public class LocalDateTimeTest {
public static void main(String[] args) {
// 1. 使用now()方法获取当前日期时间(默认使用系统时区)
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current dateTime: " + currentDateTime); // 2024-11-13T16:40:59.697
System.out.println("===========时间日期的加减============");
System.out.println("当前日期时间:" + currentDateTime);
System.out.println(currentDateTime + "--->增加2年后的时间是:" + currentDateTime.plusYears(2));
System.out.println(currentDateTime + "--->增加3月后的时间是:" + currentDateTime.plusMonths(3));
System.out.println(currentDateTime + "--->减少1年后的时间是:" + currentDateTime.minusYears(1));
System.out.println(currentDateTime + "--->减少13月后的时间是:" + currentDateTime.minusMonths(13));
System.out.println(currentDateTime + "--->增加1小时后的时间是:" + currentDateTime.plusHours(1));
System.out.println(currentDateTime + "--->增加30分钟后的时间是:" + currentDateTime.plusMinutes(30));
}
}
Current dateTime: 2024-11-13T16:49:22.260
===========时间日期的加减============
当前日期时间:2024-11-13T16:49:22.260
2024-11-13T16:49:22.260--->增加2年后的时间是:2026-11-13T16:49:22.260
2024-11-13T16:49:22.260--->增加3月后的时间是:2025-02-13T16:49:22.260
2024-11-13T16:49:22.260--->减少1年后的时间是:2023-11-13T16:49:22.260
2024-11-13T16:49:22.260--->减少13月后的时间是:2023-10-13T16:49:22.260
2024-11-13T16:49:22.260--->增加1小时后的时间是:2024-11-13T17:49:22.260
2024-11-13T16:49:22.260--->增加30分钟后的时间是:2024-11-13T17:19:22.260
这里需要注意的是,LocalDate、LocalTime、LocalDateTime类的实例是不可变的,在对象上进行日期和时间的加减,不改变原有对象的值,这里是复制了一个新的对象来进行修改的,修改后的对象和原对象是两个不同的对象。
public static void main(String[] args) {
// 时间1
LocalDateTime currentDateTime1 = LocalDateTime.now();
// 时间2
LocalDateTime currentDateTime2 = LocalDateTime.parse("2023-10-10T01:01:01");
System.out.println("时间1在时间2前面吗?-----》" + currentDateTime1.isBefore(currentDateTime2));
System.out.println("时间1在时间2后面吗?-----》" + currentDateTime1.isAfter(currentDateTime2));
}
时间1在时间2前面吗?-----》false
时间1在时间2后面吗?-----》true
jdk8中,提供了Duration
和Period
类来计算日期时间的差值
Duration类:比较两个时间(LocalTime
)的差值
Period类:比较两个日期(LocalDate
)的差值
public class DurationAndPeriodTest {
public static void main(String[] args) {
// Duration类 比较两个时间LocalTime的差值
LocalTime time1 = LocalTime.now();
System.out.println("time1 :" + time1);
LocalTime time2 = LocalTime.of(12, 23, 23);
System.out.println("time2 :" + time2);
Duration duration = Duration.between(time2, time1);
System.out.println("相差的小时数:" + duration.toHours());
System.out.println("相差的分钟数:" + duration.toMinutes());
}
}
time1 :17:22:00.981
time2 :12:23:23
相差的小时数:4
相差的分钟数:298
Duration.between()方法是用第二个参数减去第一个参数的值,这里注意位置,避免得出的结果是负数
public class DurationAndPeriodTest {
public static void main(String[] args) {
// Period类 比较两个日期LocalDate的差值
LocalDate date1 = LocalDate.now();
System.out.println("date1 :" + date1);
LocalDate date2 = LocalDate.of(2022, 9, 1);
System.out.println("date2 :" + date2);
Period period = Period.between(date2, date1);
System.out.println("相差的年数:" + period.getYears());
System.out.println("相差的天数:" + period.getDays());
System.out.println("相差的月数:" + period.getMonths());
}
}
date1 :2024-11-13
date2 :2022-09-01
相差的年数:2
相差的天数:12
相差的月数:2
注意,这里有个坑,Period在比较的时候,并不是计算总的差值,而是各字段上的时间差,这里的月份和天数都不对,这就有点难受了。
Period
的坑及解决办法对于获取相差的月份来说,Period
给了toTotalMonths()
方法,获取总相差的月份
public long toTotalMonths() {
return years * 12L + months; // no overflow
}
// Period类 比较两个日期LocalDate的差值
LocalDate date1 = LocalDate.now();
System.out.println("date1 :" + date1);
LocalDate date2 = LocalDate.of(2022, 9, 1);
System.out.println("date2 :" + date2);
Period period = Period.between(date2, date1);
System.out.println("总的相差的月份数:" + period.toTotalMonths());
date1 :2024-11-13
date2 :2022-09-01
总的相差的月份数:26
对于天数的统计,可以用ChronoUnit.DAYS.between()
// Period类 比较两个日期LocalDate的差值
LocalDate date1 = LocalDate.now();
System.out.println("date1 :" + date1);
LocalDate date2 = LocalDate.of(2022, 9, 1);
System.out.println("date2 :" + date2);
Period period = Period.between(date2, date1);
System.out.println("相差的年数:" + period.getYears());
System.out.println("相差的天数:" + period.getDays());
System.out.println("相差的月数:" + period.getMonths());
System.out.println("总的相差的月份数:" + period.toTotalMonths());
long days = ChronoUnit.DAYS.between(date2, date1);
System.out.println("总的相差的天数:" + days);
date1 :2024-11-13
date2 :2022-09-01
总的相差的月份数:26
总的相差的天数:804
DateTimeFormatter
是Java 8中用于格式化和解析日期时间的工具类。专门用于格式化和解析LocalDate
、LocalTime
、LocalDateTime
以及ZonedDateTime
等日期和时间对象。通过DateTimeFormatter
,我们可以将这些日期和时间对象转化为指定格式的字符串,也可以将符合特定格式的字符串解析为日期和时间对象。
在DateTimeFormatter
类中,预定义了很多种标准格式
比如DateTimeFormatter.ISO_LOCAL_DATE
用于格式化或解析LocalDate
对象,格式为 yyyy-MM-dd
public static final DateTimeFormatter ISO_LOCAL_DATE;
static {
ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
使用DateTimeFormatter.ofPattern()
自定义日期时间格式化类型,
日期时间对象使用format()
方法进行格式化输出为字符串
使用parse()
方法解析字符串为时间日期对象
public static void main(String[] args) {
LocalDateTime dateTime = LocalDateTime.now();
System.out.println("当前日期时间:" + dateTime);
// 设置格式化样式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
// 格式化
String formattedDateTime = dateTime.format(formatter);
System.out.println("格式化后的日期时间对象: " + formattedDateTime);
// 解析
String dateStr = "2024-11-13 18:15:53";
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDate dateTime1 = LocalDate.parse(dateStr, formatter2);
System.out.println("解析后的日期对象:" + dateTime1);
}
当前日期时间:2024-11-13T18:21:54.663
格式化后的日期时间对象: 2024年11月13日 18:21:54
解析后的日期对象:2024-11-13
DateTimeFormatter
是不可变的和线程安全的,因此它可以被多个线程共享。在实际应用中,建议创建一个DateTimeFormatter
实例并在整个应用中复用,而不是每次需要格式化或解析时都创建一个新的实例。
前面提到,LocalDate
,LocalTime
,LocalDateTime
是不带时区的,如果要加入时区,与之对应的有三个类,分别是ZonedDate
、ZonedTime
、ZonedDateTime
类
举个例子
public static void main(String[] args) {
// 使用计算机默认时区
ZonedDateTime defaultNow = ZonedDateTime.now();
System.out.println("当前本地时间:" + defaultNow);
// 世界标准时间
ZonedDateTime zdt = ZonedDateTime.now(Clock.systemUTC());
System.out.println("世界标准时间: " + zdt);
System.out.println("==========改变时区==========");
ZonedDateTime zonedDateTime = zdt.withZoneSameInstant(ZoneId.systemDefault());
System.out.println("设置为系统默认时区后的时间:" + zonedDateTime);
ZonedDateTime zonedDateTime1 = zdt.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
System.out.println("设置为东八区后的时间:" + zonedDateTime1);
}
当前本地时间:2024-11-13T18:36:45.277+08:00[Asia/Shanghai]
世界标准时间: 2024-11-13T10:36:45.278Z
==========改变时区==========
设置为系统默认时区后的时间:2024-11-13T18:36:45.278+08:00[Asia/Shanghai]
设置为东八区后的时间:2024-11-13T18:36:45.278+08:00[Asia/Shanghai]
这里主要说下 Date
与 LocalDateTime
,LocalDate
进行互转的情况,而对于 LocalTime
和 Date
的转换其实意义不大,这里就不再赘述。
先将 Date
对象转换为 Instant
,然后设置时区,进而转为 LocalDateTime
Date date = new Date();
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
先设置时区,再转为 Instant
,最后借助 Date.from
转为 Date
类型
LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
这个和 Date
转为 localDateTime
类似,只是转为 LocalDate
时去掉了时间部分
Date date = new Date();
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate
是没有时间部分的,转为 Date
时先通过atStartOfDay
设置时间为一天的开始,进而转为 Date
类型。
LocalDate localDate = LocalDate.now();
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());