preface

Java8 was released a few years ago, but many people still stick with time manipulation using SimpleDateFormat and Date. The SimpleDateFormat class is not thread-safe and can cause fatal problems when used carelessly. The Date class can reset the time, which is very insecure for some internal attributes of the class.

SimpleDateFormat is a thread-unsafe class

In the Alibaba protocol manual, it is mandatory that SimpleDateFormat be a thread-unsafe class that must be locked when defined as a static variable. Ignoring thread-safety issues is where most Java novices stumble when it comes to time conversions.

The Date property resets the time

For example, user.java looks like this:

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; }}Copy the code

We instantiate the User

public class Main {
​
 public static void main(String[] args) {
 User user = new User("happyjava", new Date()); }}Copy the code

This is fine, of course, but I can get a reference to birthday using the user.getbirthday () method and change the birthday value directly. As follows:

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());
}
Copy the code

The following output is displayed:

As you can see, the birthday property of the User object has been modified. This can be solved by rewriting the getter method to return a new Date object, as follows:

 public Date getBirthday() {
// return birthday;
 return new Date(birthday.getTime());
 }
Copy the code

Remember that you cannot use the Clone method to generate and return a new Date object, because the Date class can be inherited and you are not sure if the caller subclassed Date.

LocalDateTime, the new time class library provided by Java8

Java8 provides LocalDateTime instead of Date to handle time. Let’s explore how to use this library.

1. Obtain the current time

LocalDateTime LocalDateTime = localDatetime.now (); Method to get the current time as follows:

@Test
public void testNow() {
 LocalDateTime localDateTime = LocalDateTime.now();
 System.out.println(localDateTime);
}
Copy the code

The output

The 2019-05-06 T22:25:07. 309Copy the code

2. Initialize the time based on the timestamp

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

Plus 8 here means east 8, same thing.

Output result:

The 2019-05-06 T22: take. 567Copy the code

3. Obtain the time based on the string

The localDatetime. parse method can be used to convert a string to a time. If no pattern is passed, the default format is 2019-05-06t11:16:12.361.

@Test
public void testNewFromString// 1. Default format 2019-05-06t11:16:12.361 String dateStr ="The 2019-05-06 T11: affliction. 361";
 LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
 System.out.println(localDateTime); // 2. Customize the format String pattern ="yyyy-MM-dd HH:mm:ss";
 dateStr = "The 2019-01-01 12:12:12";
 localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
 System.out.println(localDateTime);
}
Copy the code

Output result:

The 2019-05-06 T11: affliction. 361, the 2019-01-01 T12: trueCopy the code

4. Time is converted to a string

LocalDateTime can be converted to a string using the Format method of DateTimeFormatter.

@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);
}
Copy the code

Output result:

The 2019-05-06 22:33:03Copy the code

5. Turn LocalDateTime to timestamp

@Test
public void testDateToTimeMillis() {
 LocalDateTime dateTime = LocalDateTime.now();
 long epochMilli = dateTime.toInstant(ZoneOffset.of("+ 8")).toEpochMilli();
 System.out.println(epochMilli);
}
Copy the code

Output result:

1557153504304
Copy the code

conclusion

Because the DateTimeFormatter is thread-safe, you can define the DateTimeFormatter as a static constant when actually using LocalDateTime. LocalDateTime can also do a lot of things, so let the reader find out for himself. I packaged a LocalDateTime tool class by myself, and only did a simple self-test, you can refer to it:

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"); /** * default yyyY-MM-DD HH: MM: SS format */ public static String dateToString(LocalDateTime dateTime) {assert dateTime! = null;returnCOMMON_FORMATTER.format(dateTime); } /** * default yyyY-MM-DD HH: MM :ss format */ public static LocalDateTime stringToDate(String dateStr) {assert dateStr! = null;returnLocalDateTime.parse(dateStr, COMMON_FORMATTER); } public static String dateToString(LocalDateTime dateTime, DateTimeFormatter formatter) { assert dateTime ! = null;returnformatter.format(dateTime); } public static LocalDateTime stringToDate(String dateStr, DateTimeFormatter formatter) { assert dateStr ! = null;returnLocalDateTime.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 = "The 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())); }}Copy the code