首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >06-Java8新特性 新时间日期API

06-Java8新特性 新时间日期API

作者头像
彼岸舞
发布2021-12-14 19:43:16
发布2021-12-14 19:43:16
70100
代码可运行
举报
运行总次数:0
代码可运行

传统时间格式化的线程安全问题

测试线程安全问题

新建测试类

代码语言:javascript
代码运行次数:0
运行
复制
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());
        }

    }

}

测试结果

代码语言:javascript
代码运行次数:0
运行
复制
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类

代码语言:javascript
代码运行次数:0
运行
复制
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);
    }

}

修改测试类

代码语言:javascript
代码运行次数:0
运行
复制
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());
        }

    }

}

测试结果

代码语言:javascript
代码运行次数:0
运行
复制
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解决线程安全问题

新建测试类

代码语言:javascript
代码运行次数:0
运行
复制
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();

    }

}

测试结果

代码语言:javascript
代码运行次数:0
运行
复制
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

代码语言:javascript
代码运行次数:0
运行
复制
@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());
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
当前时间为: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 到某个时间之间的毫秒值)

代码语言:javascript
代码运行次数:0
运行
复制
@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);
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
时间为:2021-12-04T10:10:50.324Z
偏移后的时间:2021-12-04T18:10:50.324+08:00
毫秒:1638612650324
系统:1638612650428
元年偏移时间:1970-01-01T00:01:00Z

使用Duration

Duration

代码语言:javascript
代码运行次数:0
运行
复制
@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);
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
时间间隔为:1
时间间隔为:1

使用Period

Period

代码语言:javascript
代码运行次数:0
运行
复制
@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);
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
日期间隔:P3M

日期的操纵

  • TemporalAdjuster:时间矫正器,有时我们可能需要获取列如:将日期调整到"下个周期"等操作
  • TemporalAdjusters:该类通过静态方法提供了大量的常用TemporalAdjuster的实现

时间矫正器(TemporalAdjuster)

代码语言:javascript
代码运行次数:0
运行
复制
@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);

}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
当前时间为: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

代码语言:javascript
代码运行次数:0
运行
复制
@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);
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
2021-12-04
2021-12-04 22:19:10

时区的处理

  • Java8中假如了对时区的支持,带时区的时间分别为:
    • ZonedDate,ZonedTime,ZonedDateTime
    • 其中每个时区都对应着ID,地区ID都为 "{区域}/{城市}"的格式
    • 例如:Asia/Shanghai等
    • ZondId:该类中包含了所有的时区信息
    • getAvailableZoneIds():可以获取所有时区的时区信息
    • of(id):用指定的时区信息获取ZoneId对象

ZonedDateTime

代码语言:javascript
代码运行次数:0
运行
复制
@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);
}

执行结果

代码语言:javascript
代码运行次数:0
运行
复制
2021-12-04T22:39:25.881
2021-12-04T22:39:25.881+08:00[Asia/Shanghai]
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 传统时间格式化的线程安全问题
  • 测试线程安全问题
    • 新建测试类
    • 测试结果
  • 使用ThreadLocal解决线程安全问题
    • 新建ThreadLocal类
    • 修改测试类
    • 测试结果
  • 使用新的日期API解决线程安全问题
    • 新建测试类
    • 测试结果
  • 新的日期API
    • 使用LocalDate,LocalTime,LocalDateTime
      • LocalDateTime
      • 执行结果
      • LocalDate和LocalTime
    • 使用Instant
      • Instant
      • 执行结果
    • 使用Duration
      • Duration
      • 执行结果
    • 使用Period
      • Period
      • 执行结果
    • 日期的操纵
      • 时间矫正器(TemporalAdjuster)
      • 执行结果
    • 使用DateTimeFormatter
      • DateTimeFormatter
      • 执行结果
    • 时区的处理
      • ZonedDateTime
      • 执行结果
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档