java8 clock_java8时间工具类

java8时间简介

在jdk1.8之前,我们使用时间Calendar或者SimpleDateFormat,但是Calendar的日历格式从0开始,容易给人误解。SimpleDateFormat非线程安全。不过我们可以借助joda库来简化开发。

joda-time

joda-time

2.9.2

好在jdk1.8在java.time.*包下给我们提供了简便的时间工具类,下面我们就先从SimpleDateFormat非线程安全的问题之后再到jdk1.8之前的解决方案和jdk1.8的解决方案。最后我们来学习使用jdk1.8的时间相关的API。

SimpleDateFormat线程不安全问题

public class TestSimpleDateFormat {

public static void main(String[] args) throws ExecutionException, InterruptedException {

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

Callable task = new Callable() {

@Override

public Date call() throws Exception {

return sdf.parse("20210204");

}

};

ExecutorService pool = Executors.newFixedThreadPool(10);

List> results = new ArrayList<>();

for(int i = 0;i <10;i++) {

results.add(pool.submit(task));

}

for(Future future : results) {

System.out.println(future.get());

}

pool.shutdown();

}

}

以上程序在多线程下执行会抛出类似如下所示的错误:

538275467499

image.png

在jdk1.8之前的解决方案是使用ThreadLocal的方式

public static final ThreadLocal dateFormatThreadLocal = new ThreadLocal(){

@Override

protected SimpleDateFormat initialValue() {

return new SimpleDateFormat("yyyyMMdd");

}

};

public static void main(String[] args) throws ExecutionException, InterruptedException {

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

Callable task = new Callable() {

@Override

public Date call() throws Exception {

return dateFormatThreadLocal.get().parse("20210204");

}

};

// 省略了后面的调用部分

}

jdk1.8的解决方案如下:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

Callable task= new Callable() {

@Override

public LocalDate call() throws Exception {

return LocalDate.parse("20210204", dtf);

}

};

ExecutorService pool = Executors.newFixedThreadPool(10);

List> results = new ArrayList<>();

for(int i = 0;i < 10;i++) {

results.add(pool.submit(task));

}

for (Future future : results) {

System.out.println(future.get());

}

pool.shutdown();

从以上看出jdk1.8的解决方案更加优雅。

jdk1.8的时间相关的api使用

/**

* Local(本地):简化了日期时间的处理,没有时区的问题。

* Zoned(时区):通过制定的时区处理日期时间。

* 具体的API:

* LocalDate:存储不包含时间的日期,比如2020-01-11。可以用来存储生日,周年纪念日,入职日期等。

* LocalTime:存储不包含日期的时间,比如11:07:03.580

*/

public class DateTimeTest {

public static void main(String[] args) {

//通过字符串指定

LocalDate towDay = LocalDate.parse("2021-02-24");

System.out.println(towDay); // 2021-02-24

//比较日期是否相等

LocalDate date1 = LocalDate.parse("2021-02-11");

LocalDate date2 = LocalDate.parse("2021-02-04");

System.out.println(date1.equals(date2)); // false

//日期前后比较

boolean before = LocalDate.parse("2021-02-11").isBefore(LocalDate.now());

System.out.println(before); // true

Clock clock = Clock.systemUTC();

System.out.println(clock); // SystemClock[Z]

System.out.println(clock.instant()); // 获取UTC时区转换的当前时间 2021-02-24T04:37:26.632Z

System.out.println(clock.millis()); // 获取UTC时区转换的毫秒数 1614141446633

}

private static void formatterTest() {

DateTimeFormatter isoDateTime = DateTimeFormatter.ISO_DATE_TIME;

LocalDateTime ldt = LocalDateTime.now();

String strDate = ldt.format(isoDateTime);

System.out.println(strDate); // 2021-02-24T12:05:15.447

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

String format = dtf.format(ldt);

System.out.println(format); // 2021年02月24日 12:02:05

LocalDateTime newDate = ldt.parse(format,dtf);

System.out.println(newDate); //2021-02-24T12:05:15

Set availableZoneIds = ZoneId.getAvailableZoneIds();

availableZoneIds.forEach(System.out::println); // 打印所有的时区,如 Asia/Shanghai

LocalDateTime now = LocalDateTime.now(ZoneId.of("America/Jujuy"));

System.out.println(now); // 2021-02-24T01:05:15.463

LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("America/Jujuy"));

ZonedDateTime atZone = ldt2.atZone(ZoneId.of("America/Jujuy"));

System.out.println(atZone); // 2021-02-24T01:05:15.463-03:00[America/Jujuy]

}

private static void temporalAdjsuterTest() {

/**

* 时间矫正器 TemporalAdjuster 有时我们可能需要获取

* 例如: 将日期调整到“下个周日”等操作

* TemporalAdjusters: 该类通过静态方法提供了大量的常用TemporalAdjuster操作

*/

LocalDateTime ldt = LocalDateTime.now();

System.out.println(ldt); // 2021-02-24T11:37:23.442

LocalDateTime ldt2 = ldt.withDayOfMonth(10);

System.out.println(ldt2); // 2021-02-10T11:37:23.442

LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));

System.out.println(ldt3); // 2021-02-28T11:37:23.442

//自定义: 下一个工作日

LocalDateTime ldt5 = ldt.with((l) ->{

LocalDateTime ldt4 = (LocalDateTime) l;

DayOfWeek dayOfWeek = ldt4.getDayOfWeek();

if(dayOfWeek.equals(DayOfWeek.FRIDAY)) {

return ldt4.plusDays(3);

}else if(dayOfWeek.equals(DayOfWeek.SATURDAY)) {

return ldt4.plusDays(2);

}else {

return ldt4.plusDays(1);

}

});

System.out.println(ldt5); // 2021-02-25T11:37:23.442

}

private static void durationAndPeriodTest() {

/**

* Duration: 计算两个时间之间的间隔

* Period: 计算两个日期之间的间隔

*/

Instant ins1 = Instant.now();

Instant ins2 = Instant.now();

Duration duration = Duration.between(ins1,ins2);

System.out.println(duration.toMillis()); // 0

LocalTime lt1 = LocalTime.now();

LocalTime lt2 = LocalTime.now();

System.out.println(Duration.between(lt1,lt2).toMillis()); // 0

LocalDate ld1 = LocalDate.now();

LocalDate ld2 = LocalDate.of(2015,1,1);

Period period = Period.between(ld1,ld2);

System.out.println(period); // P-6Y-1M-23D

System.out.println(period.getYears()); // -6

}

private static void instantTest() {

/**

* Instant : 时间戳 (以unix元年 1970-01-01 00:00:00 到某个时间之间的毫秒值)

*/

Instant inst1 = Instant.now(); // 默认获取UTC时区

System.out.println(inst1); // 2021-02-24T03:27:37.359Z

// 获取东8区,即北京时间

OffsetDateTime odt = inst1.atOffset(ZoneOffset.ofHours(8));

System.out.println(odt); // 2021-02-24T11:27:37.359+08:00

// 转为毫秒值

System.out.println(inst1.toEpochMilli()); // 1614137257359

// 给定秒获取时间

Instant ofEpochSecond = Instant.ofEpochSecond(1000);

System.out.println(ofEpochSecond); // 1970-01-01T00:16:40Z

}

/**

* LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,

* 分别表示使用ISO-8601日历、日期和时间。他们提供了简单的日期或

* 时间,不包含与时区相关的信息。

* ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法

*/

private static void localDateTimeTest() {

// 当前时间

LocalDateTime ldt = LocalDateTime.now();

System.out.println(ldt); // 2021-02-24T11:22:14.701

// 给定时间的LocalDateTime

LocalDateTime ldt2 = LocalDateTime.of(2020,2,24,11,18);

System.out.println(ldt2); // 2020-02-24T11:18

// 当前时间加两年后的时间

LocalDateTime plusYears = ldt.plusYears(2);

System.out.println(plusYears); // 2023-02-24T11:22:14.701

// 减去两个月的时间

LocalDateTime minusMonths = ldt.minusMonths(2);

System.out.println(minusMonths); // 2020-12-24T11:22:14.701

System.out.println(ldt.getYear()); // 2021

System.out.println(ldt.getMonthValue()); // 2

System.out.println(ldt.getMonth()); // FEBRUARY

System.out.println(ldt.getDayOfMonth()); // 24

System.out.println(ldt.getDayOfWeek()); // WEDNESDAY

System.out.println(ldt.getMinute()); // 22

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值