還在用SimpleDateFormat?Java8都發布N年了,轉LocalDateTime吧

前言

Java8發佈,已有數年之久,可是發現不少人都仍是堅持着用SimpleDateFormat和Date進行時間操做。SimpleDateFormat這個類不是線程安全的,在使用的時候稍不注意,就會產生致命的問題。Date這個類,是能夠從新設置時間的,這對於一些類內部的屬性來講,是很是不安全的。java

SimpleDateFormat是線程不安全的類

在阿里巴巴規約手冊裏,強制規定SimpleDateFormat是線程不安全的類,當定義爲靜態變量時,必須加鎖處理。忽略線程安全問題,正是大多數Java初學者在進行時間轉化時容易踩坑的點。安全

還在用SimpleDateFormat?Java8都發布N年了,轉LocalDateTime吧

Date屬性能夠從新設置時間

好比有User.java以下:bash

public class User {
​
 private String username;
​
 private Date birthday;
​
 public User(String username, Date birthday) {
 this.username = username;
 this.birthday = birthday;
 }
​
 public String getUsername() {
 return username;
 }
​
 public void setUsername(String username) {
 this.username = username;
 }
​
 public Date getBirthday() {
 return birthday;
 }
​
 public void setBirthday(Date birthday) {
 this.birthday = birthday;
 }
}
複製代碼

咱們實例化該Userapp

public class Main {
​
 public static void main(String[] args) {
 User user = new User("happyjava", new Date());
 }
​
}
複製代碼

這固然沒什麼問題,可是我能夠經過user.getBirthday()方法獲取到birthday的引用,從而修改直接修改birthday的值。以下:工具

public static void main(String[] args) {
 User user = new User("happyjava", new Date());
 System.out.println(user.getBirthday());
 Date birthday = user.getBirthday();
 birthday.setTime(11111111L);
 System.out.println(user.getBirthday());
}
複製代碼

輸出結果以下:測試

還在用SimpleDateFormat?Java8都發布N年了,轉LocalDateTime吧

這裏能夠看到,user對象的birthday屬性被修改掉了。這也是Date對象的弊端所在,咱們能夠經過改寫getter方法,使它返回一個新的Date對象便可解決,以下:ui

public Date getBirthday() {
// return birthday;
 return new Date(birthday.getTime());
 }
複製代碼

切記這裏是不能夠用clone方法來生成返回一個新的Date對象的,由於Date類能夠被繼承,你不能肯定調用者是否給birthday設置了一個Date的子類。this

Java8提供的新的時間類庫LocalDateTime

Java8提供了LocalDateTime來替代傳統的Date來處理時間,下面,咱們就來探討下這個類庫的使用方法吧。spa

1.獲取當前時間線程

能夠經過 LocalDateTime localDateTime = LocalDateTime.now();方法來獲取當前時間,測試以下:

@Test
public void testNow() {
 LocalDateTime localDateTime = LocalDateTime.now();
 System.out.println(localDateTime);
}
複製代碼

輸出結果

2019-05-06T22:25:07.309
複製代碼

2.根據時間戳初始化時間

@Test
public void testNewFromTimestamp() {
 Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
 LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.of("+8"));
 System.out.println(dateTime);
}
複製代碼

這裏的+8意思是東八區,下同。

輸出結果:

2019-05-06T22:27:34.567
複製代碼

3.根據字符串獲取時間

可使用LocalDateTime.parse方法對字符串進行轉化成時間,若是不傳pattern,默認是2019-05-06T11:16:12.361格式。

@Test
public void testNewFromString() {
 // 1.默認格式 2019-05-06T11:16:12.361
 String dateStr = "2019-05-06T11:16:12.361";
 LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
 System.out.println(localDateTime);
 // 2. 自定義格式
 String pattern = "yyyy-MM-dd HH:mm:ss";
 dateStr = "2019-01-01 12:12:12";
 localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
 System.out.println(localDateTime);
}
複製代碼

輸出結果:

2019-05-06T11:16:12.361
2019-01-01T12:12:12
複製代碼

4.時間轉化成字符串

能夠經過DateTimeFormatter的format方法,將LocalDateTime轉化成字符串。

@Test
public void testToString() {
 LocalDateTime now = LocalDateTime.now(ZoneId.of("+8"));
 String pattern = "yyyy-MM-dd HH:mm:ss";
 DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
 String format = formatter.format(now);
 System.out.println(format);
}
複製代碼

輸出結果:

2019-05-06 22:33:03
複製代碼

5.LocalDateTime轉時間戳

@Test
public void testDateToTimeMillis() {
 LocalDateTime dateTime = LocalDateTime.now();
 long epochMilli = dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
 System.out.println(epochMilli);
}
複製代碼

輸出結果:

1557153504304
複製代碼

總結

由於DateTimeFormatter是線程安全的,因此在實際使用LocalDateTime的時候,能夠把DateTimeFormatter定義成靜態常量的方式進行使用。以上列舉了比較經常使用的時間操做,LocalDateTime還能夠作不少事情,這個就讓讀者自行去挖掘吧。我本身封裝了個LocalDateTime工具類,只作過簡單的自測,你們能夠參考一下:

package happy.localdatetime;
​
​
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
​
/**
 * @author Happy
 */
public class DateTimeUtils {
​
 private DateTimeUtils() {
 }
​
 private final static String COMMON_PATTERN = "yyyy-MM-dd HH:mm:ss";
​
 private final static DateTimeFormatter COMMON_FORMATTER = DateTimeFormatter.ofPattern(COMMON_PATTERN);
​
 private final static ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.of("+8");
​
 /**
 * 默認 yyyy-MM-dd HH:mm:ss 格式
 */
 public static String dateToString(LocalDateTime dateTime) {
 assert dateTime != null;
 return COMMON_FORMATTER.format(dateTime);
 }
​
 /**
 * 默認 yyyy-MM-dd HH:mm:ss 格式
 */
 public static LocalDateTime stringToDate(String dateStr) {
 assert dateStr != null;
 return LocalDateTime.parse(dateStr, COMMON_FORMATTER);
 }
​
 public static String dateToString(LocalDateTime dateTime, DateTimeFormatter formatter) {
 assert dateTime != null;
 return formatter.format(dateTime);
 }
​
 public static LocalDateTime stringToDate(String dateStr, DateTimeFormatter formatter) {
 assert dateStr != null;
 return LocalDateTime.parse(dateStr, formatter);
 }
​
 public static long dateToTimeMillis(LocalDateTime dateTime) {
 assert dateTime != null;
 return dateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli();
 }
​
 public static LocalDateTime timeMillisToDate(long timeMillis) {
 Instant instant = Instant.ofEpochMilli(timeMillis);
 return LocalDateTime.ofInstant(instant, DEFAULT_ZONE_OFFSET);
 }
​
 public static void main(String[] args) {
 String s = dateToString(LocalDateTime.now());
 System.out.println(s);
 System.out.println();
 String dateStr = "2019-01-01 12:12:12";
 LocalDateTime localDateTime = stringToDate(dateStr);
 System.out.println(localDateTime);
 System.out.println();
 System.out.println(dateToTimeMillis(localDateTime));
 System.out.println();
 System.out.println(timeMillisToDate(System.currentTimeMillis()));
 }
​
}
複製代碼
相關文章
相關標籤/搜索