者:何甜甜在嗎 來源:http://1t.click/a7Gm
在項目開發過程中經常遇到時間處理,但是你真的用對了嗎,理解阿里巴巴開發手冊中禁用static修飾SimpleDateFormat嗎?
通過閱讀本篇文章你將了解到:
為什么需要LocalDate、LocalTime、LocalDateTime【java8新提供的類】;
java8新的時間API的使用方式,包括創建、格式化、解析、計算、修改。
# 為什么需要LocalDate、LocalTime、LocalDateTime
1.Date如果不格式化,打印出的日期可讀性差
Tue Sep 10 09:34:04 CST 2019
2.使用SimpleDateFormat對時間進行格式化,但SimpleDateFormat是線程不安全的SimpleDateFormat的format方法最終調用代碼:
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 < compiledPattern.length; ) {
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是共享變量,并且這個共享變量沒有做線程安全控制。當多個線程同時使用相同的SimpleDateFormat對象【如用static修飾的SimpleDateFormat】調用format方法時,多個線程會同時調用calendar.setTime方法,可能一個線程剛設置好time值
另外的一個線程馬上把設置的time值給修改了導致返回的格式化時間可能是錯誤的。在多并發情況下使用SimpleDateFormat需格外注意 SimpleDateFormat除了format是線程不安全以外,parse方法也是線程不安全的。parse方法實際調用alb.establish(calendar).getTime方法來解析,alb.establish(calendar)方法里主要完成了
a、重置日期對象cal的屬性值
b、使用calb中中屬性設置cal
c、返回設置好的cal對象
但是這三步不是原子操作
多線程并發如何保證線程安全 - 避免線程之間共享一個SimpleDateFormat對象,每個線程使用時都創建一次SimpleDateFormat對象=> 創建和銷毀對象的開銷大 - 對使用format和parse方法的地方進行加鎖=> 線程阻塞性能差 - 使用ThreadLocal保證每個線程最多只創建一次SimpleDateFormat對象=> 較好的方法
1.Date對時間處理比較麻煩,比如想獲取某年、某月、某星期,以及n天以后的時間,如果用Date來處理的話真是太難了,你可能會說Date類不是有getYear、getMonth這些方法嗎,獲取年月日很Easy,但都被棄用了啊
# Come On 一起使用java8全新的日期和時間API
只會獲取年月日
創建LocalDate
//獲取當前年月日
LocalDate localDate=LocalDate.now;
//構造指定的年月日
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
LocalTime localTime=LocalTime.of(13, 51, 10);
LocalTime localTime1=LocalTime.now;
獲取時分秒
//獲取小時
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);
獲取年月日時分秒,等于LocalDate+LocalTime
創建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對象
Instant instant=Instant.now;
獲取秒數
long currentSecond=instant.getEpochSecond;
獲取毫秒數
long currentMilli=instant.toEpochMilli;
個人覺得如果只是為了獲取秒數或者毫秒數,使用System.currentTimeMillis來得更為方便
修改LocalDate、LocalTime、LocalDateTime、Instant
LocalDate、LocalTime、LocalDateTime、Instant為不可變對象,修改這些對象對象會返回一個副本
增加、減少年數、月數、天數等 以LocalDateTime為例
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);
還可以修改月、日
比如有些時候想知道這個月的最后一天是幾號、下個周末是幾號,通過提供的時間和日期API可以很快得到答案
LocalDate localDate=LocalDate.now;
LocalDate localDate1=localDate.with(firstDayOfYear);
比如通過firstDayOfYear返回了當前日期的第一天日期,還有很多方法這里不在舉例說明
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方法創建自定義格式化方式
LocalDate localDate1=LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate2=LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);
和SimpleDateFormat相比,DateTimeFormatter是線程安全的
LocalDateTime:Date有的我都有,Date沒有的我也有,日期選擇請Pick Me
======================Update On 2019/09/18=================
SpringBoot中應用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;
———— e n d ————
微服務、高并發、JVM調優、面試專欄等20 大進階架構師專題請關注公眾號【Java進階架構師】后在菜單欄查看。
者:何甜甜在嗎
https://juejin.im/post/5d7787625188252388753eae
在項目開發過程中經常遇到時間處理,但是你真的用對了嗎,理解阿里巴巴開發手冊中禁用static修飾SimpleDateFormat嗎?
通過閱讀本篇文章你將了解到:
1.Date如果不格式化,打印出的日期可讀性差
Tue Sep 10 09:34:04 CST 2019
2.使用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)方法里主要完成了
a、重置日期對象cal的屬性值b、使用calb中中屬性設置calc、返回設置好的cal對象
但是這三步不是原子操作
多線程并發如何保證線程安全 - 避免線程之間共享一個SimpleDateFormat對象,每個線程使用時都創建一次SimpleDateFormat對象=> 創建和銷毀對象的開銷大 - 對使用format和parse方法的地方進行加鎖=> 線程阻塞性能差 - 使用ThreadLocal保證每個線程最多只創建一次SimpleDateFormat對象=> 較好的方法
1.Date對時間處理比較麻煩,比如想獲取某年、某月、某星期,以及n天以后的時間,如果用Date來處理的話真是太難了,你可能會說Date類不是有getYear、getMonth這些方法嗎,獲取年月日很Easy,但都被棄用了啊
只會獲取年月日
創建LocalDate
//獲取當前年月日
LocalDate localDate=LocalDate.now();
//構造指定的年月日
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
只會獲取幾點幾分幾秒
創建LocalTime
LocalTime localTime=LocalTime.of(13, 51, 10);
LocalTime localTime1=LocalTime.now();
獲取時分秒
//獲取小時
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
獲取年月日時分秒,等于LocalDate+LocalTime
創建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
獲取秒數
創建Instant對象
Instant instant=Instant.now();
獲取秒數
long currentSecond=instant.getEpochSecond();
獲取毫秒數
long currentMilli=instant.toEpochMilli();
個人覺得如果只是為了獲取秒數或者毫秒數,使用System.currentTimeMillis()來得更為方便
LocalDate、LocalTime、LocalDateTime、Instant為不可變對象,修改這些對象對象會返回一個副本
增加、減少年數、月數、天數等 以LocalDateTime為例
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);
還可以修改月、日
比如有些時候想知道這個月的最后一天是幾號、下個周末是幾號,通過提供的時間和日期API可以很快得到答案
LocalDate localDate=LocalDate.now();
LocalDate localDate1=localDate.with(firstDayOfYear());比如通過firstDayOfYear()返回了當前日期的第一天日期,還有很多方法這里不在舉例說明
比如通過firstDayOfYear()返回了當前日期的第一天日期,還有很多方法這里不在舉例說明
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方法創建自定義格式化方式
LocalDate localDate1=LocalDate.parse("20190910", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate localDate2=LocalDate.parse("2019-09-10", DateTimeFormatter.ISO_LOCAL_DATE);
和SimpleDateFormat相比,DateTimeFormatter是線程安全的
LocalDateTime:Date有的我都有,Date沒有的我也有,日期選擇請Pick Me
SpringBoot中應用LocalDateTime
將LocalDateTime字段以時間戳的方式返回給前端添加日期轉化類
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;
對前端傳入的日期進行格式化 在LocalDateTime字段上添加@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")注解即可,如下:
頭條創作挑戰賽#
在Java中,LocalDateTime類用于處理日期和時間,它提供了一種不依賴于時區的表示方式。以下是一些常見的LocalDateTime的使用方法:
LocalDateTime now=LocalDateTime.now(); //獲取當前日期和時間。
LocalDateTime specificDateTime=LocalDateTime.of(2023,5,26,10,30,0); //指定日期和時間創建對象
LocalDateTime parsedDateTime=LocalDateTime.parse("2023-05-26T10:30:00");//從字符串解析日期和時間
//獲取年份
int year=dateTime.getYear();
//獲取月份
Month month=dateTime.getMonth();
//獲取日期
int day=dateTime.getDayOfMonth();
//獲取小時
int hour=dateTime.getHour();
//獲取分鐘
int minute=dateTime.getMinute();
//獲取秒數
int second=dateTime.getSecond();
//修改年份
LocalDateTime modifiedDateTime=dateTime.withYear(2024);
//增加小時
LocalDateTime addedHourDateTime=dateTime.plusHours(2);
//減少天數
LocalDateTime subtractedDaysDateTime=dateTime.minusDays(1);
String formattedDateTime=dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 比較第一個日期時間是否在第二個之前
boolean isBefore=dateTime1.isBefore(dateTime2);
//比較第一個日期時間是否在第二個之后
boolean isAfter=dateTime1.isAfter(dateTime2);
//比較兩個日期時間是否相等
boolean isEqual=dateTime1.isEqual(dateTime2);
//可以將時分秒和納秒都設為0
LocalDateTime todayStart=LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
//使用Java8中的LocalDateTime類和Java8中的DayOfWeek枚舉來獲取當天星期
LocalDateTime now=LocalDateTime.now();
DayOfWeek dayOfWeek=now.getDayOfWeek();
System.out.println("今天星期"+dayOfWeek.getValue());
*請認真填寫需求信息,我們會在24小時內與您取得聯系。