全新的日期、时间API
线程安全问题
Date线程不安全问题
多线程操作,解析同一个日期字符串
public class Demo01 {
/**
* Date 线程不安全
*/
@Test
public void test01() throws ExecutionException, InterruptedException {
List<Future<Date>> dates = new ArrayList<>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("2020-09-08");
}
};
for (int i = 0; i < 100; i++) {
dates.add(pool.submit(task));
}
for (Future<Date> date : dates) {
System.out.println(date.get());
}
}
}
抛出NumberFormatException
异常
Tue Sep 08 00:00:00 GMT+08:00 2020
Tue Sep 08 00:00:00 GMT+08:00 2020
java.util.concurrent.ExecutionException: java.lang.NumberFormatException: For input string: "220022.E220022E44"
Date线程解决方案-ThreadLocal
ThreadLocal
处理
/**
* @description: Date 线程不安全的解决方案-ThreadLocal
*/
public class Demo02 {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
@Override
protected DateFormat initialValue(){
return new SimpleDateFormat("yyyy-MM-dd");
}
};
public static Date convert(String dateStr) throws ParseException {
return df.get().parse(dateStr);
}
/**
* Date 线程不安全,处理现场
*/
@Test
public void test01() throws ExecutionException, InterruptedException {
List<Future<Date>> dates = new ArrayList<>();
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return convert("2020-09-08");
}
};
for (int i = 0; i < 100; i++) {
dates.add(pool.submit(task));
}
pool.shutdown();
for (Future<Date> date : dates) {
System.out.println(date.get());
}
}
}
线程安全的类-LocalDate
/**
* @description: 使用LocalDate DateTimeFormatter 线程安全的类解决线程安全问题
*/
public class Demo03 {
/**
* LocalDate 线程安全的类
*/
@Test
public void test01() throws ExecutionException, InterruptedException {
List<Future<LocalDate>> dates = new ArrayList<>();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("2020-09-08",dtf);
}
};
for (int i = 0; i < 100; i++) {
dates.add(pool.submit(task));
}
for (Future<LocalDate> date : dates) {
System.out.println(date.get());
}
}
}
部分API示例
/**
* @description: 新的类API
*/
public class TestLocalDateTime {
// 创建对象
static final LocalDateTime now = LocalDateTime.now();
static final LocalDateTime point = LocalDateTime.of(2020, 9, 8, 15, 48, 35);
@Test
public void test01(){
System.out.println(point); // 2020-09-08T15:48:35
System.out.println(point.plusDays(1)); // 2020-09-09T15:48:35
System.out.println(point.minusDays(1)); // 2020-09-07T15:48:35
System.out.println(point.getMonth()); // SEPTEMBER
System.out.println(point.getMonthValue()); // 9
}
/**
* Unix元年
*/
@Test
public void test02(){
Instant now = Instant.now(); // 默认获取UTC时区,世界协调时间
System.out.println(now); // 2020-09-08T08:35:19.255Z
System.out.println(now.toEpochMilli()); // 1599554269206
OffsetDateTime fdt = now.atOffset(ZoneOffset.ofHours(8));
System.out.println(fdt); // 2020-09-08T16:35:19.255+08:00
System.out.println(fdt.toInstant()); // 2020-09-08T08:37:49.206Z
System.out.println(fdt.toInstant().toEpochMilli()); // 1599554269206
}
}
求始末日期工具类
/**
* @description: 给定一个时间段的始末日期
* 使用1.8的静态方法和全新的API
*/
public interface RangeUtils {
/*
* 昨天
*/
static Range lastDay() {
LocalDate now = LocalDate.now();
return new Range(now.plusDays(-1), now.plusDays(-1));
}
/*
* 本周,是否包含未来
*/
static Range currentWeek(boolean includeFuture) {
LocalDate now = LocalDate.now();
LocalDate start = now.with(WeekFields.of(Locale.CHINESE).dayOfWeek(), 1);
LocalDate end = includeFuture ? now.with(WeekFields.of(Locale.CHINESE).dayOfWeek(), 7) : now;
return new Range(start, end);
}
/**
* 本月,是否包含未来
*/
static Range currentMonth(boolean includeFuture) {
LocalDate now = LocalDate.now();
LocalDate start = now.with(TemporalAdjusters.firstDayOfMonth());
LocalDate end = includeFuture ? now.with(TemporalAdjusters.lastDayOfMonth()) : now;
return new Range(start, end);
}
/*
* 前 month 个月的始末
*/
static Range lastMonth(int month) {
LocalDate now = LocalDate.now();
LocalDate start = now.plusMonths(-month).with(TemporalAdjusters.firstDayOfMonth());
LocalDate end = now.plusMonths(-month).with(TemporalAdjusters.lastDayOfMonth());
return new Range(start, end);
}
/*
* 前 week 个周的始末
*/
static Range lastWeek(int week) {
LocalDate now = LocalDate.now();
LocalDate start = now.plusWeeks(-week).with(WeekFields.of(Locale.CHINESE).dayOfWeek(), 1);
LocalDate end = now.plusWeeks(-week).with(WeekFields.of(Locale.CHINESE).dayOfWeek(), 7);
return new Range(start, end);
}
/*
* 指定日期到今天的始末
*/
static Range untilToday(String yyyyMMdd) {
LocalDate start = LocalDate.parse(yyyyMMdd, DateTimeFormatter.ofPattern("yyyy-MM-DD"));
if (start.isAfter(LocalDate.now())) {
throw new IllegalStateException(start + " is after today.");
}
return new Range(start, LocalDate.now());
}
/*
* 转换指定起始日期
*/
static Range range(String st1, String st2) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate start = LocalDate.parse(st1, dateTimeFormatter);
LocalDate end = LocalDate.parse(st2, dateTimeFormatter);
if (start.isAfter(end)) {
throw new IllegalStateException(start + " is after " + end + ".");
}
return new Range(start, end);
}
/*
* 日期的区间内部类
*/
class Range {
private final LocalDate start;
private final LocalDate end;
public Range(LocalDate start, LocalDate end) {
this.start = start;
this.end = end;
}
@Override
public String toString() {
return "Range{" +
"start=" + start +
", end=" + end +
'}';
}
}
}
时间转化与比较
// 确认验证码是否过期
final LocalDateTime now = LocalDateTime.now();
final LocalDateTime createdTime = smsCheckCode.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
if (Duration.between(createdTime, now).toMinutes() > 5) {
// 过期提示已过期
rstFulBody.fail("该验证码已过期,请重新获取验证码!");
smsCheckCodeService.deleteByPrimaryKey(smsCheckCode.getCkCodeId());
return rstFulBody;
}
LocalDateTime localDateTime=LocalDateTime.now()
Date date = Date.from(localDateTime.atZone( ZoneId.systemDefault()).toInstant());
Date startDate=new Date();
LocalDateTime localDateTime = startDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
当前所处在一年中的周数
LocalDateTime now = LocalDateTime.now();
DayOfWeek dayOfWeek = DayOfWeek.MONDAY;
WeekFields weekFields = WeekFields.of(dayOfWeek,1);
int weekInYear = now.get(weekFields.weekOfWeekBasedYear());
getWeekIndex(){
// 截掉时分秒保留整数天
var date=new Date(new Date().toLocaleDateString());
//设置日期为当前周周四
date.setDate(date.getDate()+(4-(date.getDay()||7)));
var year=date.getFullYear();
var firstDate=new Date(year,0,1);
firstDate.setDate(firstDate.getDate()+(4-(firstDate.getDay()||7)));
//当年第一天早于周四第一周延后七天
if(firstDate.getFullYear()<year){
firstDate.setDate(firstDate.getDate()+7);
}
//计算当前周和第一周之间周数差
return Math.ceil(((date-firstDate)/86400000+1)/7);
},