為什么建議使用你 LocalDateTime ,而不是 Date?
點(diǎn)擊上方“JAVA”,星標(biāo)公眾號(hào)

來(lái)源:juejin.im/post/5d7787625188252388753eae
為什么需要LocalDate、LocalTime、LocalDateTime
Come On 一起使用java8全新的日期和時(shí)間API
小結(jié)
在項(xiàng)目開發(fā)過程中經(jīng)常遇到時(shí)間處理,但是你真的用對(duì)了嗎,理解阿里巴巴開發(fā)手冊(cè)中禁用static修飾SimpleDateFormat嗎
通過閱讀本篇文章你將了解到:
為什么需要
LocalDate、LocalTime、LocalDateTime【java8新提供的類】java8新的時(shí)間API的使用方式,包括創(chuàng)建、格式化、解析、計(jì)算、修改
為什么需要LocalDate、LocalTime、LocalDateTime
Date如果不格式化,打印出的日期可讀性差
Tue?Sep?10?09:34:04?CST?2019??
使用 SimpleDateFormat對(duì)時(shí)間進(jìn)行格式化,但SimpleDateFormat是線程不安全的SimpleDateFormat的format方法最終調(diào)用代碼:
private?StringBuffer?format(Date?date,?StringBuffer?toAppendTo,??
??????????????????????????????FieldDelegate?delegate)?{??
????????//?Convert?input?date?to?time?field?list??
????????calendar.setTime(date);??
????????boolean?useDateFormatSymbols?=?useDateFormatSymbols();??
????????for?(int?i?=?0;?i?????????????int?tag?=?compiledPattern[i]?>>>?8;??
????????????int?count?=?compiledPattern[i++]?&?0xff;??
????????????if?(count?==?255)?{??
????????????????count?=?compiledPattern[i++]?<16;??
????????????????count?|=?compiledPattern[i++];??
????????????}??
????????????switch?(tag)?{??
????????????case?TAG_QUOTE_ASCII_CHAR:??
????????????????toAppendTo.append((char)count);??
????????????????break;??
????????????case?TAG_QUOTE_CHARS:??
????????????????toAppendTo.append(compiledPattern,?i,?count);??
????????????????i?+=?count;??
????????????????break;??
????????????default:??
????????????????subFormat(tag,?count,?delegate,?toAppendTo,?useDateFormatSymbols);??
????????????????break;??
????????????}??
????????}??
????????return?toAppendTo;??
????}??
calendar是共享變量,并且這個(gè)共享變量沒有做線程安全控制。當(dāng)多個(gè)線程同時(shí)使用相同的SimpleDateFormat對(duì)象【如用static修飾的SimpleDateFormat】調(diào)用format方法時(shí),多個(gè)線程會(huì)同時(shí)調(diào)用calendar.setTime方法,可能一個(gè)線程剛設(shè)置好time值另外的一個(gè)線程馬上把設(shè)置的time值給修改了導(dǎo)致返回的格式化時(shí)間可能是錯(cuò)誤的。在多并發(fā)情況下使用SimpleDateFormat需格外注意SimpleDateFormat除了format是線程不安全以外,parse方法也是線程不安全的。parse方法實(shí)際調(diào)用alb.establish(calendar).getTime()方法來(lái)解析,alb.establish(calendar)方法里主要完成了
重置日期對(duì)象cal的屬性值 使用calb中中屬性設(shè)置cal 返回設(shè)置好的cal對(duì)象
但是這三步不是原子操作
SimpleDateFormat對(duì)象,每個(gè)線程使用時(shí)都創(chuàng)建一次SimpleDateFormat對(duì)象 => 創(chuàng)建和銷毀對(duì)象的開銷大 - 對(duì)使用format和parse方法的地方進(jìn)行加鎖 => 線程阻塞性能差 - 使用ThreadLocal保證每個(gè)線程最多只創(chuàng)建一次SimpleDateFormat對(duì)象 => 較好的方法Date對(duì)時(shí)間處理比較麻煩,比如想獲取某年、某月、某星期,以及n天以后的時(shí)間,如果用Date來(lái)處理的話真是太難了,你可能會(huì)說Date類不是有getYear、getMonth這些方法嗎,獲取年月日很Easy,但都被棄用了啊
Come On 一起使用java8全新的日期和時(shí)間API
LocalDate
只會(huì)獲取年月日
創(chuàng)建 LocalDate
//獲取當(dāng)前年月日??
LocalDate?localDate?=?LocalDate.now();??
//構(gòu)造指定的年月日??
LocalDate?localDate1?=?LocalDate.of(2019,?9,?10);??
獲取年、月、日、星期幾
int?year?=?localDate.getYear();??
int?year1?=?localDate.get(ChronoField.YEAR);??
Month?month?=?localDate.getMonth();??
int?month1?=?localDate.get(ChronoField.MONTH_OF_YEAR);??
int?day?=?localDate.getDayOfMonth();??
int?day1?=?localDate.get(ChronoField.DAY_OF_MONTH);??
DayOfWeek?dayOfWeek?=?localDate.getDayOfWeek();??
int?dayOfWeek1?=?localDate.get(ChronoField.DAY_OF_WEEK);??
LocalTime
只會(huì)獲取幾點(diǎn)幾分幾秒
創(chuàng)建 LocalTime
?LocalTime?localTime?=?LocalTime.of(13,?51,?10);??
?LocalTime?localTime1?=?LocalTime.now();??
獲取時(shí)分秒
//獲取小時(shí)??
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);??
LocalDateTime
獲取年月日時(shí)分秒,等于LocalDate+LocalTime
創(chuàng)建 LocalDateTime
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);??
獲取 LocalDate
LocalDate?localDate2?=?localDateTime.toLocalDate();??
獲取 LocalTime
LocalTime?localTime2?=?localDateTime.toLocalTime();??
Instant
獲取秒數(shù)
創(chuàng)建 Instant對(duì)象
Instant?instant?=?Instant.now();??
獲取秒數(shù)
long?currentSecond?=?instant.getEpochSecond();??
獲取毫秒數(shù)
long?currentMilli?=?instant.toEpochMilli();??
個(gè)人覺得如果只是為了獲取秒數(shù)或者毫秒數(shù),使用System.currentTimeMillis()來(lái)得更為方便
修改LocalDate、LocalTime、LocalDateTime、Instant
LocalDate、LocalTime、LocalDateTime、Instant為不可變對(duì)象,修改這些對(duì)象對(duì)象會(huì)返回一個(gè)副本
增加、減少年數(shù)、月數(shù)、天數(shù)等 以
LocalDateTime??
為例
LocalDateTime?localDateTime?=?LocalDateTime.of(2019,?Month.SEPTEMBER,?10,??
??????????????14,?46,?56);??
//增加一年??
localDateTime?=?localDateTime.plusYears(1);??
localDateTime?=?localDateTime.plus(1,?ChronoUnit.YEARS);??
//減少一個(gè)月??
localDateTime?=?localDateTime.minusMonths(1);??
localDateTime?=?localDateTime.minus(1,?ChronoUnit.MONTHS);??
通過
with??
修改某些值
//修改年為2019??
localDateTime?=?localDateTime.withYear(2020);??
//修改為2022??
localDateTime?=?localDateTime.with(ChronoField.YEAR,?2022);??
還可以修改月、日
時(shí)間計(jì)算
比如有些時(shí)候想知道這個(gè)月的最后一天是幾號(hào)、下個(gè)周末是幾號(hào),通過提供的時(shí)間和日期API可以很快得到答案
LocalDate?localDate?=?LocalDate.now();??
LocalDate?localDate1?=?localDate.with(firstDayOfYear());??
比如通過firstDayOfYear()返回了當(dāng)前日期的第一天日期,還有很多方法這里不在舉例說明
格式化時(shí)間
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默認(rèn)提供了多種格式化方式,如果默認(rèn)提供的不能滿足要求,可以通過DateTimeFormatter的ofPattern方法創(chuàng)建自定義格式化方式
解析時(shí)間
LocalDate?localDate1?=?LocalDate.parse("20190910",?DateTimeFormatter.BASIC_ISO_DATE);??
LocalDate?localDate2?=?LocalDate.parse("2019-09-10",?DateTimeFormatter.ISO_LOCAL_DATE);??
和SimpleDateFormat相比,DateTimeFormatter是線程安全的
小結(jié)
LocalDateTime:Date有的我都有,Date沒有的我也有,日期選擇請(qǐng)Pick Me
====================== Update On 2019/09/18 =================
SpringBoot中應(yīng)用LocalDateTime
將LocalDateTime字段以時(shí)間戳的方式返回給前端 添加日期轉(zhuǎn)化類
public?class?LocalDateTimeConverter?extends?JsonSerializer?{??
????@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;??
對(duì)前端傳入的日期進(jìn)行格式化 在
LocalDateTime??
字段上添加
@DateTimeFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss")??
注解即可,如下:
@DateTimeFormat(pattern?=?"yyyy-MM-dd?HH:mm:ss")??
protected?LocalDateTime?gmtModified;??
更多精彩?
在公眾號(hào)【程序員編程】對(duì)話框輸入以下關(guān)鍵詞 查看更多優(yōu)質(zhì)內(nèi)容! 大數(shù)據(jù)?|?Java?|?1024?|?電子書?|?速查表? Python進(jìn)階?|?面試?|?手冊(cè)?|?成神?|?思想?|?小程序 命令行?|?人工智能?|?軟件測(cè)試?|?Web前端?|?Python 獲取更多學(xué)習(xí)資料
視頻 |?面試 |?技術(shù) | 電子書?
