您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
JDK8 如何优雅的处理时间
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
JDK8 如何优雅的处理时间
自猿其说Tech
2021-10-27
IP归属:未知
23400浏览
计算机编程
### 1 前言 最近做报表开发,在计算同比、环比过程中需要各种类型的时间处理。对于时间处理,在jdk8之前,java处理日期、时间的方式一直不太友好。主要吐槽点包括:Date输出可读性差、SimpleDateFormat不是线程安全的,还有就是Calendar对日期的计算方式繁琐,易用性差。 jdk8推出了全新的api,采用人类语言方式处理时间,方式更加灵活,并且java.time包下类被final修饰,不必担心线程安全问题。 ### 2 核心类说明 在jdk8中,java.time包下包含以下几个核心类 ``` Instant:时间戳 Period:时间段 Duration:持续时间,时间差 LocalDate:只包含日期,比如:2021-08-30 LocalTime:只包含时间,比如:12:12:10 LocalDateTime:包含日期和时间,比如:2021-08-30 12:12:10 ZoneDateTime:带有时区信息的时间对象 ``` #### 2.1 LocalDate、LocalTime和LocalDateTime 从源码来看,Date包含一个long类型的变量表示完整的时间。在新的api中,将时间和日期拆分成不同的对象,分别为LocalTime 和LocalDate,并以组合的方式形成LocalDateTime。LocalDate和LocalTime 也将年月日时分秒定义为不同的属性。 ![](//img1.jcloudcs.com/developer.jdcloud.com/274450bd-64fe-448d-b324-4647503735b620211027141118.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/f029523f-15d9-4bb5-a51f-fa69f7cf0ecb20211027141126.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/5cdd556b-76fc-40bd-8b4d-678e2a55516f20211027141133.png) ![](//img1.jcloudcs.com/developer.jdcloud.com/c44b01ab-50db-45cd-abaa-ed790378ee4e20211027141146.png) 时间的创建和获取 ``` LocalDate nowDay = LocalDate.now(); // 获取当前日期 LocalTime nowTime = LocalTime.now(); // 获取当前时间 LocalDateTime nowDayTime = LocalDateTime.now(); // 获取当前日期时间 LocalDate localDate = LocalDate.of(2021, 9, 10); // 初始化一个日期:2021-09-10 int year = localDate.getYear(); // 获取年份:2021 Month month = localDate.getMonth(); // 获取月份:SEPTEMBER int dayOfMonth = localDate.getDayOfMonth(); // 月份中的第几天:10 DayOfWeek dayOfWeek = localDate.getDayOfWeek(); // 一周的第几天:FRIDAY int length = localDate.lengthOfMonth(); // 月份的天数:30 System.out.println("当前日期:"+ nowDay); System.out.println("当前时间:"+ nowTime); System.out.println("当前日期时间:"+ nowDayTime); System.out.println("年份:"+ year); System.out.println("月份:"+ month); System.out.println("日:"+ dayOfMonth); System.out.println("星期:"+ dayOfWeek); System.out.println("当月天数:"+ length); //输出结果 当前日期:2021-09-12 当前时间:23:06:34.922 当前日期时间:2021-09-12T23:06:34.922 年份:2021 月份:SEPTEMBER 日:10 星期:FRIDAY 当月天数:30 ``` #### 2.2 Instant Instant用于表示时间戳,使用 Instant.now()创建。相比于System.currentTimeMillis(),Instant可以精确到纳秒。Instant源码包含两个常量,seconds表示自格林威治时间(GMT)1970年1月1日0点到当前时间的秒数,nanos表示纳秒部分 ![](//img1.jcloudcs.com/developer.jdcloud.com/a091c811-67b5-4dc6-a574-c8635171697c20211027141217.png) ``` Instant instant = Instant.now(); System.out.println(" 毫秒数:"+instant.toEpochMilli()); System.out.println("系统毫秒数:"+System.currentTimeMillis()); System.out.println("纳秒数:"+instant.getNano()); //输出结果 毫秒数:1631463501941 系统毫秒数:1631463501941 纳秒数:941000000 ``` #### 2.3 Duration 相比于Instant,Duration表示一个时间段,所以它没有now方法,可以通过Duration.between()或则Duration.of时间类型()方式来创建。 ``` LocalDateTime from = LocalDateTime.of(2021, Month.JANUARY, 10, 10, 20, 0); // 2021-01-05 10:20:00 LocalDateTime to = LocalDateTime.of(2021, Month.FEBRUARY, 5, 10, 30, 0); // 2021-02-05 10:30:00 Duration duration = Duration.between(from, to); // 表示从 2021-01-05 10:20:00 到 2021-02-05 10:30:00 这段时间 long days = duration.toDays(); // 这段时间的总天数 long hours = duration.toHours(); // 这段时间的小时数 days * 24 long minutes = duration.toMinutes(); // 这段时间的分钟数 days * 24 * 60 long seconds = duration.getSeconds(); // 这段时间的秒数 days * 24 * 60 * 60 long milliSeconds = duration.toMillis(); // 这段时间的毫秒数 days * 24 * 60 * 60 * 1000 long nanoSeconds = duration.toNanos(); // 这段时间的纳秒数,当超过Long.MAX_VALUE会抛出异常 long nanoSecondsDiff = duration.getNano(); // 纳秒部分差额 ``` 也可通过duration.get(ChronoUnit)方式获取对应的值,值得注意的是,这种方式只支持获取秒和纳秒差额。至于为什么这么设定,或许是因为Duration对象只有秒和 纳秒差额两个变量,其他值则是通过second和纳秒差额计算得到的。 #### 2.4 Period Period区别于Duration,Period以日期表示一个日期段,不包含时分秒。在用法上两者相似 ### 3 常用操作 LocalDateTime采用人类语言定义处理时间的转换,需要注意的是,时间相关的api操作都是对原对象的copy,需要一个新的返回值,对象本身不会发生变化,这点在源码中有详细描述。 ![](//img1.jcloudcs.com/developer.jdcloud.com/9dfc6892-8a85-461e-a039-cdb11f0e338820211027141323.png) #### 3.1时间创建 时间创建主要有两种方式,通过now()仿佛获取当前时间,或者通过of()方式或者指定时间。 对象可以直接输出,相比于Date可读性更好 ``` LocalDateTime now = LocalDateTime.now(); // 当前时间 LocalDateTime dateTime = LocalDateTime.of(2021, Month.SEPTEMBER, 1, 10, 11, 12); // 2021-09-01 10:11:12 System.out.println("当前时间:"+now); System.out.println("指定时间:"+dateTime); // 输出结果 当前时间:2021-09-12T22:01:43.417 指定时间:2021-09-01T10:11:12 ``` #### 3.2 时间修改 时间修改通常使用with()方法,返回原对象的一个copy,需要有返回值,原对象本身不会发生变化 ``` LocalDateTime dateTime = LocalDateTime.of(2021, Month.SEPTEMBER, 1, 10, 11, 12); // 2021-09-01 10:11:12 LocalDateTime dateTime1 = dateTime.withYear(2020); // 修改年份为2020年 LocalDateTime dateTime2 = dateTime.withMonth(2); // 修改月份为 2月 LocalDateTime dateTime3 = dateTime.withDayOfMonth(1); // 修改日期为1号 LocalDateTime dateTime4 = dateTime.withHour(12); // 修改小时为12点 LocalDateTime dateTime5 = dateTime.withMinute(50); // 修改分钟为50 LocalDateTime dateTime6 = dateTime.withSecond(59); // 修改秒数为59 LocalDateTime dateTime7 = dateTime.withYear(2020).withMonth(2).withDayOfMonth(1).withHour(12).withMinute(50).withSecond(59); ``` #### 3.3 时间计算 ``` LocalDateTime dateTime = LocalDateTime.now(); LocalDateTime dateTime1 = dateTime.plusYears(1); // 增加一年 LocalDateTime dateTime2 = dateTime.minusMonths(2); // 减少两个月 LocalDateTime dateTime3 = dateTime.plus(5, ChronoUnit.DAYS); // 增加5天 // 计算日期差 long between = ChronoUnit.DAYS.between(dateTime, dateTime3); System.out.println("相差天数:" + between); // 输出结果 相差天数:5 ``` #### 3.4 时间转换 Instant是LocalDateTime与java.util.Date转换的桥梁。 Instant与LocalDateTime相互转换 ``` Instant instant = Instant.now(); // Instant转LocalDateTime LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); // LocalDateTime 转Instant Instant instant1 = LocalDateTime.now().toInstant(ZoneOffset.UTC); ``` LocalDateTime与Date相互转换 ``` Instant instant = Instant.now(); Date date = Date.from(instant); LocalDateTime dateTime5 = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); ``` #### 3.5 格式化 时间格式化采用DateTimeFormatter,相比于SimpleDateFormat,前者是线程安全的,另外定义时间格式时不需要再关注位数;字符串转时间默认使用DateTimeFormatter.ISO_LOCAL_DATE_TIME格式,可根据需求选择其他默认格式或自定义 ``` String format = dateTime.format(DateTimeFormatter.ofPattern("y-M-d H:m:s")); LocalDateTime parse = LocalDateTime.parse("2021-09-11T12:00:05"); System.out.println("时间转换字符串:"+format); System.out.println("字符串转换时间:"+parse); // 输出结果 时间转换字符串:2021-9-13 0:58:36 字符串转换时间:2021-09-11T12:00:05 ``` #### 3.6 时区 jdk8除了将日期与时间拆分外,同时将时区也拆分出来了。由于Date对象里存的是自格林威治时间(GMT)1970年1月1日0点至Date对象所表示时刻所经过的毫秒数,所以本地时间LocalDateTime转换成Date时需要加入时区信息。 另外单独提供了ZoneDateTime这样一个带有时区信息的时间对象,使用上同LocalDateTime类似,只需要增加时区ZoneId对象 ![](//img1.jcloudcs.com/developer.jdcloud.com/839049ac-9a1f-411e-b8df-7aca3697fbcf20211027141552.png) ### 4 总结 以上就是jdk8对于时间的常用操作。在日常开发中,时间处理应用场景较多,诉求不尽相同。在使用过程中若遇到问题,欢迎大家留言交流。 ------------ ###### 自猿其说Tech-JDL京东物流技术发展部 ###### 作者:攀登者小组(京喜达技术部 吉文凯)
原创文章,需联系作者,授权转载
上一篇:自动桩代码生成探讨
下一篇:经典书籍需要不断被重读——每一次重读都会有新的体会
相关文章
Taro小程序跨端开发入门实战
Flutter For Web实践
配运基础数据缓存瘦身实践
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会出现Optioanl方法之间的对比,实践,误用情况分析,优缺点等。与大家一起,对这项Java8中的新特性,进行理解和深入。
01
Taro小程序跨端开发入门实战
为了让小程序开发更简单,更高效,我们采用 Taro 作为首选框架,我们将使用 Taro 的实践经验整理了出来,主要内容围绕着什么是 Taro,为什么用 Taro,以及 Taro 如何使用(正确使用的姿势),还有 Taro 背后的一些设计思想来进行展开,让大家能够对 Taro 有个完整的认识。
01
Flutter For Web实践
Flutter For Web 已经发布一年多时间,它的发布意味着我们可以真正地使用一套代码、一套资源部署整个大前端系统(包括:iOS、Android、Web)。渠道研发组经过一段时间的探索,使用Flutter For Web技术开发了移动端可视化编程平台—Flutter乐高,在这里希望和大家分享下使用Flutter For Web实践过程和踩坑实践
01
配运基础数据缓存瘦身实践
在基础数据的常规能力当中,数据的存取是最基础也是最重要的能力,为了整体提高数据的读取能力,缓存技术在基础数据的场景中得到了广泛的使用,下面会重点展示一下配运组近期针对数据缓存做的瘦身实践。
自猿其说Tech
文章数
426
阅读量
2149963
作者其他文章
01
深入JDK中的Optional
01
Taro小程序跨端开发入门实战
01
Flutter For Web实践
01
配运基础数据缓存瘦身实践
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号