Java十九篇:常用類 時間日期類

2021-12-25 小劉Java之路



在計算機中,應該如何表示日期和時間呢?

我們經常看到的日期和時間表示方式如下:

2019-11-20 0:15:00 GMT+00:00

11/19/2019 19:15:00 America/New_York

如果直接以字符串的形式存儲,那麼不同的格式,不同的語言會讓表示方式非常繁瑣。

在理解日期和時間的表示方式之前,我們先要理解數據的存儲和展示。

當我們定義一個整型變量並賦值時:

int n = 123400;

編譯器會把上述字符串(程序源碼就是一個字符串)編譯成字節碼。在程序的運行期,變量n指向的內存實際上是一個4位元組區域:

│00│01│e2│08│

注意到計算機內存除了二進位的0/1外沒有其他任何格式。上述十六機制是為了簡化表示。

當我們用System.out.println(n)列印這個整數的時候,實際上println()這個方法在內部把int類型轉換成String類型,然後列印出字符串123400。

它們實際上是數據的展示格式,分別按英國時區、中國時區、紐約時區對同一個時刻進行展示。而這個「同一個時刻」在計算機中存儲的本質上只是一個整數,我們稱它為Epoch Time。

Epoch Time是計算從1970年1月1日零點(格林威治時區/GMT+00:00)到現在所經歷的秒數,例如:

1574208900表示從從1970年1月1日零點GMT時區到該時刻一共經歷了1574208900秒,換算成倫敦、北京和紐約時間分別是:

1574208900 = 北京時間2019-11-20 8:15:00
= 倫敦時間2019-11-20 0:15:00
= 紐約時間2019-11-19 19:15:00

img格式化字符串和日期對象的DateFormat格式轉換類

一、古老的Date類Date這個類自jdk1.0開始就被設計出來, 從它的原始碼中我們也是可以看出來,Date類曾經扮演過很重要的角色,jdk早期的版本中有關日期和時間的操作幾乎都是由Date類完成的,下面我們一起看看它的源碼:

private transient long fastTime;

二、處理年月日的年曆類Calendar以前我們是可以使用Date來處理日期年月日的,但是由於該類不支持國際化等原因,現在其中大部分方法被註解,不再推薦使用,現在的Date類更像是代表著某一個時刻的對象,而處理年月日的這種轉換則完全交給了Calendar類處理。所以Calendar目前是日期時間處理中的核心類,接下來我們看看其中源碼:

//和Date一樣封裝了毫秒屬性
protected long time;
protected int fields[];
//封裝了十七個靜態常量
public final static int ERA = 0;
public final static int YEAR = 1;
public final static int MONTH = 2;
public final static int WEEK_OF_YEAR = 3;
....
public final static int DST_OFFSET = 16;

三、DateFormat處理格式轉換DateFormat是一個抽象類,該類主要用於實現Date對象和字符串之間相互轉換, 涉及到兩個轉換的方法:

//將Date類型轉換為String類型
public final String format(Date date)
//將String類型轉換Date類型
public Date parse(String source)

四、優秀的實現類SimpleDateFormatSimpleDateFormat是DateFormat的一個優秀的實現類,它增強了一個重要的性質。它允許自定義格式輸出模板。構造SimpleDateFormat實例的時候,可以傳入一個pattern作為輸出模板。看個例子:

    public static void main(String[] args) {
Calendar c = Calendar.getInstance();
SimpleDateFormat sm = new SimpleDateFormat("yyyy年MM月dd日 E HH時mm分ss秒");
System.out.println(sm.format(c.getTime()));

輸出結果:

2017年05月29日 星期一 20時25分31秒

上述的代碼中,字符串yyyy年MM月dd日 E HH時mm分ss秒就是一個模板pattern,其中:

五、開源第三方庫Joda-TimeJoda-Time庫中的內容還是很多的,我們簡單了解下基本的使用即可,至於深入學習該庫,大家可以自行嘗試,此處限於篇幅,不再贅述。在該庫中DateTime相當於jdk中Calendar,主要完成對日期年月日的計算操作。首先我們通過簡單易理解的方式創建DateTime的實例對象:

//2017-05-29 21:40
DateTime dt = new DateTime(2017,5,29,21,40);

//2017-05-29 21:40 50秒
DateTime dt2 = new DateTime(2017,5,29,21,40,50);

Java8以前在java.util這個包裡,主要包括Date、Calendar和TimeZone這幾個類;

Java8中推出了全新的日期時間類在java.time這個包裡面,使用起來更加簡單和安全,常用的有以下幾個

LocalDate:本地日期,只包括日期

LocalTime:本地時間,只包括時間

LocalDateTime:本地日期時間,包括日期和時間

ZonedDateTime:完整的本地日期時間,包括日期,時間,和時區

代碼片段:獲取當前日期
LocalDate localDate = LocalDate.now();
System.out.println("當前日期為:" + localDate);//當前日期為:2021-12-24

LocalDate提供了獲取年、月、日的快捷方法
System.out.println("當前年為:" + localDate.getYear());//當前年為:2021
System.out.println("當前月為:" + localDate.getMonth());//當前月為:JUNE
System.out.println("當前月為:" + localDate.getMonthValue());//當前月為:6
System.out.println("當前日為當月的第:" + localDate.getDayOfMonth() + "天");//當前日為當月的第:19天
System.out.println("當前日為當周的:" + localDate.getDayOfWeek());//當前日為當周的:FRIDAY
System.out.println("當前日為當年的第:" + localDate.getDayOfYear() + "天");//當前日為當年的第:171天

指定日期,這裡的月對應的就是實際的月
 LocalDate zdDate = LocalDate.of(2020, 06, 18);
System.out.println("指定日期為:" + zdDate);//指定日期為:2021-12-24

判斷兩個日期是否相等,直接使用equals
boolean flag = localDate.equals(zdDate);
System.out.println("兩個日期是否相等" + flag);//兩個日期是否相等false
boolean isEqual = localDate.isEqual(zdDate);
System.out.println("兩個日期是否相等" + flag);//兩個日期是否相等false

判斷是否為閏年
System.out.println("是否為閏年:" + localDate.isLeapYear());//是否為閏年:true

只需要年月、月日,獲取方式有多種
YearMonth yearMonth = YearMonth.now();
System.out.println("當前年月為:" + yearMonth);//當前年月為:2020-06
YearMonth currentYearMonth1 = YearMonth.from(localDate);
System.out.println("當前年月為:" + currentYearMonth1);//當前年月為:2020-06
YearMonth zdYearMonth = YearMonth.of(zdDate.getYear(), zdDate.getMonth());
System.out.println("指定年月為:" + zdYearMonth);//指定年月為:2020-06

返回當月天數
System.out.println("當月天數為:" + yearMonth.lengthOfMonth());//當月天數為:30

獲取月日
MonthDay monthDay = MonthDay.now();
System.out.println("當前月日為:" + monthDay);//當前月日為:--06-19
MonthDay currentMonthDay = MonthDay.from(localDate);
System.out.println("當前月日為:" + currentMonthDay);//當前月日為:--06-19
MonthDay zdMonthDay = MonthDay.of(zdDate.getMonth(), zdDate.getDayOfMonth());
System.out.println("指定月日為:" + zdMonthDay);//指定月日為:--06-18

日期的加減

通過LocalDate的plus方法增加年、月、周、天,也可以使用plus後直接跟年(plusYears)、月(plusMonths)、周(plusWeeks)、日(plusDays);minus方法減少年、月、周、天,也可以使用minus後直接跟年(minusYears)、月(minusMonths)、周(minusWeeks)、日(minusDays)

LocalDate nextWeek = localDate.plus(1, ChronoUnit.WEEKS);
System.out.println("一周後日期為:" + nextWeek);//一周後日期為:2020-06-26
LocalDate newWeek = localDate.plusWeeks(1);
System.out.println("一周後日期為:" + newWeek);//一周後日期為:2020-06-26
LocalDate oldWeek = localDate.minus(1, ChronoUnit.WEEKS);
System.out.println("一周前日期為:" + oldWeek);//一周前日期為:2020-06-12

獲取當前時間,默認時間格式為hh:mm:ss:nnn
LocalTime localTime = LocalTime.now();
System.out.println("當前時間為:" + localTime);//當前時間為:16:17:35.717
LocalTime zdLocalTime = LocalTime.of(14, 40, 30);
System.out.println("指定時間為:" + zdLocalTime);//指定時間為:14:40:30

時間的加減

通過LocalTime的plus方法增加時、分、秒,也可以使用plus後直接跟時(plusHours)、分(plusMinutes)、秒(plusSeconds);minus方法減少時、分、秒,也可以使用minus後直接跟時(minusHours)、分(minusMinutes)、秒(minusSeconds)

LocalTime newLocalTimeHour = localTime.plusHours(2);
System.out.println("2個小時後時間為:" + newLocalTimeHour);//2個小時後時間為:18:17:35.717
LocalTime oldLocalTimeHour = localTime.minusHours(2);
System.out.println("2個小時前時間為:" + oldLocalTimeHour);//2個小時前時間為:14:17:35.717
LocalTime newLocalTimeMinute = localTime.plusMinutes(20);
System.out.println("20分鐘後時間為:" + newLocalTimeMinute);//20分鐘後時間為:16:37:35.717
LocalTime oldLocalTimeMinute = localTime.minusMinutes(20);
System.out.println("20分鐘前時間為:" + oldLocalTimeMinute);//20分鐘前時間為:15:57:35.717

使用Duration計算兩個時間間隔多少小時、分鐘、秒
long minutes = Duration.between(zdLocalTime, localTime).toMinutes();
System.out.println("兩個時間間隔為:" + minutes);//兩個時間間隔為:97

使用Duration計算兩個日期間隔天數
	LocalDate localDate = LocalDate.now();
LocalDate agoDate = LocalDate.of(2020, 12, 20);
long days = Duration.between(agoDate.atStartOfDay(), localDate.atStartOfDay()).toDays();

使用ChronoUnit計算兩個日期間隔天數
LocalDate localDate = LocalDate.now();
LocalDate agoDate = LocalDate.of(2020, 12, 20);
long days = ChronoUnit.DAYS.between(agoDate, localDate);

使用LocalDate計算兩個日期間隔天數
LocalDate localDate = LocalDate.now();
LocalDate agoDate = LocalDate.of(2020, 12, 20);
long days = localDate.toEpochDay() - agoDate.toEpochDay();

使用Period計算兩個日期間隔多少年、月、天
long days = Period.between(zdDate, localDate).getDays();
System.out.println("兩個日期間隔為:" + days);//兩個日期間隔為:1

Instant時間戳,默認使用 UTC 時區(世界協調時間)
Instant instant = Instant.now();
System.out.println(instant);//2020-06-19T08:17:35.718Z
System.out.println("時間戳秒" + instant.getEpochSecond());//時間戳秒1592554655
System.out.println("時間戳毫秒" + instant.toEpochMilli());//時間戳毫秒1592554655718
System.out.println("在1970-01-01T00:00:00上加上20秒為:" + Instant.ofEpochSecond(20));//在1970-01-01T00:00:00上加上20秒為:1970-01-01T00:00:20Z
System.out.println("在1970-01-01T00:00:00上加上20毫秒為:" + Instant.ofEpochMilli(20));//在1970-01-01T00:00:00上加上20毫秒為:1970-01-01T00:00:00.020Z

使用LocalDateTime獲取時間戳
LocalDateTime localDateTime = LocalDateTime.now();
long second = localDateTime.toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
System.out.println("當前日期時間戳(精確到秒)為:" + second);
long milli = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
System.out.println("當前日期時間戳(精確到毫秒)為:" + milli);

將時間戳轉化為LocalDateTime
LocalDateTime localDateTime1 = LocalDateTime.ofEpochSecond(second, 0, ZoneOffset.ofHours(8));
System.out.println("將時間戳(精確到秒)轉化為時間為:" + localDateTime1);
LocalDateTime localDateTime2 = LocalDateTime.ofInstant(Instant.ofEpochSecond(second), ZoneId.systemDefault());
System.out.println("將時間戳(精確到秒)轉化為時間為:" + localDateTime2);
LocalDateTime localDateTime3 = LocalDateTime.ofInstant(Instant.ofEpochMilli(milli), ZoneId.systemDefault());
System.out.println("將時間戳(精確到毫秒)轉化為時間為:" + localDateTime3);

時區偏移量計算
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println("偏移8小時後為:" + offsetDateTime);//偏移8小時後為:2020-06-19T16:30:55.011+08:00

Clock時鐘類獲取當前時間戳
Clock clock = Clock.systemUTC();
System.out.println("Clock:" + clock);//Clock:SystemClock[Z]
System.out.println("Clock時間戳為" + clock.millis());//Clock時間戳為1592555455013
Clock defaultClock = Clock.systemDefaultZone();
System.out.println(defaultClock);//SystemClock[Asia/Shanghai]
System.out.println("Clock系統時間戳為" + defaultClock.millis());//Clock系統時間戳為1592555455013

判斷日期早於或晚於
boolean isBeforeDate = localDate.isBefore(zdDate);
System.out.println("當前日期是否早於指定日期" + isBeforeDate);//當前日期是否早於指定日期false
boolean isAfterDate = localDate.isAfter(zdDate);
System.out.println("當前日期是否晚於指定日期" + isAfterDate);//當前日期是否晚於指定日期true

判斷時間早於或晚於
boolean isBeforeTime = localTime.isBefore(zdLocalTime);
System.out.println("當前時間是否早於指定時間" + isBeforeTime);//當前時間是否早於指定時間false
boolean isAfterTime = localTime.isAfter(zdLocalTime);
System.out.println("當前時間是否晚於指定時間" + isAfterTime);//當前時間是否晚於指定時間true

獲取當前日期時間
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("當前日期時間為:" + localDateTime);//當前日期時間為:2020-06-19T16:30:55.013
LocalDateTime zdLocalDateTime1 = LocalDateTime.of(2020, 06, 19, 15, 20, 30);
System.out.println("指定日期時間為:" + zdLocalDateTime1);//指定日期時間為:2020-06-19T15:20:30
LocalDateTime zdLocalDateTime2 = LocalDateTime.of(zdDate, zdLocalTime);
System.out.println("指定日期時間為:" + zdLocalDateTime2);//指定日期時間為:2020-06-18T14:40:30
LocalDateTime nextLocalDateTime = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println("下一個周日的日期時間為:" + nextLocalDateTime);//下一個周日的日期時間為:2020-06-21T16:30:55.013

帶時區的日期時間
ZoneId america = ZoneId.of("America/New_York");
ZonedDateTime zonedDateTimeNewYork = ZonedDateTime.of(localDateTime, america);
System.out.println("指定時區日期時間為:" + zonedDateTimeNewYork);//指定時區日期時間為:2020-06-19T16:30:55.013-04:00[America/New_York]

格式化日期時間
String formatLocalDate = localDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
System.out.println("格式化日期為:" + formatLocalDate);//格式化日期為:20200619
String formatLocalDateTime = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
System.out.println("格式化日期時間為:" + formatLocalDateTime);//格式化日期時間為:20200619163055

將字符串轉換為日期
LocalDate parseLocalDate = LocalDate.parse("2020-06-19", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
System.out.println("將指定的日期字符串轉換為日期為:" + parseLocalDate);//將指定的日期字符串轉換為日期為:2020-06-19

Date轉換為LocalDateTime、LocalDate
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDateTime localDateTime1 = Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
LocalDate localDate1 = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate();
LocalDate localDate2 = Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();

LocalDateTime、LocalDate轉換為Date
LocalDateTime localDateTime = LocalDateTime.now();
Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
LocalDate localDate = LocalDate.now();
Date date1 = Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());

2.

相關焦點

  • Java 日期時間處理
    Calendar由於Date存在缺陷,所以JDK又提供了java.util.Calendar來處理日期和時間.Calendar是一個抽象類,是所有日曆類的模板,因此,我們可以繼承Calendar來實現其他的曆法(比如陰曆);Java中提供了一種Calendar的默認實現java.util.GregorianCalendar
  • Java知識之常用數據結構及類
    源程序代碼如下://程序文件名為UseVector.javaimport java.util.Vector;//引入JDK的Vector類public class UseVector{    public static void main(String[] args)    {       Vector
  • Java常用類,這一次幫你總結好!
    java.lang包2.包裝類的意義:讓基本數據類型有面向對象的特徵封裝了字符串轉化成基本數據類型的方法(重點)3.包裝類常用方法:Integer.parseInt()Long.paseLong()Double.parseDouble()【參考代碼】
  • 非常強大的java時間處理工具類!
    xk-time 是時間轉換,時間計算,時間格式化,時間解析,日曆,時間cron表達式和時間NLP等的工具,使用Java8,線程安全,簡單易用,多達70幾種常用日期格式化模板,支持Java8時間類和Date,輕量級,無第三方依賴。為什麼要開發這個工具?(1)Java8以前的Date API設計不太好,使用不方便,往往會有線程安全問題。
  • Java 8新的時間日期庫的20個使用示例
    .html除了lambda表達式,stream以及幾個小的改進之外,Java 8還引入了一套全新的時間日期API,在本篇教程中我們將通過幾個簡單的任務示例來學習如何使用Java 8的這套API。Java 8仍然延用了ISO的日曆體系,並且與它的前輩們不同,java.time包中的類是不可變且線程安全的。新的時間及日期API位於java.time包中,下面是裡面的一些關鍵的類:●Instant——它代表的是時間戳●LocalDate——不包含具體時間的日期,比如2014-01-14。它可以用來存儲生日,周年紀念日,入職日期等。
  • Java8 新特性之日期-時間 API
    在Java8之前的版本中,我們處理時間類型常常使用的是java.util包下的Date類。但使用Date類卻有諸多的弊端,如:java.util.Date是非線程安全的,所有的日期類都是可變的;日期/時間類的定義並不一致,在java.util和java.sql的包下都含有Date類,在開發過程中極易出錯;日期類並不提供國際化,沒有時區支持。
  • Java 8 日期 / 時間( Date Time )API 指南
    在Java中,現有的與日期和時間相關的類存在諸多問題,其中有:Java的日期/時間類的定義並不一致,在java.util和java.sql的包中都有日期類,此外用于格式化和解析的類在java.text包中定義。java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,將其納入java.sql包並不合理。
  • 18 個示例帶你掌握 Java 8 日期時間處理!
    Java處理日期、日曆和時間的方式一直為社區所詬病,將 java.util.Date設定為可變類型,以及SimpleDateFormat的非線程安全使其應用非常受限。新API基於ISO標準日曆系統,java.time包下的所有類都是不可變類型而且線程安全。
  • Java需要掌握的常用類庫
    java.io        通過數據流、對象序列以及文件系統實現的系統輸入、輸出5.       java.net       用於實現網絡通訊應用的所有類6.       java.util       集合類、時間處理模式、日期時間工具等各類常用工具包其它還有7.
  • 一個 Java 時間工具類
    package com..util;import java.sql.Timestamp;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;public class DataUtil { /
  • 【第11章:Java常用類庫】_Math與Random類
    Math類常用方法public class Hello{   public static void main(String
  • 一文告訴你Java日期時間API到底有多爛
    最後再看「屈居」第二名的Date/Time/Calendar日期時間API,它就不得了了。畢竟此API有個很大的特點:哪怕到了現在(2021年)依舊非常常用。所以,它設計得爛帶來的實際影響是蠻大的。下面就來具體了解下它有哪些坑爹的設計和槽點,一起不吐不快。
  • Java 中日期的幾種常見操作
    在舊版本 JDK 的時代,有不少代碼中日期取值利用了 java.util.Date 類,但是由於 Date 類不便於實現國際化,其實從 JDK1.1 開始,就更推薦使用 java.util.Calendar 類進行時間和日期方面的處理。這裡便不介紹 Date 類的操作,讓我們直奔主題吧,如何利用 Calendar 類取得現在的日期時間。
  • Java世界最常用的工具類庫
    有很多實用的工具類並沒有全部列出來,只列出了最基礎的一部分,感興趣的小夥伴,可以看官方的api進行更深入的學習Apache CommonsApache Commons有很多子項目,常用的項目如下項目作用BeanUtils對Java Bean進行各種操作,複製對象,屬性Codec處理常用的編碼,解碼Collections擴展Java集合框架的操作I/O輸入/輸出工具的封裝Langjava
  • [Java包裝類]
    1 Integer2 Boolean3 Byte4 Character5 Double6 Number1 Integerjava.lang包中的Integer類、Long類和Short類,分別將基本類型int、long 和short封裝成一個類。
  • Java 類加載機制詳解
    什麼是 Java 類加載機制?Java 虛擬機一般使用 Java 類的流程為:首先將開發者編寫的 Java 原始碼(.java文件)編譯成 Java 字節碼(.class文件),然後類加載器會讀取這個 .class 文件,並轉換成 java.lang.Class 的實例。
  • Java類加載器 — classloader 的原理及應用
    虛擬機控制的,我們除了適應它的規範進行開發外,能夠幹預的空間並不多。classloader的雙親委託機制是指多個類加載器之間存在父子關係的時候,某個class類具體由哪個加載器進行加載的問題。**等等都是由根加載器加載。
  • Java Web安全 || Java基礎 · ClassLoader(類加載機制)
    點擊上方「凌天實驗室」,「星標或置頂公眾號」漏洞、技術還是其他,我都想第一時間和你分享已連載更新全部內容
  • Java基礎學習-Math與 System類
    >概述: java.lang.Math(類): Math包含執行基本數字運算的方法的工具類。        Math類構造方法被私有修飾,不能創建對象。        Math類內部都是「靜態方法」,通過「類名」直接調用即可。
  • 夯實Java基礎系列9:深入理解Class類和Object類
    這種調用方式適用於方法b()執行時間不長的情況,因為b()方法執行時間一長或者直接阻塞的話,a()方法的餘下代碼是無法執行下去的,這樣會造成整個流程的阻塞。(2)異步調用異步調用是為了解決同步調用可能出現阻塞,導致整個流程卡住而產生的一種調用方式。