時間戳是指格林威治時間1970年01月01日00時00分00秒起至現在的總毫秒數,是所有時間的基礎,其他時間可以通過時間戳轉換得到。Java中本來已經有相關獲取時間戳的方法,Java8后增加新的類Instant等專用於處理時間戳問題。
1 獲取時間戳的方法和性能對比
1.1 獲取時間戳方法
Java8以前可以使用System.currentTimeMillis() 、new Date().getTime() 、和Calendar.getInstance().getTimeInMillis()獲取。Java8以后可以另外通過Instant.now().toEpochMilli()和Clock.systemUTC().millis()獲取。
比較簡單,下面直接看代碼:
/** * 使用System獲取時間戳 */ @Test public void getEpochMilliWithSystem(){ long s = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { System.currentTimeMillis(); } System.out.println("getEpochMilliWithSystem cost:"+(System.currentTimeMillis()-s)); } /** * 使用Date獲取時間戳 */ @Test public void getEpochMilliWithDate(){ long s = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { new Date().getTime(); } System.out.println("getEpochMilliWithDate cost:"+(System.currentTimeMillis()-s)); } /** * 使用Calendar獲取時間戳 */ @Test public void getEpochMilliWithCalendar(){ long s = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { Calendar.getInstance().getTimeInMillis(); } System.out.println("getEpochMilliWithCalendar cost:"+(System.currentTimeMillis()-s)); } /** * 使用Instant獲取時間戳 */ @Test public void getEpochMilliWithInstant(){ long s = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { Instant.now().toEpochMilli(); } System.out.println("getEpochMilliWithInstant cost:"+(System.currentTimeMillis()-s)); } /** * 使用Clock獲取時間戳 */ @Test public void getEpochMilliWithClock(){ long s = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { Clock.systemUTC().millis(); } System.out.println("getEpochMilliWithClock cost:"+(System.currentTimeMillis()-s)); }
查看過上面相關源碼,基本都是通過System.currentTimeMillis() 來創建對象的。比如 new Date:
public Date() { this(System.currentTimeMillis()); }
1.2 性能對比
上面代碼執行輸出:
getEpochMilliWithSystem cost:5 getEpochMilliWithDate cost:38 getEpochMilliWithCalendar cost:1094 getEpochMilliWithInstant cost:106 getEpochMilliWithClock cost:17
通過1.1 中的分析得知基本都是通過System.currentTimeMillis() 來創建對象的System.currentTimeMillis()最快,性能最好。
所以,性能排序:System > Clock > Date > Instant > Calendar 。
2.時間戳轉換為其他類
2.1 時間戳和其他類型的轉換
/** * 時間戳epochMilli毫秒轉Date * @param epochMilli * @return */ public static Date toDate(long epochMilli){ Objects.requireNonNull(epochMilli, "epochMilli"); return new Date(epochMilli); } /** * 時間戳epochMilli毫秒轉LocalDateTime * @param epochMilli * @return */ public static LocalDateTime toLocalDateTime(long epochMilli) { Objects.requireNonNull(epochMilli, "epochMilli"); return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneId.systemDefault()); } /** * 時間戳epochMilli毫秒轉LocalDate * @param epochMilli * @return */ public static LocalDate toLocalDate(long epochMilli) { Objects.requireNonNull(epochMilli, "epochMilli"); return toLocalDateTime(epochMilli).toLocalDate(); } /** * 時間戳epochMilli毫秒轉Instant * @param epochMilli * @return */ public static Instant toInstant(long epochMilli) { Objects.requireNonNull(epochMilli, "epochMilli"); return Instant.ofEpochMilli(epochMilli); } /** * 時間戳epochMilli毫秒轉ZonedDateTime,時區為系統默認時區 * @param epochMilli * @return */ public static ZonedDateTime toZonedDateTime(long epochMilli) { Objects.requireNonNull(epochMilli, "epochMilli"); return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneId.systemDefault()) .atZone(ZoneId.systemDefault()); } /** * 時間戳epochMilli轉Timestamp * @param epochMilli * @return */ public static Timestamp toTimestamp(long epochMilli){ return new Timestamp(epochMilli); } /** * Date轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param date * @return */ public static long toEpochMilli(Date date){ Objects.requireNonNull(date, "date"); return date.getTime(); } /** * LocalDateTime轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param localDateTime * @return */ public static long toEpochMilli(LocalDateTime localDateTime){ return toInstant(localDateTime).toEpochMilli(); } /** * LocalDate轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param localDate * @return */ public static long toEpochMilli(LocalDate localDate){ return toInstant(localDate).toEpochMilli(); } /** * Instant轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param instant * @return */ public static long toEpochMilli(Instant instant){ Objects.requireNonNull(instant, "instant"); return instant.toEpochMilli(); } /** * ZonedDateTime轉時間戳,注意,zonedDateTime時區必須和當前系統時區一致,不然會出現問題 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param zonedDateTime * @return */ public static long toEpochMilli(ZonedDateTime zonedDateTime) { Objects.requireNonNull(zonedDateTime, "zonedDateTime"); return zonedDateTime.toInstant().toEpochMilli(); } /** * Timestamp轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param timestamp * @return */ public static long toEpochMilli(Timestamp timestamp){ Objects.requireNonNull(timestamp, "timestamp"); return timestamp.getTime(); }
測試代碼:
/** * 時間戳轉換測試 */ @Test public void epochMilliConverterTest(){ System.out.println("===================epochMilliConverterTest====================="); Date date = new Date(); long epochMilli = date.getTime(); System.out.println("epochMilli:"+epochMilli); System.out.println("===================ToOther====================="); System.out.println(DateTimeConverterUtil.toDate(epochMilli)); System.out.println(DateTimeConverterUtil.toLocalDateTime(epochMilli)); System.out.println(DateTimeConverterUtil.toLocalDate(epochMilli)); System.out.println(DateTimeConverterUtil.toInstant(epochMilli)); System.out.println(DateTimeConverterUtil.toZonedDateTime(epochMilli)); System.out.println(DateTimeConverterUtil.toTimestamp(epochMilli)); System.out.println("===================toEpochMilli====================="); System.out.println(DateTimeConverterUtil.toEpochMilli(new Date())); System.out.println(DateTimeConverterUtil.toEpochMilli(LocalDateTime.now())); // 另一種方式: +8 時區 System.out.println(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()); System.out.println(DateTimeConverterUtil.toEpochMilli(LocalDate.now())); System.out.println(DateTimeConverterUtil.toEpochMilli(Instant.now())); System.out.println(DateTimeConverterUtil.toEpochMilli(ZonedDateTime.now())); System.out.println(DateTimeConverterUtil.toEpochMilli(new Timestamp(System.currentTimeMillis()))); }
輸出:
===================epochMilliConverterTest===================== epochMilli:1587950768191 ===================ToOther===================== Mon Apr 27 09:26:08 CST 2020 2020-04-27T09:26:08.191 2020-04-27 2020-04-27T01:26:08.191Z 2020-04-27T09:26:08.191+08:00[Asia/Shanghai] 2020-04-27 09:26:08.191 ===================toEpochMilli===================== 1587950768304 1587950768304 1587950768304 1587916800000 1587950768305 1587950768305 1587950768305
3 Timestamp
Timestamp是Java8以前處理時間戳的類。Timestamp和其他類型的轉換
/** * Timestamp轉LocalDateTime * @param timestamp * @return */ public static LocalDateTime toLocalDateTime(Timestamp timestamp) { Objects.requireNonNull(timestamp, "timestamp"); return timestamp.toLocalDateTime(); } /** * Timestamp轉Instant * @param timestamp * @return */ public static Instant toInstant(Timestamp timestamp) { Objects.requireNonNull(timestamp, "timestamp"); return timestamp.toInstant(); } /** * Timestamp轉時間戳 * 從1970-01-01T00:00:00Z開始的毫秒值 * @param timestamp * @return */ public static long toEpochMilli(Timestamp timestamp){ Objects.requireNonNull(timestamp, "timestamp"); return timestamp.getTime(); } /** * Date轉Timestamp * @param date * @return */ public static Timestamp toTimestamp(Date date){ Objects.requireNonNull(date, "date"); return new Timestamp(date.getTime()); } /** * LocalDateTime轉Timestamp * @param localDateTime * @return */ public static Timestamp toTimestamp(LocalDateTime localDateTime){ Objects.requireNonNull(localDateTime, "localDateTime"); return Timestamp.valueOf(localDateTime); } /** * Instant轉Timestamp * @param instant * @return */ public static Timestamp toTimestamp(Instant instant){ Objects.requireNonNull(instant, "instant"); return Timestamp.from(instant); } /** * 時間戳epochMilli轉Timestamp * @param epochMilli * @return */ public static Timestamp toTimestamp(long epochMilli){ return new Timestamp(epochMilli); }
測試代碼:
/** * Timestamp轉換測試 */ @Test public void timestampConverterTest(){ System.out.println("===================timestampConverterTest====================="); Timestamp timestamp = new Timestamp(System.currentTimeMillis()); long epochMilli = timestamp.getTime(); System.out.println("epochMilli:"+epochMilli); System.out.println("===================ToOther====================="); System.out.println(DateTimeConverterUtil.toLocalDateTime(timestamp)); System.out.println(DateTimeConverterUtil.toInstant(timestamp)); System.out.println(DateTimeConverterUtil.toEpochMilli(timestamp)); System.out.println("===================toEpochMilli====================="); System.out.println(DateTimeConverterUtil.toTimestamp(new Date())); System.out.println(DateTimeConverterUtil.toTimestamp(LocalDateTime.now())); System.out.println(DateTimeConverterUtil.toTimestamp(Instant.now())); System.out.println(DateTimeConverterUtil.toTimestamp(epochMilli)); }
輸出:
===================timestampConverterTest===================== epochMilli:1587950937677 ===================ToOther===================== 2020-04-27T09:28:57.677 2020-04-27T01:28:57.677Z 1587950937677 ===================toEpochMilli===================== 2020-04-27 09:28:57.774 2020-04-27 09:28:57.781 2020-04-27 09:28:57.782 2020-04-27 09:28:57.677
4 Instant
Java8可以使用Instant方便的獲取時間戳相關的信息。
4.1 創建方式
public static Instant now() { return Clock.systemUTC().instant(); }
Instant now方法默認使用的是UTC,協調世界時。now(Clock clock)方法 clock參數可以設置時區信息,就可以獲取不同時區的Instant,比如 Clock systemDefaultZone()
或指定時區 Clock system(ZoneId zone)等。
4.2 獲取時間戳
public long toEpochMilli() 獲取時間戳 單位為毫秒。
public long getEpochSecond() 獲取時間戳 單位為秒。
5.總結
通過上面可以看出,時間戳是所有時間創建和轉換的基礎,通過簡單的System.currentTimeMillis()獲取到,但時間戳只是一個簡單的數字,不轉換為其他時間類沒有意義,比如 年、月、日、時、分、秒、星期、閏年、時區、夏令時等,更多相關的比如各種節假日,星座等附加意義的信息。