简介
在之前的Java中,日期类型的 java.util.Date类、java.util.Calendar类的起始日期为1900年,易用性较差,因此在 Java 8 增加了对于日期方面的改进工作。
新增日期类:
类名 | 说明 |
---|---|
LocalDate | 日期 |
LocalTime | 时间 |
LocalDateTime | 日期+时间 |
ChronoField | 枚举,日期、时间类型 |
Instant | 机器时间,以纳秒为单位 |
Duration | 日期范围 |
Period | 时间范围 |
TemporalAdjusters | 灵活的日期操作 |
DateTimeFormatter | 日期时间格式 |
实用的操作:
操作 |
---|
1.日期比较大小 |
2.获取两个日期之间的天数、小时数、分钟数 |
3.日期加减 |
新增日期类
LocalDate 日期
java.time.LocalDate,该类的示例是一个不可变对象,它只提供了简单的日期,并不含时间信息,也不附带时区相关信息。
举个栗子:
public static void main(String[] args) {
LocalDate date = LocalDate.of(2014, 3, 18); // 2014-03-18
int year = date.getYear(); // 2014
Month month = date.getMonth(); // MARCH
int day = date.getDayOfMonth(); // 18
DayOfWeek dow = date.getDayOfWeek(); // TUESDAY
int len = date.lengthOfMonth(); // 31 (三月的天数)
boolean leap = date.isLeapYear(); // false (不是闰年)
date = LocalDate.now(); // 当天日期
int year2 = date.get(ChronoField.YEAR); // 2020
int month2 = date.get(ChronoField.MONTH_OF_YEAR); // 3
int day2 = date.get(ChronoField.DAY_OF_MONTH); // 23
// 如果不能解析为合法的LocalDate对象,会抛出DateTimeParseException
date = LocalDate.parse("2014-03-18"); // 2014-03-18
}
补充:
- 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
- 表示时间点的日期 - 时间类的通用方法:
方法名 | 是否为静态方法 | 描述 |
---|---|---|
from | 是 | 依据传入的 Temporal 对象创建对象实例 |
now | 是 | 依据系统时钟创建 Temporal 对象 |
of | 是 | 由 Temporal 对象的某个部分创建该对象的实例 |
parse | 是 | 由字符串创建 Temporal 对象的实例 |
atOffset | 否 | 将 Temporal 对象和某个时区偏移相结合 |
atZone | 否 | 将 Temporal 对象和某个时区相结合 |
format | 否 | 使用某个指定的格式器将Temporal对象转换为字符串(Instant类不提供该方法) |
get | 否 | 读取 Temporal 对象的某一部分的值 |
minus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值减去一定的时长创建该副本 |
plus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值加上一定的时长创建该副本 |
with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |
LocalTime 时间
java.time.LocalTime,表示一天中的时间,比如13:45:20
举个栗子:
public static void main(String[] args) {
LocalTime time = LocalTime.of(13, 45, 20); // 13:45:20
int hour = time.getHour(); // 13
int minute = time.getMinute(); // 45
int second = time.getSecond(); // 20
time = LocalTime.now(); // 当前时间
// 如果不能解析为合法的LocalTime对象,会抛出DateTimeParseException
time = LocalTime.parse("13:45:20"); // 13:45:20
}
补充:
- 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
- 表示时间点的日期 - 时间类的通用方法:
方法名 | 是否为静态方法 | 描述 |
---|---|---|
from | 是 | 依据传入的 Temporal 对象创建对象实例 |
now | 是 | 依据系统时钟创建 Temporal 对象 |
of | 是 | 由 Temporal 对象的某个部分创建该对象的实例 |
parse | 是 | 由字符串创建 Temporal 对象的实例 |
atOffset | 否 | 将 Temporal 对象和某个时区偏移相结合 |
atZone | 否 | 将 Temporal 对象和某个时区相结合 |
format | 否 | 使用某个指定的格式器将Temporal对象转换为字符串(Instant类不提供该方法) |
get | 否 | 读取 Temporal 对象的某一部分的值 |
minus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值减去一定的时长创建该副本 |
plus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值加上一定的时长创建该副本 |
with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |
LocalDateTime 日期+时间
java.time.LocalDateTime,合并日期和时间。
举个栗子:
public static void main(String[] args) {
LocalDate date = LocalDate.parse("2014-03-18");
LocalTime time = LocalTime.parse("13:45:20");
// 2013-03-18T13:45:20
LocalDateTime dateTime1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20)
LocalDateTime dateTime2 = LocalDateTime.of(date, time);
LocalDateTime dateTime3 = date.atTime(13, 45, 20);
LocalDateTime dateTime4 = date.atTime(time);
LocalDateTime dateTime5 = time.atDate(date);
LocalDate date1 = dateTime1.toLocalDate(); // 2014-03-18
LocalTime time1 = dateTime1.toLocalTime(); // 13:45:20
}
补充:
-
LocalDateTime和Instant是为不同的目的而设计的,一个是为了便于人阅读使用,另一个是为了便于机器处理。
-
表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
-
表示时间点的日期 - 时间类的通用方法:
方法名 | 是否为静态方法 | 描述 |
---|---|---|
from | 是 | 依据传入的 Temporal 对象创建对象实例 |
now | 是 | 依据系统时钟创建 Temporal 对象 |
of | 是 | 由 Temporal 对象的某个部分创建该对象的实例 |
parse | 是 | 由字符串创建 Temporal 对象的实例 |
atOffset | 否 | 将 Temporal 对象和某个时区偏移相结合 |
atZone | 否 | 将 Temporal 对象和某个时区相结合 |
format | 否 | 使用某个指定的格式器将Temporal对象转换为字符串(Instant类不提供该方法) |
get | 否 | 读取 Temporal 对象的某一部分的值 |
minus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值减去一定的时长创建该副本 |
plus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值加上一定的时长创建该副本 |
with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |
ChronoField 取值类型
java.time.temporal.ChronoField,实现了TemporalField接口,TemporalField定义了如何访问Temporal对象某个字段的值,所以可以很方便地使用get方法得到枚举元素的值。常用枚举值如下:
枚举值 | 说明 |
---|---|
ChronoField.YEAR | 年 |
ChronoField.MONTH_OF_YEAR | 月(按一年有多少月算) |
ChronoField.DAY_OF_MONTH | 日(按一月有多少日算) |
ChronoField.HOUR_OF_AMPM | 时(12小时制) |
ChronoField.HOUR_OF_DAY | 时(24小时制) |
ChronoField.MINUTE_OF_HOUR | 分(按一小时有多少分钟算) |
ChronoField.SECOND_OF_MINUTE | 秒(按一分钟有多少秒算) |
举个栗子:
public static void main(String[] args) {
LocalDate date = LocalDate.parse("2014-03-18");
int year2 = date.get(ChronoField.YEAR); // 2014
int month2 = date.get(ChronoField.MONTH_OF_YEAR); // 3
int day2 = date.get(ChronoField.DAY_OF_MONTH); // 18
LocalTime time = LocalTime.parse("13:45:20");
int hour2 = time.get(ChronoField.HOUR_OF_DAY); // 13
int minute2 = time.get(ChronoField.MINUTE_OF_HOUR); // 45
int second2 = time.get(ChronoField.SECOND_OF_MINUTE); // 20
}
Instant 系统时间
java.time.Instant,以Unix元年时间(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的秒数进行计算。
举个栗子:
public static void main(String[] args) {
// 在1970年1月1日0时,加3秒
Instant instant1 = Instant.ofEpochSecond(3);
// 在1970年1月1日0时,加2秒后再加上10亿纳秒(1s)
Instant instant2 = Instant.ofEpochSecond(2, 1_000_000_000);
// 在1970年1月1日0时,加4秒前再加上10亿纳秒(1s)
Instant instant3 = Instant.ofEpochSecond(4, -1_000_000_000);
}
注意:
Instant是机器时间,没有日、月、年的概念,所以当执行如下代码的时候会抛出UnsupportedTemporalTypeException异常。
Instant.now().get(ChronoField.DAY_OF_MONTH);
补充:
-
LocalDateTime和Instant是为不同的目的而设计的,一个是为了便于人阅读使用,另一个是为了便于机器处理。
-
表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
-
表示时间点的日期 - 时间类的通用方法:
方法名 | 是否为静态方法 | 描述 |
---|---|---|
from | 是 | 依据传入的 Temporal 对象创建对象实例 |
now | 是 | 依据系统时钟创建 Temporal 对象 |
of | 是 | 由 Temporal 对象的某个部分创建该对象的实例 |
parse | 是 | 由字符串创建 Temporal 对象的实例 |
atOffset | 否 | 将 Temporal 对象和某个时区偏移相结合 |
atZone | 否 | 将 Temporal 对象和某个时区相结合 |
format | 否 | 使用某个指定的格式器将Temporal对象转换为字符串(Instant类不提供该方法) |
get | 否 | 读取 Temporal 对象的某一部分的值 |
minus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值减去一定的时长创建该副本 |
plus | 否 | 创建 Temporal 对象的一个副本,通过将当前 Temporal 对象的值加上一定的时长创建该副本 |
with | 否 | 以该 Temporal 对象为模板,对某些状态进行修改创建该对象的副本 |
Duration 日期范围
java.time.Duration, 主要用于以纳秒、秒、分钟、小时来衡量时间的长短。
举个栗子:
public static void main(String[] args) {
// duration : PT3M
LocalTime time1 = LocalTime.parse("13:45:20");
LocalTime time2 = LocalTime.parse("13:48:20");
Duration duration1 = Duration.between(time1, time2);
// 获取间隔分钟数
long minutes = duration1.toMinutes();
LocalDateTime dateTime1 = LocalDateTime.parse("2013-03-18T13:45:20");
LocalDateTime dateTime2 = LocalDateTime.parse("2013-03-18T13:48:20");
Duration duration2 = Duration.between(dateTime1, dateTime2);
Instant instant1 = Instant.ofEpochSecond(0);
Instant instant2 = Instant.ofEpochSecond(180);
Duration duration3 = Duration.between(instant1, instant2);
Duration duration4 = Duration.ofMinutes(3);
Duration duration5 = Duration.of(3, ChronoUnit.MINUTES);
}
补充:
日期-时间类中表示时间间隔的通用方法:
方法名 | 是否为静态方法 | 方法描述 |
---|---|---|
between | 是 | 创建两个时间点之间的interval(间隔) |
from | 是 | 由一个临时时间点创建的interval |
of | 是 | 由它的组成部分创建interval的实例 |
parse | 是 | 由字符串创建interval的实例 |
addTo | 否 | 创建该interval的副本,并将其叠加到某个指定的temporal对象 |
get | 否 | 读取该interval的状态 |
isNegative | 否 | 检查该interval是否为负值,不包括零 |
isZero | 否 | 检查该interval的时长是否为零 |
minus | 否 | 通过减去一定的时间创建该interval的副本 |
multipliedBy | 否 | 将interval的值乘以某个标量创建该interval的副本 |
negated | 否 | 以忽略某个时长的方式创建该interval的副本 |
plus | 否 | 以增加某个指定的时长的方式创建该interval的副本 |
subtractFrom | 否 | 以指定的temporal对象中减去该interval |
Period 时间范围
java.time.Period, 主要用于以纳秒、秒、分钟、小时来衡量时间的长短。
举个栗子:
public static void main(String[] args) {
LocalDate date1 = LocalDate.parse("2014-03-18");
LocalDate date2 = LocalDate.parse("2014-03-19");
Period period = Period.between(date1, date2);
Period tenDays = Period.ofDays(10);
Period threeWeeks = Period.ofWeeks(3);
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
}
补充:
日期-时间类中表示时间间隔的通用方法:
方法名 | 是否为静态方法 | 方法描述 |
---|---|---|
between | 是 | 创建两个时间点之间的interval(间隔) |
from | 是 | 由一个临时时间点创建的interval |
of | 是 | 由它的组成部分创建interval的实例 |
parse | 是 | 由字符串创建interval的实例 |
addTo | 否 | 创建该interval的副本,并将其叠加到某个指定的temporal对象 |
get | 否 | 读取该interval的状态 |
isNegative | 否 | 检查该interval是否为负值,不包括零 |
isZero | 否 | 检查该interval的时长是否为零 |
minus | 否 | 通过减去一定的时间创建该interval的副本 |
multipliedBy | 否 | 将interval的值乘以某个标量创建该interval的副本 |
negated | 否 | 以忽略某个时长的方式创建该interval的副本 |
plus | 否 | 以增加某个指定的时长的方式创建该interval的副本 |
subtractFrom | 否 | 以指定的temporal对象中减去该interval |
TemporalAdjusters 灵活操作时间
java.time.temporal.TemporalAdjusters,有的时候,你需要进行一些更加复杂的操作,比如,将日起调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,想起传递一个提供了更多定制化选择的TemporalAdjusts对象。
举个栗子:
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2014, 3, 18); // 2014-03-18
LocalDate date2 = date1.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); // 2014-03-23
LocalDate date3 = date2.with(TemporalAdjusters.lastDayOfMonth()); // 2014-03-31
}
补充:
TemporalAdjusters类中的工厂方法:
方法名 | 描述 |
---|---|
dayOfWeekInMonth | 创建一个新的日期,它的值为同一个月中每一周的第几天 |
firstDayOfMonth | 创建一个新的日期,它的值为当月的第一天 |
firstDayOfNextMonth | 创建一个新的日期,它的值为下月的第一天 |
firstDayOfNextYear | 创建一个新的日期,它的值为明年的第一天 |
firstDayOfYear | 创建一个新的日期,它的值为当年的第一天 |
firstInMonth | 创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值 |
lastDayOfMonth | 创建一个新的日期,它的值为当月的最后一天 |
lastDayOfNextMonth | 创建一个新的日期,它的值为下月的最后一天 |
lastDayOfNextYear | 创建一个新的日期,它的值为明年的最后一天 |
lastDayOfYear | 创建一个新的日期,它的值为今年的最后一天 |
lastInMonth | 创建一个新的日期,它的值为同一个月中,最后一个符合星期几要求的值 |
next/previous | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期 |
nextOrSame/previousOrSame | 创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象 |
DateTimeFormatter 日期时间格式化
java.time.format.DateTimeFormatter,格式化日期。
举个栗子:
public static void main(String[] args) {
// 示例1
LocalDate date = LocalDate.of(2014, 3, 18);
String s1 = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
// 示例2
LocalDate date1 = LocalDate.parse("20140318",
DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18",
DateTimeFormatter.ISO_LOCAL_DATE);
// 示例3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
date1 = LocalDate.of(2014, 3, 18);
String formattedDate = date1.format(formatter);
date2 = LocalDate.parse(formattedDate, formatter);
// 示例4 - 2020/12/19 13:54:13.934
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS");
String dateTime = LocalDateTime.now().format(dateTimeFormatter);
}
实用操作
1.日期比较大小
示例 | 说明 |
---|---|
date1.isBefore(date2); | date1 < date2 |
date1.isAfter(date2); | date1 > date2 |
date1.isEqual(date2); | date1 = date2 |
2.获取两个日期之间的天数、小时数、分钟数
public static void main(String[] args) {
LocalDateTime localDateTime1 = LocalDateTime.of(2019, 10, 1, 0, 0, 0);
LocalDateTime localDateTime2 = LocalDateTime.of(2019, 10, 2, 2, 3, 4);
// 天数
long days = Duration.between(localDateTime1, localDateTime2).toDays();
// 小时数
long hours = Duration.between(localDateTime1, localDateTime2).toHours() % 24;
// 分钟数
long minutes = Duration.between(localDateTime1, localDateTime2).toMinutes() % 60;
// 秒数
long seconds = Duration.between(localDateTime1, localDateTime2).getSeconds() % 60;
String result = String.format("两个时间相隔了%d天%d小时%d分钟%d秒", days, hours, minutes, seconds);
System.out.println("result: " + result);
}
输出结果:
result: 两个时间相隔了1天2小时3分钟4秒
3.日期加减
日期加 | 日期减 | 说明 |
---|---|---|
dateTime.plusDays(1); | dateTime.minusDays(1); | 加(减)1天 |
dateTime.plusHours(1); | dateTime.minusHours(1); | 加(减)1个小时 |
dateTime.plusMinutes(1); | dateTime.minusMinutes(1); | 加(减)1分钟 |
dateTime.plusSeconds(1); | dateTime.minusSeconds(1); | 加(减)1秒 |
dateTime.plusWeeks(1); | dateTime.minusWeeks(1); | 加(减)1周 |
dateTime.plusMonths(1); | dateTime.minusMonths(1); | 加(减)1个月 |
dateTime.plusYears(1); | dateTime.minusYears(1); | 加(减)1年 |
public static void main(String[] args) {
LocalDateTime dateTime = LocalDateTime.of(2019, 10, 1, 0, 0, 0);
dateTime = dateTime.plusDays(1);
String result = dateTime.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
System.out.println("result: " + result);
}
输出结果
result: 2019年10月02日