1. 概述

JDK1.8中对日期的改动是特别大的,基本上是引入了一套全新的API 。因为由于原来老旧的日期API一直被人诟病,比如java.util.Date,java.util.Calendar等,并且原来所有的日期类都是可变且线程不安全的,导致许多人要么自己手动封装,要么转去使用Joda Time等这类优秀的第三方工具包。所以,在JDK1.8中,JDK官方在Joda Time等优秀工具包基础上,重新提供了一份相当不错的日期API。并且,在JDK1.8中,java.time包中的类是不可变且线程安全的。

JAVA8中的日期API是JSR-310的实现,并且是工作在ISO-8601日历系统基础上的,但我们也可以在非ISO的日历上。

JDK8的日期API大致分为以下几个包:

java.time包:JDK8中的基础包,所有常用的基础类都是这个包的一部分,如LocalDate,LocalTime,LocalDateTime等等,所有这些类都是不可变且线程安全的;

java.time.chrono包:这个包为非ISO的日历系统定义了一些API,我们可以在借助这个包中的一些类扩展我们自己的日历系统;

java.time.format包:这个包很明显了,格式化和解析日期时间对象,一般java.time包中的类都差不多能满足我们的需求了,如果有需要,可以调用这个包下的类自定义解析方式;

java.time.temporal包:这个包很有意思,封装了一些获取某个特定日期和时间的接口,比如某月的第一天或最后一天,并且这些方法都是属于特别好认的方法。

java.time.zone包:这个包就是时区相关的类了。

下面对ISO-8601简单描述一下,参考自百度百科:

ISO-8601: 国际标准化组织制定的日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》,简称为ISO-8601。

日的表示:小时、分和秒都用2位数表示,对UTC时间最后加一个大写字母Z,其他时区用实际时间加时差表示。如UTC时间下午2点30分5秒表示为14:30:05Z或143005Z,当时的北京时间表示为22:30:05+08:00或223005+0800,也可以简化成223005+08。

日期和时间的组合表示:合并表示时,要在时间前面加一大写字母T,如要表示北京时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。

在JDK1.8中,我们经常使用的大约有如下几个类:LocalDate, LocalTime, LocalDateTime, DateTimeFormatter等,所以我们主要看一下这几个类的相关方法。

2. 日期API

2.1 LocalDate

java.time.LocalDate这个类,是用来表示日期的,也仅包含日期,用起来十分方便,方法也十分简单。我们来看一些小例子:

public static void testDate() {

// 1. 获取当前日期(年月日) -----打印输出-----2018-01-29

LocalDate localDate = LocalDate.now();

System.out.println(localDate.toString());

// 2. 根据年月日构建Date ----打印输出-----2018-01-30

LocalDate localDate1 = LocalDate.of(2018, 01, 30);

// 3. 字符串转换日期,默认按照yyyy-MM-dd格式,也可以自定义格式 -----打印输出-----2018-01-30

LocalDate localDate2 = LocalDate.parse("2018-01-30");

// 4. 获取本月第一天 -----打印输出-----2018-01-01

LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());

// 5. 获取本月第二天 -----打印输出-----2018-01-02

LocalDate secondDayOfMonth = localDate.withDayOfMonth(2);

// 6. 获取本月最后一天 -----打印输出-----2018-01-31

LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());

// 7. 明天 -----打印输出----- 2018-01-30

LocalDate tomorrowDay = localDate.plusDays(1L);

// 8. 昨天 -----打印输出----- 2018-01-28

LocalDate yesterday = localDate.minusDays(1L);

// 9. 获取本年第12天 -----打印输出----- 2018-04-30

LocalDate day = localDate.withDayOfYear(120);

// 10. 计算两个日期间的天数

long days = localDate.until(localDate1, ChronoUnit.DAYS);

System.out.println(days);

// 11. 计算两个日期间的周数

long weeks = localDate.until(localDate1, ChronoUnit.WEEKS);

System.out.println(weeks);

}

上面我只列举了几个常用的方法,但实际上LocalDate还有相当多的有意思的方法,基本上我们工作上遇到的与日期有关的操作,都可以通过LocadDate来实现。如果大家在遇到相关问题的时候,可以自行查看API去了解和使用。

2.2 LocalTime

同样,和LocalDate相对应的另一个类就是LocalTime,这个类恰好和LocalDate相反,它表示的全是时间,不包含日期。例子如下:

public static void testTime() {

// 1. 获取当前时间,包含毫秒数 -----打印输出----- 21:03:26.315

LocalTime localTime = LocalTime.now();

// 2. 构建时间 -----打印输出----- 12:15:30

LocalTime localTime1 = LocalTime.of(12, 15, 30);

// 3. 获取当前时间,不包含毫秒数 -----打印输出----- 21:01:56

LocalTime localTime2 = localTime.withNano(0);

// 4. 字符串转为时间,还可以有其他格式,比如12:15, 12:15:23.233

// -----打印输出----- 12:15:30

LocalTime localTime3 = LocalTime.parse("12:15:30");

}

2.3 LocalDateTime

LocalDateTime就和原先的java.util.Date很像了,既包含日期,又包含时间,它经常和DateTimeFormatter一起使用。

public static void testDateTime() {

// 1. 获取当前年月日 时分秒 -----打印输出----- 2018-01-29T21:23:26.774

LocalDateTime localDateTime = LocalDateTime.now();

// 2. 通过LocalDate和LocalTime构建 ----- 打印输出----- 2018-01-29T21:24:41.738

LocalDateTime localDateTime1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());

// 3. 构建年月日 时分秒 -----打印输出----- 2018-01-29T19:23:13

LocalDateTime localDateTime2 = LocalDateTime.of(2018, 01, 29, 19, 23, 13);

// 4. 格式化当前时间 ----打印输出----- 2018/01/29

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");

System.out.println(formatter.format(localDateTime2));

}

使用LocalDateTime的with开头的方法可以设置相应的时间,小时,分钟等,比如:

// 设置分钟数

LocalDateTime localDateTime = LocalDateTime.now().withMinute(23);

需要注意的有两点:

LocalDateTime默认的格式是 2018-01-29T21:23:26.774 这种格式,这可能与我们经常使用的格式不太符合,所以我们可以指定格式。

DateTimeFormatter本身提供了许多静态格式化常量,我们可以参考使用,如果不能满足我们的需求的话,我们可以自定义;

LocalDateTime的toString方法:

@Override

public String toString() {

return date.toString() + 'T' + time.toString();

}

LocalDate,LocalTime,LocalDateTime这三个类基本上处理了大部分的日期,时间。而与这三个类经常结合使用的还有如下几个类:Year,Month,YearMonth,MonthDay,DayOfWeek。

并且,我们在LocalDate相关类的操作也可以通过Year,Month等来实现。

Year year =Year.now();

System.out.println(year.getValue()); // 2018

2.4 TemporalAdjusters

该类是一个计算用的类,提供了各种各样的计算方法。比如某个月的第一天,某个月的最后一天,某一年的第一天,某一年的第几天等各种计算方法。该类内部实现基本上全都是通过JDK8的Lambda表达式来实现的。随便举一些例子,都很简单。

LocalDate localDate = LocalDate.now();

// 1. 本月第一天

LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());

// 2. 本月最后一天

LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth());

// 3. 本年第一天

LocalDate firstDayOfYear = localDate.with(TemporalAdjusters.firstDayOfYear());

// 4. 下个月第一天

LocalDate firstDayOfNextMonth = localDate.with(TemporalAdjusters.firstDayOfNextMonth());

// 5. 本年度最后一天

LocalDate lastDayOfYear = localDate.with(TemporalAdjusters.lastDayOfYear());

System.out.println(firstDayOfMonth);

System.out.println(lastDayOfMonth);

System.out.println(firstDayOfYear);

System.out.println(firstDayOfNextMonth);

System.out.println(lastDayOfYear);

打印输出:

2018-01-01

2018-01-31

2018-01-01

2018-02-01

2018-12-31

2.5 Period和Duration

Period是基于ISO-8601标准的日期系统,用于计算两个日期间的年,月,日的差值。比如'2年,3个月,4天';而Duration和Period很像,但Duration计算的是两个日期间的秒,纳秒的值,是一种更为精确的计算方式;而ISO-8601系统是当今世界大部分地区采用的现代日历的阳历系统。

LocalDate localDate = LocalDate.now();

LocalDate localDate1 = LocalDate.of(2018, 3, 28);

Period period = Period.between(localDate, localDate1);

System.out.println(period.getDays());

System.out.println(period.getMonths());

当然如果我们看一下Period的between方法实现,就知道底层是通过LocalDate.until方法来实现的。同样,Period的between方法也就等同于LocalDate.until方法。

但这里有一个问题,就是Period的getDays方法返回的不是两个日期间总的天数,有点像月计算后剩余的天数,但也不完全是,所以不太清楚这个类实际的意义。看个例子:

LocalDate localDate1 = LocalDate.of(2018, 01, 30);

LocalDate localDate2 = LocalDate.of(2018, 03, 01);

Period period = Period.between(localDate1, localDate2);

System.out.println(period.getDays());

打印:1

我们把第一行代码换一下值,再看一下:

LocalDate localDate1 = LocalDate.of(2018, 01, 29);

结果还是打印1。再换:

LocalDate localDate1 = LocalDate.of(2018, 01, 28);

LocalDate localDate1 = LocalDate.of(2018, 01, 27);

上面两个分别打印1,2。

所以说,在没搞清楚上面的方法之前,还是不要贸然使用,而如果要计算两个日期间的总的天数,可以用如下方法来计算:

System.out.println(localDate1.until(localDate2, ChronoUnit.DAYS));

System.out.println(ChronoUnit.DAYS.between(localDate1, localDate2));

而对于Duration来说,就更简单了,计算两个时间之间的秒数,纳秒数:

LocalTime localTime1 = LocalTime.of(12, 12, 12);

LocalTime localTime2 = LocalTime.of(12, 13, 27);

Duration duration = Duration.between(localTime1, localTime2);

System.out.println(duration.getSeconds()); // 75

但有一点需要注意,Duration中必须要支持秒数,如果没有的话,将会报错,如:

LocalDate localDate1 = LocalDate.of(2018, 02, 28);

LocalDate localDate2 = LocalDate.of(2018, 02, 27);

Duration duration = Duration.between(localDate1, localDate2);

System.out.println(duration.getSeconds());

将会直接提示:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds

at java.time.LocalDate.until(LocalDate.java:1614)

at java.time.Duration.between(Duration.java:475)

at com.jdk8.DateTest.testPeriod(DateTest.java:40)

at com.jdk8.DateTest.main(DateTest.java:23)

2.6 ChronoUnit

这个是个枚举类型,实现功能类型Period和Duration,但如果我们看它的底层实现,就可以看到它基本是基于Duration来实现的。这个枚举很简单,我们直接看一些例子就可以了:

LocalDateTime oldDate = LocalDateTime.of(2017, Month.AUGUST, 31, 10, 20, 55);

LocalDateTime newDate = LocalDateTime.of(2018, Month.NOVEMBER, 9, 10, 21, 56);

System.out.println(oldDate);

System.out.println(newDate);

// count between dates

long years = ChronoUnit.YEARS.between(oldDate, newDate);

long months = ChronoUnit.MONTHS.between(oldDate, newDate);

long weeks = ChronoUnit.WEEKS.between(oldDate, newDate);

long days = ChronoUnit.DAYS.between(oldDate, newDate);

long hours = ChronoUnit.HOURS.between(oldDate, newDate);

long minutes = ChronoUnit.MINUTES.between(oldDate, newDate);

long seconds = ChronoUnit.SECONDS.between(oldDate, newDate);

long milis = ChronoUnit.MILLIS.between(oldDate, newDate);

long nano = ChronoUnit.NANOS.between(oldDate, newDate);

System.out.println("\n--- Total --- ");

System.out.println(years + " years");

System.out.println(months + " months");

System.out.println(weeks + " weeks");

System.out.println(days + " days");

System.out.println(hours + " hours");

System.out.println(minutes + " minutes");

System.out.println(seconds + " seconds");

System.out.println(milis + " milis");

System.out.println(nano + " nano");

打印结果:

2017-08-31T10:20:55

2018-11-09T10:21:56

--- Total ---

1 years

14 months

62 weeks

435 days

10440 hours

626401 minutes

37584061 seconds

37584061000 milis

37584061000000000 nano

2.7 Clock

时钟系统,用于查找当前时刻。通过指定一个时区,我们可以获取到当前的时刻,日期,时间。所以可以使用一个时钟来代替System.currenttimemillis() 和 TimeZone.getDefault()。

在应用程序的最佳实践是将时钟传递给任何需要当前即刻的方法:

public class MyBean {

private Clock clock; // dependency inject

...

public void process(LocalDate eventDate) {

if (eventDate.isBefore(LocalDate.now(clock)) {

...

}

}

}

我们可以简单测试一下:

// 系统默认

Clock systemDefaultClock = Clock.systemDefaultZone();

System.out.println("Current DateTime with system default clock: " + LocalDateTime.now(systemDefaultClock));

System.out.println(systemDefaultClock.millis());

// 世界协调时UTC

Clock systemUTCClock = Clock.systemUTC();

System.out.println("Current DateTime with UTC clock: " + LocalDateTime.now(systemUTCClock));

System.out.println(systemUTCClock.millis());

//芝加哥

Clock clock = Clock.system(ZoneId.of(ZoneId.SHORT_IDS.get("CST")));

System.out.println("Current DateTime with CST clock: " + LocalDateTime.now(clock));

System.out.println(clock.millis());

打印:

Current DateTime with system default clock: 2018-02-02T16:26:07.665

1517559967665

Current DateTime with UTC clock: 2018-02-02T08:26:07.665

1517559967665

Current DateTime with CST clock: 2018-02-02T02:26:07.667

1517559967667

并且我们可以使用 millis 方法来代替 System.currenttimemillis()。

更多有关Clock方法实例可以参考下面链接(没找到JDK8的,不过可以参考JDK9的):

https://www.concretepage.com/java/java-9/java-clock

2.8 其他

其中还有一些类没有详细说明,比如:

Instant,表示的是时间戳,用于记录某一时刻的更改(JDK8之前的Timestamp);

ZoneId 时区标志,比如用于标志欧洲/巴黎;

ZoneOffset 时区偏移量,与UTC的偏移量;

ZonedDateTime 与时区有关的日历系统,比如2007-12 03t10:15:30+01欧洲/巴黎;

OffsetDateTime 用于与UTC偏移的日期时间,如如2007-12 03t10:15:30+01:00。

3. 转换

3.1 java.util.Date与LocalDate,LocalTime,LocalDateTime替换

将Date转换为LocalDate,LocalTime,LocalDateTime可以借助于ZonedDateTime和Instant,实现如下:

Date date = new Date();

System.out.println("current date: " + date);

// Date -> LocalDateTime

LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

System.out.println("localDateTime by Instant: " + localDateTime);

// Date -> LocalDate

LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

System.out.println("localDate by Instant: " + localDate);

// Date -> LocalTime

LocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();

System.out.println("localTime by Instant: " + localTime);

//2. Date -> LocalDateTime

localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

System.out.println("localDateTime by ofInstant: " + localDateTime);

output:

current date: Fri Feb 02 16:43:13 CST 2018

localDateTime by Instant: 2018-02-02T16:43:13.073

localDateTime by ofInstant: 2018-02-02T16:43:13.073

localDate by Instant: 2018-02-02

localTime by Instant: 16:43:13.073

由于JDK8实现了向下兼容,所以Date里在JDK8版本引入了2个方法,from 和

toInstant,所以我们可以借助这两个方法来实现LocalDateTime到Date的转换。将LocalDateTime转为Date如下:

LocalDateTime localDateTime = LocalDateTime.now();

System.out.println("localDateTime: " + localDateTime);

// LocalDateTime -> Date

Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

System.out.println("LocalDateTime -> current date: " + date);

// LocalDate -> Date,时间默认都是00

LocalDate localDate = LocalDate.now();

date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());

System.out.println("LocalDate -> current date: " + date);

output:

localDateTime: 2018-02-02T16:55:52.464

LocalDateTime -> current date: Fri Feb 02 16:55:52 CST 2018

LocalDate -> current date: Fri Feb 02 00:00:00 CST 2018

而单独的LocalTime转为Date没什么意义,所以如果LocalTime要转为Date,一般借助于LocalDate和LocalDateTime来实现就可以了。

3.2 日期与字符串的转换

日期与字符串的转换比较简单。先说转换成日期格式,通过LocalDate,LocalTime,LocalDateTime的parse方法和DateTimeFormatter来实现:

LocalDate localDate = LocalDate.parse("2018-09-09", DateTimeFormatter.ofPattern("yyyy-MM-dd"));

LocalDateTime localDateTime = LocalDateTime.parse("2018-09-10 12:12:12", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

而将日期转为字符串,可以通过format方法和DateTimeFormatter来实现:

String localDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

String localDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

// 也可以通过DateTimeFormatter的format方法

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

localDateTime = dateTimeFormatter.format(LocalDateTime.now());

毫秒的话,是SSS,这个可能不经常使用,不过也要注意下:yyyy-MM-dd HH:mm:ss.SSS。

3.3 时间戳与LocalDateTime转换

将时间戳转为LocalDateTime,可以借助Instant(其实就是时间戳)来实现:

public static LocalDateTime convertToDate(long timestamp) {

// ofEpochSecond 以秒为单位, ofEpochMilli 以毫秒为单位

// Instant.ofEpochSecond(timestamp);

Instant instant = Instant.ofEpochMilli(timestamp);

return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

}

而将LocalDateTime转为时间戳,则同样可以借助Instant来实现:

public static long convertToTimestamp() {

LocalDateTime localDateTime = LocalDateTime.now();

return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

}

而至于字符串与时间戳的转换,借助LocalDateTime来实现即可。

总结

java.time包下其实还有一些其他的类与方法,如查询是否是闰年,日期比较,获取某一年的某一天等等,我们可以等用到的时候再去查看不迟。并且我们可以将我们常用的方法封装成util包供我们在使用的时候直接调用。

JDK8提供的这套API接口基本上封装了我们平时常用的所有与日期时间的相关操作,所以如果升级了JDK8,在处理日期和时间的时候尽量多用新的API。

JDK8中新的日期不但命名优雅,通俗易懂,而且提供了向下兼容的能力,可以无缝连接。

如果用到了Period,注意它的getDays方法。

java1.8日期类_JDK1.8-日期使用相关推荐

  1. dateformat java 格式_java Date日期类和SimpleDateFormat日期类格式

    ~Date表示特定的时间,精确到毫秒 ~构造方法: public Date()//构造Date对象并初始化为当前系统的时间 public Date(long date) //1970-1-1 0:0: ...

  2. 构造一个日期类java_Java8 新日期时间类(1)

    Java.time 包的优势 使用Java8,新的日期时间API引入覆盖旧的日期时间API的以下缺点. 非线程安全 - java.util.Date不是线程安全的,因此开发者必须在使用日期处理并发性问 ...

  3. java 日期类代码_java 日期时间处理类

    import java.util.Calendar; import java.sql.Date; import java.text.SimpleDateFormat; import java.text ...

  4. date日期相减 java_03时间日期类

    Java8 在 java.time 包中增加了时间日期相关的API,弥补了 Java8 以前对日期.时间处理的不足. 在介绍Java8新的时间日期API前,先看看 java8 以前我们操作日期时间常用 ...

  5. java知识点八:时间日期类

    时间日期类 一.常用日期类 1.System类 2.Date类 3.SimpleDateFormat类 4.Calendar类 二.System类 比较常用的相关方法currentTimeMills( ...

  6. 【日期类问题】例2.1日期差值

    二 日期类问题 此类问题解题思路: 定一个锚点日期,如0年1月1日,先算出往后多少年内每一日子距离这个锚点的天数,例如要算两个日期间天数时,便可以将两个日期距离锚点日期之间的天数相减,即可得到. 题目 ...

  7. 三代日期类的基本使用

    三代日期类的基本使用 文章目录 三代日期类的基本使用 一.第一代日期类Date 二.第二代的日期类Calendar 二.第三代的日期类LocalDateTime 总结 一.第一代日期类Date Dat ...

  8. 日期类的实现(C++)

    目录 注意: 1.作用域 2.实例化 3.this指针 4.std 1).std是什么? 2).为什么将cout放到名字空间std中? 3).std都是什么时候使用? 5.C语言"/&quo ...

  9. 计算机数学相关课程设计,课程设计-日期类-小学生数学测验软件器.doc

    文档介绍: 目录课程设计任务书一.................................................................................... ...

最新文章

  1. 学习编程能够从事哪些行业?
  2. POJ 2778 DNA Sequence [AC自动机 + 矩阵快速幂]
  3. VTK:相互作用之KeypressObserver
  4. 什么是SAP Spartacus schematics
  5. php session 效率,大量php session临时文件带来的服务器效率问题
  6. GHOST系统后一些问题如无法加入到域
  7. python 完全背包问题_动态规划——背包问题python实现(01背包、完全背包、多重背包)...
  8. 想成为架构师,你必须掌握的CAP细节
  9. VB添加TTS语音合成
  10. jQuery实现动态添加删除表格的行
  11. Similarity-Preserving Knowledge Distillation
  12. 数商云营销渠道管理系统解决方案:企业级营销系统类型、定位、管理
  13. dw读取access中的图片_DreamWeaver入门必看:ACCESS数据库(三)
  14. VMware 8安装Mac OS X 10.7 Lion
  15. window.name属性详解(Javascript)
  16. BlockingQueue解析
  17. 教育行业数据可视化应用方案与实践
  18. 史上最简单的Spring Security教程(二十八):CA登录与默认用户名密码登录共存详细实现及配置
  19. audition cc变声插件_Adobe Audition CC怎么安装插件?
  20. FFmpeg学习之八(FFmpeg源码编译)

热门文章

  1. 融云钜惠来袭,新客尝鲜首月 2.7 折起,超值套餐 6 折起
  2. Android 64位变32位
  3. 计算机方面的顶级会议
  4. 每日一篇系列---CSS3实现下雨动效
  5. 5G关键厂商推动2019年推出下一代网络;大疆发布首条企业级无人机产品Matrice 200│IoT黑板报...
  6. 民间秘术——镇鬼送神
  7. html樱花飘落代码_武大樱花又盛开,用python画一棵樱花树
  8. 利用photoshop去掉图片中文字
  9. 思科模拟器动态路由器的配置(rip)
  10. 数据库主从分离和读写分离