Java8 新的日期和时间(LocalDateTime、DateTimeFormatter等)

简介

在之前的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
}

补充:

  1. 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
  2. 表示时间点的日期 - 时间类的通用方法:
方法名是否为静态方法描述
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
}

补充:

  1. 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;
  2. 表示时间点的日期 - 时间类的通用方法:
方法名是否为静态方法描述
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
}

补充:

  1. LocalDateTime和Instant是为不同的目的而设计的,一个是为了便于人阅读使用,另一个是为了便于机器处理。

  2. 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;

  3. 表示时间点的日期 - 时间类的通用方法:

方法名是否为静态方法描述
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);

补充:

  1. LocalDateTime和Instant是为不同的目的而设计的,一个是为了便于人阅读使用,另一个是为了便于机器处理。

  2. 表示时间点的LocalDate、LocalTime、LocalDateTime、Instant 均实现自 Temporal接口;

  3. 表示时间点的日期 - 时间类的通用方法:

方法名是否为静态方法描述
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: 两个时间相隔了12小时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: 20191002
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不愿放下技术的小赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值