JDK 1.8 完整日期时间Api

JDK 1.8 完整日期时间Api (文末附示例)
        </h1>
        <div class="clear"></div>
        <div class="postBody">

一、背景

jdk 1.8 之前, Java 时间使用java.util.Datejava.util.Calendar 类。

Date today = new Date();
System.out.println(today);

// 转为字符串
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
String todayStr = sdf.format(today);
System.out.println(todayStr);

Date 的几个问题:

  1. 如果不格式化,Date打印出的日期可读性差;
  2. 可以使用 SimpleDateFormat 对时间进行格式化,但 SimpleDateFormat 是线程不安全的(阿里巴巴开发手册中禁用static修饰SimpleDateFormat);
  3. Date对时间处理比较麻烦,比如想获取某年、某月、某星期,以及 n 天以后的时间,如果用Date来处理的话真是太难了,并且 Date 类的 getYear()getMonth() 这些方法都被弃用了;

二、JDK 1.8 新的日期时间类型

Java8引入的新的一系列API,对时间日期的处理提供了更好的支持,清楚的定义了时间日期的一些概念,比如说,瞬时时间(Instant),持续时间(duration),日期(date),时间(time),时区(time-zone)以及时间段(Period)。

  1. LocalDate:不包含时间的日期,比如2019-10-14。可以用来存储生日,周年纪念日,入职日期等。
  2. LocalTime:与LocalDate想对照,它是不包含日期的时间。
  3. LocalDateTime:包含了日期及时间,没有偏移信息(时区)。
  4. ZonedDateTime:包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
  5. Instant:时间戳,与System.currentTimeMillis()类似。
  6. Duration:表示一个时间段。
  7. Period:用来表示以年月日来衡量一个时间段。
  8. DateTimeFormatter:新的日期解析格式化类。

2.1 LocalDate

LocalDate类内只包含日期,不包含具体时间。只需要表示日期而不包含时间,就可以使用它。

public static void localDate() {
    //获取当前年月日
    LocalDate today = LocalDate.now();
    System.out.println("当前年月日:" + today);
<span class="hljs-comment">// 获取年的两种方式</span>
<span class="hljs-keyword">int</span> thisYear = today.getYear();
<span class="hljs-keyword">int</span> thisYearAnother = today.get(ChronoField.YEAR);
System.out.println(<span class="hljs-string">"今年是"</span> + thisYear + <span class="hljs-string">"年"</span>);
System.out.println(<span class="hljs-string">"今年是"</span> + thisYearAnother + <span class="hljs-string">"年"</span>);

<span class="hljs-comment">// 获取月</span>
Month thisMonth = today.getMonth();
System.out.println(thisMonth.toString());
<span class="hljs-comment">// 这是今年的第几个月(两种写法)</span>
<span class="hljs-keyword">int</span> monthOfYear = today.getMonthValue();
<span class="hljs-comment">// int monthOfYear = today.get(ChronoField.MONTH_OF_YEAR);</span>
System.out.println(<span class="hljs-string">"这个月是今年的第"</span> + monthOfYear + <span class="hljs-string">"个月"</span>);
<span class="hljs-comment">// 月份的天数</span>
<span class="hljs-keyword">int</span> length = today.lengthOfMonth();
System.out.println(<span class="hljs-string">"这个月有"</span> + length + <span class="hljs-string">"天"</span>);

<span class="hljs-comment">// 获取日的两种方式</span>
<span class="hljs-keyword">int</span> thisDay = today.getDayOfMonth();
<span class="hljs-keyword">int</span> thisDayAnother = today.get(ChronoField.DAY_OF_MONTH);
System.out.println(<span class="hljs-string">"今天是这个月的第"</span> + thisDay + <span class="hljs-string">"天"</span>);
System.out.println(<span class="hljs-string">"今天是这个月的第"</span> + thisDayAnother + <span class="hljs-string">"天"</span>);

<span class="hljs-comment">// 获取星期</span>
DayOfWeek thisDayOfWeek = today.getDayOfWeek();
System.out.println(thisDayOfWeek.toString());
<span class="hljs-comment">// 今天是这周的第几天</span>
<span class="hljs-keyword">int</span> dayOfWeek = today.get(ChronoField.DAY_OF_WEEK);
System.out.println(<span class="hljs-string">"今天是这周的第"</span> + dayOfWeek + <span class="hljs-string">"天"</span>);

<span class="hljs-comment">// 是否为闰年</span>
<span class="hljs-keyword">boolean</span> leapYear = today.isLeapYear();
System.out.println(<span class="hljs-string">"今年是闰年:"</span> + leapYear);

<span class="hljs-comment">//构造指定的年月日</span>
LocalDate anotherDay = LocalDate.of(<span class="hljs-number">2008</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>);
System.out.println(<span class="hljs-string">"指定年月日:"</span> + anotherDay);

}

2.2 LocalTime

LocalTime只会获取时间,不获取日期。LocalTimeLocalDate类似,区别在于LocalDate不包含具体时间,而LocalTime不包含具体日期。

public static void localTime() {
    // 获取当前时间
    LocalTime nowTime = LocalTime.now();
    System.out.println("当前时间:" + nowTime);
<span class="hljs-comment">//获取小时的两种方式</span>
<span class="hljs-keyword">int</span> hour = nowTime.getHour();
<span class="hljs-keyword">int</span> thisHour = nowTime.get(ChronoField.HOUR_OF_DAY);
System.out.println(<span class="hljs-string">"当前时:"</span> + hour);
System.out.println(<span class="hljs-string">"当前时:"</span> + thisHour);


<span class="hljs-comment">//获取分的两种方式</span>
<span class="hljs-keyword">int</span> minute = nowTime.getMinute();
<span class="hljs-keyword">int</span> thisMinute = nowTime.get(ChronoField.MINUTE_OF_HOUR);
System.out.println(<span class="hljs-string">"当前分:"</span> + minute);
System.out.println(<span class="hljs-string">"当前分:"</span> + thisMinute);

<span class="hljs-comment">//获取秒的两种方式</span>
<span class="hljs-keyword">int</span> second = nowTime.getSecond();
<span class="hljs-keyword">int</span> thisSecond = nowTime.get(ChronoField.SECOND_OF_MINUTE);
System.out.println(<span class="hljs-string">"当前秒:"</span> + second);
System.out.println(<span class="hljs-string">"当前秒:"</span> + thisSecond);

<span class="hljs-comment">// 构造指定时间(最多可到纳秒)</span>
LocalTime anotherTime = LocalTime.of(<span class="hljs-number">20</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>);
System.out.println(<span class="hljs-string">"构造指定时间:"</span> + anotherTime);

}

2.3 LocalDateTime

LocalDateTime表示日期和时间组合。可以通过of()方法直接创建,也可以调用LocalDateatTime()方法或LocalTimeatDate()方法将LocalDateLocalTime合并成一个LocalDateTime

public static void localDateTime() {
    // 当前日期和时间
    LocalDateTime today = LocalDateTime.now();
    System.out.println("现在是:" + today);
<span class="hljs-comment">// 创建指定日期和时间</span>
LocalDateTime anotherDay = LocalDateTime.of(<span class="hljs-number">2008</span>, Month.AUGUST, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>);
System.out.println(<span class="hljs-string">"创建的指定时间是:"</span> + anotherDay);

<span class="hljs-comment">// 拼接日期和时间</span>
<span class="hljs-comment">// 使用当前日期,指定时间生成的 LocalDateTime</span>
LocalDateTime thisTime = LocalTime.now().atDate(LocalDate.of(<span class="hljs-number">2008</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>));
System.out.println(<span class="hljs-string">"拼接的日期是:"</span> + thisTime);
<span class="hljs-comment">// 使用当前日期,指定时间生成的 LocalDateTime</span>
LocalDateTime thisDay = LocalDate.now().atTime(LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">24</span>, <span class="hljs-number">12</span>));
System.out.println(<span class="hljs-string">"拼接的日期是:"</span> + thisDay);
<span class="hljs-comment">// 指定日期和时间生成 LocalDateTime</span>
LocalDateTime thisDayAndTime = LocalDateTime.of(LocalDate.of(<span class="hljs-number">2008</span>, <span class="hljs-number">8</span>, <span class="hljs-number">8</span>), LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">24</span>, <span class="hljs-number">12</span>));
System.out.println(<span class="hljs-string">"拼接的日期是:"</span> + thisDayAndTime);

<span class="hljs-comment">// 获取LocalDate</span>
LocalDate todayDate = today.toLocalDate();
System.out.println(<span class="hljs-string">"今天日期是:"</span> + todayDate);

<span class="hljs-comment">// 获取LocalTime</span>
LocalTime todayTime = today.toLocalTime();
System.out.println(<span class="hljs-string">"现在时间是:"</span> + todayTime);

}

2.4 Instant

Instant用于一个获取时间戳,与System.currentTimeMillis()类似,但Instant可以精确到纳秒。

public class InstantDemo {
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{

    <span class="hljs-comment">// 创建Instant对象</span>
    Instant instant = Instant.now();
    <span class="hljs-comment">// 通过ofEpochSecond方法创建(第一个参数表示秒,第二个参数表示纳秒)</span>
    Instant another = Instant.ofEpochSecond(<span class="hljs-number">365</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span>, <span class="hljs-number">100</span>);

    <span class="hljs-comment">// 获取到秒数</span>
    <span class="hljs-keyword">long</span> currentSecond = instant.getEpochSecond();
    System.out.println(<span class="hljs-string">"获取到秒数:"</span> + currentSecond);

    <span class="hljs-comment">// 获取到毫秒数</span>
    <span class="hljs-keyword">long</span> currentMilli = instant.toEpochMilli();
    System.out.println(<span class="hljs-string">"获取到毫秒数:"</span> + currentMilli);
}

}

2.5 Duration

Duration的内部实现与Instant类似,但Duration表示时间段,通过between方法创建,还可以通过of()方法创建。

public static void duration() {
    LocalDateTime from = LocalDateTime.now();
    LocalDateTime to = LocalDateTime.now().plusDays(1);
    // 通过between()方法创建
    Duration duration = Duration.between(from, to);
    // 通过of()方法创建,该方法参数为时间段长度和时间单位。
    // 7天
    Duration duration1 = Duration.of(7, ChronoUnit.DAYS);
    // 60秒
    Duration duration2 = Duration.of(60, ChronoUnit.SECONDS);
}

2.5 Period

PeriodDuration类似,获取一个时间段,只不过单位为年月日,也可以通过of方法和between方法创建,between方法接收的参数为LocalDate

private static void period() {
    // 通过of方法
    Period period = Period.of(2012, 12, 24);
    // 通过between方法
    Period period1 = Period.between(LocalDate.now(), LocalDate.of(2020,12,31));
}

三、时间操作

3.1 时间比较

isBefore()isAfter()判断给定的时间或日期是在另一个时间/日期之前还是之后。
LocalDate为例,LocalDateTime/LocalTime 同理。

public static void compare() {
    LocalDate thisDay = LocalDate.of(2008, 8, 8);
    LocalDate otherDay = LocalDate.of(2018, 8, 8);
<span class="hljs-comment">// 晚于</span>
<span class="hljs-keyword">boolean</span> isAfter = thisDay.isAfter(otherDay);
System.out.println(isAfter);

<span class="hljs-comment">// 早于</span>
<span class="hljs-keyword">boolean</span> isBefore = thisDay.isBefore(otherDay);
System.out.println(isBefore);

}

3.2 增加/减少年数、月数、天数

LocalDateTime为例,LocalDate/LocalTime同理。

public static void plusAndMinus() {
    // 增加
    LocalDateTime today = LocalDateTime.now();
    LocalDateTime nextYearDay = today.plusYears(1);
    System.out.println("下一年的今天是:" + nextYearDay);
    LocalDateTime nextMonthDay = today.plus(1, ChronoUnit.MONTHS);
    System.out.println("下一个月的今天是:" + nextMonthDay);
<span class="hljs-comment">//减少</span>
LocalDateTime lastMonthDay = today.minusMonths(<span class="hljs-number">1</span>);
LocalDateTime lastYearDay = today.minus(<span class="hljs-number">1</span>, ChronoUnit.YEARS);
System.out.println(<span class="hljs-string">"一个月前是:"</span> + lastMonthDay);
System.out.println(<span class="hljs-string">"一年前是:"</span> + lastYearDay);

}

3.3 时间修改

通过with修改时间

public static void edit() {
    LocalDateTime today = LocalDateTime.now();
    // 修改年为2012年
    LocalDateTime thisYearDay = today.withYear(2012);
    System.out.println("修改年后的时间为:" + thisYearDay);
    // 修改为12月
    LocalDateTime thisMonthDay = today.with(ChronoField.MONTH_OF_YEAR, 12);
    System.out.println("修改月后的时间为:" + thisMonthDay);
}

3.4 时间计算

通过 TemporalAdjusters 的静态方法 和 Duration 计算时间

public static void compute() {
    // TemporalAdjusters 的静态方法
    LocalDate today = LocalDate.now();
    // 获取今年的第一天
    LocalDate date = today.with(firstDayOfYear());
    System.out.println("今年的第一天是:" + date);
<span class="hljs-comment">// Duration 计算</span>
LocalDateTime from = LocalDateTime.now();
LocalDateTime to = LocalDateTime.now().plusMonths(<span class="hljs-number">1</span>);
Duration duration = Duration.between(from, to);

<span class="hljs-comment">// 区间统计换算</span>
<span class="hljs-comment">// 总天数</span>
<span class="hljs-keyword">long</span> days = duration.toDays();
System.out.println(<span class="hljs-string">"相隔"</span> + days + <span class="hljs-string">"天"</span>);
<span class="hljs-comment">// 小时数</span>
<span class="hljs-keyword">long</span> hours = duration.toHours();
System.out.println(<span class="hljs-string">"相隔"</span> + hours + <span class="hljs-string">"小时"</span>);
<span class="hljs-comment">// 分钟数</span>
<span class="hljs-keyword">long</span> minutes = duration.toMinutes();
System.out.println(<span class="hljs-string">"相隔"</span> + minutes + <span class="hljs-string">"分钟"</span>);

}

  • TemporalAdjusters的更多方法
方法名称描述
dayOfWeekInMonth()返回同一个月中每周的第几天
firstDayOfMonth()返回当月的第一天
firstDayOfNextMonth()返回下月的第一天
firstDayOfNextYear()返回下一年的第一天
firstDayOfYear()返回本年的第一天
firstInMonth()返回同一个月中第一个星期几
lastDayOfMonth()返回当月的最后一天
lastDayOfNextMonth()返回下月的最后一天
lastDayOfNextYear()返回下一年的最后一天
lastDayOfYear()返回本年的最后一天
lastInMonth()返回同一个月中最后一个星期几
next() / previous()返回后一个/前一个给定的星期几
nextOrSame() / previousOrSame()返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回

四、时间日期格式化

4.1 格式化时间

DateTimeFormatter默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过DateTimeFormatterofPattern方法创建自定义格式化方式。

public static void format() {
    LocalDate today = LocalDate.now();
    // 两种默认格式化时间方式
    String todayStr1 = today.format(DateTimeFormatter.BASIC_ISO_DATE);
    String todayStr2 = today.format(DateTimeFormatter.ISO_LOCAL_DATE);
    System.out.println("格式化时间:" + todayStr1);
    System.out.println("格式化时间:" + todayStr2);
    //自定义格式化
    DateTimeFormatter dateTimeFormatter =   DateTimeFormatter.ofPattern("dd/MM/yyyy");
    String todayStr3 = today.format(dateTimeFormatter);
    System.out.println("自定义格式化时间:" + todayStr3);

}

4.2 解析时间

4.1 中以何种方式格式化,这里需以同样方式解析。

public static void parse() {
    LocalDate date1 = LocalDate.parse("20080808", DateTimeFormatter.BASIC_ISO_DATE);
    LocalDate date2 = LocalDate.parse("2008-08-08", DateTimeFormatter.ISO_LOCAL_DATE);
    System.out.println(date1);
    System.out.println(date2);
}

五、总结

相较于Date 的优势

  1. Instant 的精确度更高,可以精确到纳秒级;
  2. Duration 可以便捷得到时间段内的天数、小时数等;
  3. LocalDateTime 能够快速地获取年、月、日、下一月等;
  4. TemporalAdjusters 类中包含许多常用的静态方法,避免自己编写工具类;
  5. Date的格式化方式SimpleDateFormat相比,DateTimeFormatter是线程安全的。

5.1 示例代码

Github 示例代码

5.2 技术交流

  1. 风尘博客
  2. 风尘博客-掘金
  3. 风尘博客-博客园
  4. Github
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页