06-Java8新特性 新时间日期API
传统时间格式化的线程安全问题
测试线程安全问题
新建测试类
package com.dance.java8.day01.date; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.*; public class TestSimpleDateFormat { public static void main(String[] args) throws ExecutionException, InterruptedException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); ExecutorService executorService = Executors.newFixedThreadPool(10); Callable<Date> callable = () -> simpleDateFormat.parse("20161218"); List<Future<Date>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(executorService.submit(callable)); } for (Future<Date> dateFuture : list) { System.out.println(dateFuture.get()); } } }
测试结果
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple points at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at com.dance.java8.day01.date.TestSimpleDateFormat.main(TestSimpleDateFormat.java:26) Caused by: java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890) at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) at java.lang.Double.parseDouble(Double.java:538) at java.text.DigitList.getDouble(DigitList.java:169) at java.text.DecimalFormat.parse(DecimalFormat.java:2056) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1867) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) at java.text.DateFormat.parse(DateFormat.java:364) at com.dance.java8.day01.date.TestSimpleDateFormat.lambda$main$0(TestSimpleDateFormat.java:17) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
使用ThreadLocal解决线程安全问题
新建ThreadLocal类
package com.dance.java8.day01.date; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateFormatThreadLocal { private static final ThreadLocal<DateFormat> dateformat = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyyMMdd"); } }; public static Date convert(String source) throws ParseException { return dateformat.get().parse(source); } }
修改测试类
package com.dance.java8.day01.date; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.*; public class TestSimpleDateFormat { public static void main(String[] args) throws ExecutionException, InterruptedException { // SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); ExecutorService executorService = Executors.newFixedThreadPool(10); Callable<Date> callable = () -> DateFormatThreadLocal.convert("20161218"); List<Future<Date>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(executorService.submit(callable)); } for (Future<Date> dateFuture : list) { System.out.println(dateFuture.get()); } } }
测试结果
Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016 Sun Dec 18 00:00:00 CST 2016
使用新的日期API解决线程安全问题
新建测试类
package com.dance.java8.day01.date; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.*; public class TestSimpleDateFormatNewApi { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(10); // 格式化类 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); // localDate Callable<LocalDate> callable = () -> LocalDate.parse("20161218",dateTimeFormatter); List<Future<LocalDate>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(executorService.submit(callable)); } for (Future<LocalDate> dateFuture : list) { System.out.println(dateFuture.get()); } executorService.shutdown(); } }
测试结果
2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18 2016-12-18
新的日期API
使用LocalDate,LocalTime,LocalDateTime
- LocalDate,LocalTime,LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期,时间,日期和时间,他们提供了简单的日期或时间,并不包含当前的额时间信息.也不包含与时区相关的信息
- 注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法
LocalDateTime
@Test public void test1(){ // 获取当前时间 LocalDateTime localDateTime = LocalDateTime.now(); // 打印 System.out.println("当前时间为:"+localDateTime); // 指定日期 LocalDateTime of = LocalDateTime.of(2021, 12, 4, 17, 49, 12); System.out.println("指定日期和时间:"+of); // 日期时间计算 // + 1 day System.out.println("添加一天:" + localDateTime.plusDays(1)); // -1 day System.out.println("减去一天:" + localDateTime.plusDays(-1)); // -3 year System.out.println("减去三年:" + localDateTime.minusYears(3)); // 获取 System.out.println(localDateTime.getYear()); System.out.println(localDateTime.getMonthValue()); System.out.println(localDateTime.getDayOfMonth()); System.out.println(localDateTime.getHour()); System.out.println(localDateTime.getMinute()); System.out.println(localDateTime.getSecond()); }
执行结果
当前时间为:2021-12-04T17:56:57.172 指定日期和时间:2021-12-04T17:49:12 添加一天:2021-12-05T17:56:57.172 减去一天:2021-12-03T17:56:57.172 减去三年:2018-12-04T17:56:57.172 2021 12 4 17 56 57
LocalDate和LocalTime
参考LocalDateTime
使用Instant
Instant
Instant : 时间戳(以Unix 元年: 1970年1月1日 00:00:00 到某个时间之间的毫秒值)
@Test public void test2(){ Instant now = Instant.now(); System.out.println("时间为:"+now); // 默认获取UTC 时区 格林尼治时间 // 小时偏移量计算 OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8)); System.out.println("偏移后的时间:"+offsetDateTime); // 转换为毫秒 System.out.println("毫秒:"+now.toEpochMilli()); System.out.println("系统:"+System.currentTimeMillis()); // 偏移开始时间 Instant instant = Instant.ofEpochSecond(60); System.out.println("元年偏移时间:"+instant); }
执行结果
时间为:2021-12-04T10:10:50.324Z 偏移后的时间:2021-12-04T18:10:50.324+08:00 毫秒:1638612650324 系统:1638612650428 元年偏移时间:1970-01-01T00:01:00Z
使用Duration
Duration
@Test public void test3() throws InterruptedException { // 时间间隔 Instant start = Instant.now(); Thread.sleep(1000); Instant end = Instant.now(); Duration between = Duration.between(start, end); System.out.println("时间间隔为:"+between.getSeconds()); LocalTime startTime = LocalTime.now(); Thread.sleep(1000); LocalTime endTime = LocalTime.now(); long seconds = Duration.between(startTime, endTime).getSeconds(); System.out.println("时间间隔为:" + seconds); }
执行结果
时间间隔为:1 时间间隔为:1
使用Period
Period
@Test public void test4(){ LocalDate now = LocalDate.now(); LocalDate localDate = LocalDate.of(2022,3,4); Period between = Period.between(now, localDate); System.out.println("日期间隔:"+between); }
执行结果
日期间隔:P3M
日期的操纵
- TemporalAdjuster:时间矫正器,有时我们可能需要获取列如:将日期调整到"下个周期"等操作
- TemporalAdjusters:该类通过静态方法提供了大量的常用TemporalAdjuster的实现
时间矫正器(TemporalAdjuster)
@Test public void test5(){ LocalDateTime now = LocalDateTime.now(); System.out.println("当前时间为:"+now); // 指定日期为几号 LocalDateTime localDateTime = now.withDayOfMonth(10); System.out.println("with date after:"+localDateTime); // 时间矫正器 // 调整到下周日 LocalDateTime with = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); System.out.println("下周日为:"+with); // 自定义下一个工作日 LocalDateTime workDay = now.with(l -> { LocalDateTime work = (LocalDateTime) l; DayOfWeek dayOfWeek = work.getDayOfWeek(); switch (dayOfWeek) { case FRIDAY: return work.plusDays(3); case SATURDAY: return work.plusDays(2); default: return work.plusDays(1); } }); System.out.println("下一个工作日:"+workDay); }
执行结果
当前时间为:2021-12-04T21:45:33.042 with date after:2021-12-10T21:45:33.042 下周日为:2021-12-05T21:45:33.042 下一个工作日:2021-12-06T21:45:33.042
使用DateTimeFormatter
DateTimeFormatter
@Test public void test6(){ // 使用提供的格式化类 DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE; LocalDateTime now = LocalDateTime.now(); String format = now.format(isoDate); System.out.println(format); // 自定义格式化 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String format1 = now.format(dateTimeFormatter); System.out.println(format1); }
执行结果
2021-12-04 2021-12-04 22:19:10
时区的处理
- Java8中假如了对时区的支持,带时区的时间分别为:
- ZonedDate,ZonedTime,ZonedDateTime
- 其中每个时区都对应着ID,地区ID都为 "{区域}/{城市}"的格式
- 例如:Asia/Shanghai等
- ZondId:该类中包含了所有的时区信息
- getAvailableZoneIds():可以获取所有时区的时区信息
- of(id):用指定的时区信息获取ZoneId对象
ZonedDateTime
@Test public void test7(){ // 打印所有时区 // ZoneId.getAvailableZoneIds().forEach(System.out::println); // 指定时区获取时间 LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); System.out.println(now); // 获取携带时区 ZonedDateTime zonedDateTime = now.atZone(ZoneId.of("Asia/Shanghai")); System.out.println(zonedDateTime); }
执行结果
2021-12-04T22:39:25.881 2021-12-04T22:39:25.881+08:00[Asia/Shanghai]
若有收获,就点个赞吧
作者:彼岸舞
时间:2021\12\13
内容关于:Java
本文属于作者原创,未经允许,禁止转发
分类:
Java8新特性
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」