哈喽,我是狗哥。
最近,重新读了《阿里巴巴 Java 开发规范》,其中有一条是建议使用 LocalDateTime
,而不是 Date
?
在项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用 static
修饰 SimpleDateFormat
吗?
通过阅读本篇文章你将了解到:
为什么需要 LocalDate、LocalTime、LocalDateTime
等 Java8 新提供的类Java8 新的时间 API 的使用方式,包括创建、格式化、解析、计算、修改
01 为什么需要?
Date 如果不格式化,打印出的日期可读性差
Tue Sep 10 09:34:04 CST 2019
复制
使用 SimpleDateFormat
对时间进行格式化,但 SimpleDateFormat
是线程不安全的 SimpleDateFormat
的 format
方法最终调用代码:

calendar
是共享变量,并且这个共享变量没有做线程安全控制。
当多个线程同时使用相同的 SimpleDateFormat
对象【如用 static
修饰的 SimpleDateFormat
】调用 format
方法时。
多个线程会同时调用 calendar.setTime
方法,可能一个线程刚设置好 time
值,另外的一个线程马上把设置的 time
值给修改了,导致返回的格式化时间可能是错误的。
在多线程情况下使用 SimpleDateFormat
需格外注意 SimpleDateFormat
除了 format
是线程不安全以外,parse
方法也是线程不安全的。
parse
方法实际调用 alb.establish(calendar).getTime()
方法来解析,alb.establish (calendar)
方法里主要完成了
重置日期对象 cal
的属性值使用 calb
中中属性设置cal
返回设置好的 cal
对象
但是这三步不是原子操作,多线程并发如何保证线程安全,避免线程之间共享一个 SimpleDateFormat
对象:
每个线程使用时都创建一次 SimpleDateFormat
对象 =>创建和销毁对象的开销大
对使用 format
和parse
方法的地方进行加锁 =>线程阻塞性能差
使用 ThreadLocal
保证每个线程最多只创建一次SimpleDateFormat
对象 =>较好的方法
Date 对时间处理比较麻烦,比如想获取某年、某月、某星期,以及 n 天以后的时间。
如果用 Date 来处理的话真是太难了,你可能会说 Date 类不是有 getYear、getMonth
这些方法吗,获取年月日很 Easy,但都被弃用了啊
所以,一起来使用 java8 全新的日期和时间 API 吧
02 Java8 时间 API 的使用
2.1 LocalDate
只会获取年月日
2.1.1 创建
//获取当前年月日
LocalDate localDate = LocalDate.now();
//构造指定的年月日
LocalDate localDate1 = LocalDate.of(2019, 9, 10);复制
2.1.2 获取年月日、星期几
//获取当前年月日
LocalDate localDate = LocalDate.now();
//构造指定的年月日
LocalDate localDate1 = LocalDate.of(2019, 9, 10);复制
2.2 LocalTime
只会获取几点几分几秒
2.2.1 创建
LocalTime localTime = LocalTime.of(13, 51, 10);
LocalTime localTime1 = LocalTime.now();复制
2.2.2 获取时分秒
//获取小时
int hour = localTime.getHour();
int hour1 = localTime.get(ChronoField.HOUR_OF_DAY);
//获取分
int minute = localTime.getMinute();
int minute1 = localTime.get(ChronoField.MINUTE_OF_HOUR);
//获取秒
int second = localTime.getSecond();
int second1 = localTime.get(ChronoField.SECOND_OF_MINUTE);复制
2.3 LocalDateTime
获取年月日时分秒,等于 LocalDate+LocalTime
2.3.1 创建
LocalDateTime localDateTime = LocalDateTime.now();
LocalDateTime localDateTime1 = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
LocalDateTime localDateTime2 = LocalDateTime.of(localDate, localTime);
LocalDateTime localDateTime3 = localDate.atTime(localTime);
LocalDateTime localDateTime4 = localTime.atDate(localDate);复制
2.3.2 获取 LocalDate
LocalDate localDate2 = localDateTime.toLocalDate();
复制
2.3.3 获取 LocalTime
LocalTime localTime2 = localDateTime.toLocalTime();
复制
2.4 Instant
获取秒数
2.4.1 创建
Instant instant = Instant.now();
复制
2.4.2 获取秒数
long currentSecond = instant.getEpochSecond();
复制
2.4.3 获取毫秒数
long currentMilli = instant.toEpochMilli();
复制
个人觉得如果只是为了获取秒数或者毫秒数,使用 System.currentTimeMillis () 来得更为方便
2.5 修改
LocalDate、LocalTime、LocalDateTime、Instant
为不可变对象,修改这些对象对象会返回一个副本
2.5.1 增加、减少年数、月数、天数
LocalDateTime localDateTime = LocalDateTime.of(2019, Month.SEPTEMBER, 10, 14, 46, 56);
//增加一年
localDateTime = localDateTime.plusYears(1);
localDateTime = localDateTime.plus(1, ChronoUnit.YEARS);
//减少一个月
localDateTime = localDateTime.minusMonths(1);
localDateTime = localDateTime.minus(1, ChronoUnit.MONTHS);复制
通过 with 修改某些值
//修改年为2019
localDateTime = localDateTime.withYear(2020);
//修改为2022
localDateTime = localDateTime.with(ChronoField.YEAR, 2022);复制
还可以修改月、日
2.5.2 时间计算
比如有些时候想知道这个月的最后一天是几号、下个周末是几号,通过提供的时间和日期 API 可以很快得到答案
比如通过 firstDayOfYear () 返回了当前日期的第一天日期,还有很多方法这里不在。举例说明
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = localDate.with(firstDayOfYear());复制
2.5.3 格式化时间
LocalDate localDate = LocalDate.of(2019, 9, 10);
String s1 = localDate.format(DateTimeFormatter.BASIC_ISO_DATE);
String s2 = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
//自定义格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String s3 = localDate.format(dateTimeFormatter);复制
DateTimeFormatter
默认提供了多种格式化方式,如果默认提供的不能满足要求,可以通过 DateTimeFormatter
的 ofPattern
方法创建自定义格式化方式
2.5.4 解析时间
LocalDate localDate1 = LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate2 = LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);复制
和 SimpleDateFormat
相比,DateTimeFormatter
是线程安全的
03 小结
LocalDateTime:Date
有的我都有,Date
没有的我也有,日期选择请选择前者。
Spring Boot
中应用 LocalDateTime
将 LocalDateTime
字段以时间戳的方式返回给前端 添加日期转化类
public class LocalDateTimeConverter extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNumber(value.toInstant(ZoneOffset.of("+8")).toEpochMilli());
}
}复制
并在 LocalDateTime
字段上添加 @JsonSerialize(using = LocalDateTimeConverter.class)
注解,如下:
@JsonSerialize(using = LocalDateTimeConverter.class)
protected LocalDateTime gmtModified;复制
将 LocalDateTime
字段以指定格式化日期的方式返回给前端。
在 LocalDateTime
字段上添加 @JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
注解即可,如下:
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;复制
对前端传入的日期进行格式化,在 LocalDateTime
字段上添加 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
注解即可,如下:
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
protected LocalDateTime gmtModified;复制
3.1 巨人的肩膀
juejin.cn/post/6844903939402383368
04 IDEA 激活
点击阅读原文~
05 大厂面试题 & 电子书
如果看到这里,喜欢这篇文章的话,请帮点个好看,一键三连哦。
初次见面,也不知道送你们啥。干脆就送几百本电子书和 2021 最新面试资料吧。微信搜索 JavaFish 回复 电子书送你 1000+ 本编程电子书;回复面试送点面试题;回复 1024 送你一套完整的 java 视频教程。
面试题都是有答案的,详细如下所示:有需要的就来拿吧,绝对免费,无套路获取。

