一文帶你熟練掌握Java中的日期時間相關(guān)類
一. 概念簡介
在開始學(xué)習(xí)今天的知識之前,有必要先給大家講解一下與今天內(nèi)容相關(guān)的一些概念,否則可能會讓一些小白產(chǎn)生迷惑。
1. 日期和時間的區(qū)別
首先我們得搞清楚,日期和時間的概念并不一樣。日期是指某一天,它不是連續(xù)變化的,可以說是離散的。而時間有兩種概念,一種是不帶日期的時間,如10:30:01;另一種是帶日期的時間,如2023-01-01 15:11:40。只有帶日期的時間,才能唯一確定某個時刻,而不帶日期的時間是無法確定一個唯一時刻的。
2. 本地時間
本地時間其實就是每個地方,當前所在國家所采用的標準時間。比如我們國家就是采用的北京時間,只要是在中國大陸,我們說晚上8:00見,這個8:00指的就是北京時間。即使我們國家的時區(qū),其實包括了從東五區(qū)到東九區(qū)共5個時區(qū),但我們?nèi)珖际墙y(tǒng)一采用的東八區(qū)的區(qū)時,這樣各地區(qū)人員之間的交流才不會產(chǎn)生歧義。但如果是在別的國家,那這個本地時間,就是他們國家的標準區(qū)時了,所以每個國家的標準區(qū)時可能是不同的。
3. 時區(qū)表示法
我們初中學(xué)地里的時候,就學(xué)過時區(qū)的概念,這里就不多講了。在計算機中,如果我們想準確地確定一個時間,需要把本地時間和時區(qū)結(jié)合在一起才行。其中時區(qū)有如下幾種表示方式:
GMT 或 UTC 加時區(qū)偏移表示法:如GMT+08:00 或 UTC+08:00,就表示東八區(qū)的時間。因為北京時區(qū)是東八區(qū),領(lǐng)先UTC 8個小時,所以將UTC裝換成北京時間時,要加上8小時。GMT(Greenwich Mean Time)是格林威治標準時間,UTC(Universal Time Coordinated)是世界統(tǒng)一時間或世界標準時間, GMT 和 UTC 其實基本是等價的,它們都是英國倫敦的本地時間。但UTC使用了更精確的原子鐘計時,每隔幾年會有一個閏秒,不過我們在開發(fā)時可以忽略兩者的誤差,因為計算機的時鐘在聯(lián)網(wǎng)時會自動與時間服務(wù)器同步時間。
時區(qū)縮寫表示法:如CST是China Standard Time的縮寫,即中國標準時間。但CST也是美國中部時間Central Standard Time USA的縮寫,因此有些縮寫容易產(chǎn)生混淆,開發(fā)時盡量不要使用縮寫形式。
洲/城市表示法:如Asia/Shanghai,表示上海所在地的時區(qū)。我們要特別注意,城市名稱并不是任意的城市,而是由國際標準組織規(guī)定的城市。
4. 本地化
本地化并不只包括時間這一種信息,還包括一個國家或地區(qū)所采用的日期、時間、數(shù)字、貨幣等各種信息的格式,開發(fā)時通常使用Locale進行表示。Locale由“語言_國家”的字母縮寫構(gòu)成,如“zh_CN”就表示“中文+中國”,“en_US”表示“英文+美國”。其中語言是小寫,國家是大寫。
而對于不同國家或地區(qū)的Locale日期部分來說,如中國和美國的本地時間表示方式如下:
- zh_CN:2023-01-24
- en_US:01/24/2023
5. 夏令時
夏令時(Daylight Saving Time:DST),也叫夏時制,又稱“日光節(jié)約時制”,是一種為了節(jié)約能源而人為規(guī)定地方時間的制度。一般在天亮早的夏季人為將時間調(diào)快一小時,可以使人早起早睡,減少照明量,以充分利用光照資源,從而節(jié)約照明用電。
我們國家曾經(jīng)實行過一段時間夏令時,但在1992年就廢除了,不過美國人到現(xiàn)在還在使用。所以涉及到跨國應(yīng)用開發(fā)時,相關(guān)時間的換算可能會有點復(fù)雜。因為涉及到夏令時,相同的時區(qū),如果表示的方式不同,轉(zhuǎn)換出的時間也是不同的。
6. Epoch Time時間起點
Epoch Time是一個固定的通用時間,即世界標準時間(UTC) 1970-01-01 00:00:00 UTC,它是計算機里時間開始的起點,該起點被記為0,而1970年以前的時間被認為是負數(shù)。我們知道,現(xiàn)實世界的時間誰也不知道是從什么時候開始的,但是計算機發(fā)明的時間并不長,為了方便大家進行各種開發(fā)和計算,于是國際標準委員會就給計算機設(shè)置了一個時間的起點。以這個時間為起點,每過去一秒,該數(shù)值就加1,這樣我們就可以算出對應(yīng)的公歷時間日期(不包括閏秒)。 Epoch Time在不同的編程語言中,會有幾種不同的存儲方式:
- 以秒為單位的整數(shù):1574208900,缺點是精度只能到秒;
- 以毫秒為單位的整數(shù):1574208900123,最后3位表示毫秒數(shù);
- 以秒為單位的浮點數(shù):1574208900.123,小數(shù)點后表示零點幾秒。
7. 時間戳
時間戳(timestamp),也稱為Unix時間 或 POSIX時間,它是一種時間表示方式。表示從1970年1月1日0時0分0秒(格林尼治時間)開始,一直到現(xiàn)在所經(jīng)過的秒數(shù)或毫秒數(shù)。在Java一般是用long類型來存儲該值,但在別的編程語言中有可能是使用float類型。 比如1574208900就表示從1970年1月1日零點開始,到2019年11月20日8點15分截止,一共經(jīng)歷了1574208900秒,所以換算成北京時間就是:1574208900 = 北京時間2019-11-20 8:15:00。如果我們要獲取當前的時間戳,在Java中可以使用System.currentTimeMillis()方法。
從本質(zhì)上來說,時間戳就是個時間差值,其值與時區(qū)無關(guān)。比如在UTC標準下,時間起點的時間戳就是timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
,此時對應(yīng)的北京時間是timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
了解了以上這些基本概念之后,我們就可以繼續(xù)往下學(xué)習(xí)今天其他的內(nèi)容了。
二. Date日期時間類
1. 簡介
如果我們想在Java中獲取當前的時間,可以使用 java.util.Date類 和 java.util.Calendar類來實現(xiàn)。其中,Date類封裝了系統(tǒng)的日期和時間信息,Calendar類則會根據(jù)系統(tǒng)的日歷來填充Date對象。
java.util.Date是一個表示日期和時間的類,代表了系統(tǒng)特定的時間戳。它是按照UTC時間顯示的,可以精確到毫秒,源碼內(nèi)部使用long類型進行時間的存儲。我們要注意與java.sql.Date區(qū)分,后者是用在數(shù)據(jù)庫中的類,且是按照本地時區(qū)顯示的。Date對象表示的時間,其默認順序是星期、月、日、小時、分、秒、年。
2. 構(gòu)造方法
java.util.Date類給我們提供了多個構(gòu)造方法,如下圖所示:
但是一般在開發(fā)時,我們常用的也沒有這么多,一般使用時如下形式:
- Date():創(chuàng)建Date對象并初始化,該對象可以獲取本地的當前時間,該時間會精確到毫秒。
- Date(long date):構(gòu)造一個Date對象,并接受一個從1970年1月1日起的毫秒數(shù)作為參數(shù)。
3. 常用API方法
當我們構(gòu)造出來一個Date對象之后,就可以使用它的一些API方法進行時間的操作了,這些常用的API方法如下:
序號 | 方法和描述 |
---|---|
boolean after(Date date) | 若調(diào)用該方法的Date對象,在指定的日期之后,則返回true,否則返回false。 |
boolean before(Date date) | 若調(diào)用此方法的Date對象,在指定的日期之前,則返回true,否則返回false |
int compareTo(Date date) | 比較調(diào)用此方法的Date對象和指定的日期。若兩者相等則返回0,若該對象在指定日期之前則返回負數(shù),若該對象在指定日期之后則返回正數(shù)。 |
boolean equals(Object date) | 若調(diào)用該方法的Date對象,和指定日期相等時則返回true,否則返回false。 |
long getTime( ) | 返回自1970年1月1日 00:00:00 GMT以來的毫秒數(shù)。 |
void setTime(long time) | 用從1970年1月1日00:00:00 以后的time毫秒數(shù),設(shè)置時間和日期。 |
String toString( ) | 把該Date對象轉(zhuǎn)換成dow mon dd hh:mm:ss zzz yyyy格式的字符串,其中dow是指一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。 |
4. 使用方法
4.1 基本使用
接下來我們先通過一個簡單的案例,來演示一下Date的基本用法。
import java.util.Date; /** * @author */ public class Demo01 { public static void main(String[] args) { //獲取當前時間的時間戳 long currentTimeMillis = System.currentTimeMillis(); System.out.println("時間戳="+currentTimeMillis); //獲取當前時間對象 Date date=new Date(); //Sat Feb 11 12:04:03 IRKT 2023 System.out.println("當前時間="+date); //轉(zhuǎn)為字符串:Sat Feb 11 12:04:03 IRKT 2023 System.out.println("當前時間="+date.toString()); //轉(zhuǎn)換為本地時區(qū):2023年2月11日 下午12:04:03 System.out.println("當前時間,Locale="+date.toLocaleString()); //轉(zhuǎn)換為GMT時區(qū):11 Feb 2023 04:04:03 GMT System.out.println("當前時間,GMT="+date.toGMTString()); } }
如果我們想獲取當前時間的時間戳,可以使用System.currentTimeMillis()方法。構(gòu)造出Date對象之后,我們可以直接打印該對象,就能展示出當前時間,但是這個格式并不一定符合我們中國人的閱讀習(xí)慣,后面我們可以對日期進行格式化操作。
4.2 其他用法
除了上面這些基本用法之外,Date還有其他的一些用法。
import java.util.Date; /** * @author */ public class Demo01 { public static void main(String[] args) { //獲取當前時間對象 Date date=new Date(); //獲取年月日 System.out.println("年="+(date.getYear() + 1900)); // 必須加上1900 System.out.println("月="+(date.getMonth() + 1)); // 0~11,必須加上1 System.out.println("日="+date.getDate()); // 1~31,不能加1 System.out.println("時="+date.getHours()); // 0~23 System.out.println("分="+date.getMinutes()); // 0~59,不能加1 System.out.println("秒="+date.getSeconds()); // 0~59,不能加1 System.out.println("時間戳="+date.getTime()); // 時間戳,毫秒值 //計算自己已經(jīng)活了多少天,1990年01月31日 //構(gòu)造對象的另一個方法,已過時。year:要減去1900,月份從0開始,0-11;日期是1-31 Date d1 = new Date(1990-1900, 2-1, 31); Date d2 = new Date(); long time = d2.getTime() - d1.getTime(); System.out.println("已活天數(shù)="+time/1000/60/60/24); } }
另外我們還要注意,getYear()方法返回的年份必須加上1900;getMonth()方法返回的月份是011,分別表示112月,所以要加1;而getDate()方法返回的日期范圍是1~31,就不能加1。
在打印本地時區(qū)表示的日期和時間時,不同的計算機可能會有不同的展示結(jié)果,后面我們可以使用SimpleDateFormat設(shè)置出我們想要的日期時間格式。
4.3 統(tǒng)計時間差
有時候我們要統(tǒng)計某個功能的執(zhí)行時間,此時就可以用該功能結(jié)束時的時間,減去開始時的時間,得到一個時間差,這就是該功能的執(zhí)行時間。
import java.util.Date; /** * @author */ public class Demo03 { public static void main(String[] args) { //獲取當前時間對象 //開始時間 Date startDate=new Date(); for(int i=0;i<100000;i++) { System.out.println("循環(huán)次數(shù)"+i); } //結(jié)束時間 Date endDate=new Date(); //計算時間差 long time = endDate.getTime() - startDate.getTime(); System.out.println("10w次循環(huán)的執(zhí)行時間是 "+time+" 毫秒"); } }
三. Calendar日歷類
1. 簡介
Calendar類是Java時間類Date的擴展。相比Date,它擁有更強大的功能,主要是多了可以做簡單日期和時間運算的功能,且在實現(xiàn)方式上也比Date類更復(fù)雜一些。Calendar可以用來計算日期,比如說計算下個月的日期,或者兩個月前的日期等。
Calendar類是一個抽象類,我們在實際使用時需要實現(xiàn)特定的子類,一般使用getInstance()方法創(chuàng)建即可。Calendar類有幾個主要的子類,包括java.util.GregorianCalendar和java.util.TimeZone。其中GregorianCalendar類提供了標準的日歷系統(tǒng),可以用來計算未來或過去某天的日期。TimeZone類則可以用來在不同的時區(qū)之間,轉(zhuǎn)換日期和時間。
2. Calendar常量字段
Calendar中有以下幾個常用的常量字段,用于表示不同的意義。
常量 | 描述 |
---|---|
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意義完全相同 |
Calendar.HOUR | 12小時制的小時 |
Calendar.HOUR_OF_DAY | 24小時制的小時 |
Calendar.MINUTE | 分鐘 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期幾 |
3. Calendar常用方法
除了以上常用的常量字段之外,Calendar還有一些常用的方法,如下表所示:
方法 | 描述 |
---|---|
void add(int field, int amount) | 根據(jù)日歷的規(guī)則,為給定的日歷字段 field 添加或減去指定的時間量 amount |
boolean after(Object when) | 判斷此 Calendar 表示的時間是否在指定時間 when 之后,并返回判斷結(jié)果 |
boolean before(Object when) | 判斷此 Calendar 表示的時間是否在指定時間 when 之前,并返回判斷結(jié)果 |
void clear() | 清空 Calendar 中的日期時間值 |
int compareTo(Calendar anotherCalendar) | 比較兩個 Calendar 對象表示的時間值(從格林威治時間 1970 年 01 月 01 日 00 時 00 分 00 秒至現(xiàn)在的毫秒偏移量),大則返回 1,小則返回 -1,相等返回 0 |
int get(int field) | 返回指定日歷字段的值 |
int getActualMaximum(int field) | 返回指定日歷字段可能擁有的最大值 |
int getActualMinimum(int field) | 返回指定日歷字段可能擁有的最小值 |
int getFirstDayOfWeek() | 獲取一星期的第一天。根據(jù)不同的國家地區(qū),返回不同的值 |
static Calendar getInstance() | 使用默認時區(qū)和語言壞境獲得一個日歷 |
static Calendar getInstance(TimeZone zone) | 使用指定時區(qū)和默認語言環(huán)境獲得一個日歷 |
static Calendar getInstance(TimeZone zone,Locale aLocale) | 使用指定時區(qū)和語言環(huán)境獲得一個日歷 |
Date getTime() | 返回一個表示此 Calendar 時間值(從格林威治時間1970 年 01 月 01 日 00 時 00 分 00 秒至現(xiàn)在的毫秒偏移量)的 Date 對象 |
long getTimeInMillis() | 返回此 Calendar 的時間值,以毫秒為單位 |
void set(int field, int value) | 為指定的日歷字段設(shè)置給定值 |
void set(int year, int month, int date) | 設(shè)置日歷字段 YEAR、MONTH 和 DAY_OF_MONTH 的值 |
void set(int year, int month, int date, int hourOfDay,int minute, int second) | 設(shè)置字段 YEAR、MONTH、DAY_OF_MONTH、HOUR、 MINUTE 和 SECOND 的值 |
void setFirstDayOfWeek(int value) | 設(shè)置一星期的第一天是哪一天 |
void setTimeInMillis(long millis) | 用給定的 long 值設(shè)置此 Calendar 的當前時間值 |
Calendar對象可以調(diào)用set()方法將日歷翻到任何一個時間,當參數(shù) year取負數(shù)時表示是公元前。調(diào)用 get()方法可以獲取年、月、日等時間信息,field參數(shù)的值是前面講過的Calendar靜態(tài)常量。
4. 構(gòu)建Calendar對象
Calendar類是抽象類,所以我們不能通過new的方式來構(gòu)建Calendar對象。在實際使用時,我們一般是要實現(xiàn)特定的子類,經(jīng)常是使用getInstance()方法進行創(chuàng)建。
import java.util.Calendar; /** * @author */ public class Demo04 { public static void main(String[] args) { //默認是當前日期 Calendar c1 = Calendar.getInstance(); System.out.println("c1="+c1); //創(chuàng)建一個代表2023年2月2日的Calendar對象 Calendar c2 = Calendar.getInstance(); c2.set(2023, 2-1, 2); System.out.println("c2="+c2); } }
5. 獲取當前時間
獲取到Calendar對象之后,我們可以獲取到當前日期對象的年月日時分秒等信息。
import java.util.Calendar; /** * @author */ public class Demo05 { public static void main(String[] args) { // 獲取當前時間 Calendar c = Calendar.getInstance(); int y = c.get(Calendar.YEAR); //月份要加1 int m = 1 + c.get(Calendar.MONTH); int d = c.get(Calendar.DAY_OF_MONTH); int w = c.get(Calendar.DAY_OF_WEEK); int hh = c.get(Calendar.HOUR_OF_DAY); int mm = c.get(Calendar.MINUTE); int ss = c.get(Calendar.SECOND); int ms = c.get(Calendar.MILLISECOND); //2023-2-11 7 18:10:59.847 System.out.println(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms); } }
我們要注意,Calendar是通過get()方法獲取年月日等信息的,其中返回的年份不必轉(zhuǎn)換,返回的月份仍要加1,返回的星期要特別注意,1~7分別表示周日、周一、……周六。
6. 設(shè)置時間
我們通過Calendar.getInstance()方法獲取到Calendar對象后,獲取到的其實就是當前時間。如果我們想設(shè)置某個特定的日期和時間,需要先用clear()方法清除掉之前所有的字段。
import java.util.Calendar; /** * @author */ public class Demo06 { public static void main(String[] args) { // 設(shè)置時間 Calendar c = Calendar.getInstance(); // 清除所有 c.clear(); // 設(shè)置2023年 c.set(Calendar.YEAR, 2023); // 設(shè)置2月(0~11) c.set(Calendar.MONTH, 1); // 設(shè)置2日 c.set(Calendar.DATE, 2); // 設(shè)置時間 c.set(Calendar.HOUR_OF_DAY, 21); c.set(Calendar.MINUTE, 22); c.set(Calendar.SECOND, 23); //Thu Feb 02 21:22:23 IRKT 2023 System.out.println("date="+c.getTime()); } }
我們可以利用Calendar.getTime()方法,將一個Calendar對象轉(zhuǎn)換成Date對象,后面我們就可以用SimpleDateFormat進行格式化操作了。
四. GregorianCalendar類
1. 簡介
Java中除了有Calendar類實現(xiàn)了公歷日歷,還有一個子類GregorianCalendar。在GregorianCalendar類中,定義了兩個字段:AD和BC,分別代表公歷定義的兩個時代。GregorianCalendar中的屬性和方法與Calendar類似,就不再贅述了,接下來我們直接通過一個案例來進行展示其用法。
2. 基本用法
這里我們設(shè)計一個案例,來判斷當前年份是閏年還是平年。
import java.util.Calendar; import java.util.GregorianCalendar; /** * @author */ public class Demo05 { public static void main(String[] args) { //定義一個月份數(shù)組 String months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; int year; // 使用當前時間和日期,初始化Gregorian日歷對象,默認為本地時間和時區(qū) GregorianCalendar gcalendar = new GregorianCalendar(); // 顯示當前時間和日期的信息 System.out.print("Date:"); System.out.print(months[gcalendar.get(Calendar.MONTH)]); System.out.print(" " + gcalendar.get(Calendar.DATE) + " "); System.out.println(year = gcalendar.get(Calendar.YEAR)); System.out.print("Time:"); System.out.print(gcalendar.get(Calendar.HOUR) + ":"); System.out.print(gcalendar.get(Calendar.MINUTE) + ":"); System.out.println(gcalendar.get(Calendar.SECOND)); //判斷當前年份是否為閏年 if (gcalendar.isLeapYear(year)) { System.out.println("當前年份是閏年"); } else { System.out.println("當前年份是平年"); } } }
五. 結(jié)語
至此,就把Date和擴展類Calendar給大家講解完畢,今天的內(nèi)容其實并不難,大家需要把一些常用的構(gòu)造方式及方法、常量記一下即可。
以上就是一文帶你熟練掌握Java中的日期時間相關(guān)類的詳細內(nèi)容,更多關(guān)于Java 日期時間相關(guān)類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
由淺到深帶你詳談Java實現(xiàn)數(shù)組擴容的三種方式
這篇文章主要詳細介紹了Java實現(xiàn)數(shù)組擴容的三種方式,新建一個數(shù)組,把原來數(shù)組的內(nèi)容搬到新數(shù)組中,使用system.arraycopy(),使用java.util.Arrays.copyOf()這三種方式,具有一定的參考價值,需要的朋友可以借鑒一下2023-06-06使用MyBatisPlus自動生成代碼后tomcat運行報錯的問題及解決方法
這篇文章主要介紹了使用MyBatisPlus自動生成代碼后tomcat運行報錯的問題及解決方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08Java異步線程中的CompletableFuture與@Async詳解
這篇文章主要介紹了Java異步線程中的CompletableFuture與@Async詳解,CompletableFuture是java中提供的一個異步執(zhí)行類,@Async是Spring提供的異步執(zhí)行方法,當調(diào)用方法單獨開啟一個線程進行調(diào)用,需要的朋友可以參考下2024-01-01利用feign調(diào)用返回object類型轉(zhuǎn)換成實體
這篇文章主要介紹了利用feign調(diào)用返回object類型轉(zhuǎn)換成實體,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03java.sql.SQLException問題解決以及注意事項
這篇文章主要給大家介紹了關(guān)于java.sql.SQLException問題解決以及注意事項的相關(guān)資料,這個問題其實很好解決,文中通過圖文將解決的辦法介紹的很詳細,需要的朋友可以參考下2023-07-07java中靜態(tài)代碼塊與構(gòu)造方法的執(zhí)行順序判斷
對靜態(tài)代碼塊以及構(gòu)造函數(shù)的執(zhí)行先后順序,一直很迷惑,直到最近看到一段代碼,發(fā)現(xiàn)終于弄懂了,所以這篇文章主要給大家介紹了關(guān)于如何判斷java中靜態(tài)代碼塊與構(gòu)造方法的執(zhí)行順序的相關(guān)資料,需要的朋友可以參考下。2017-12-12SpringBoot參數(shù)校驗之@Valid的使用詳解
這篇文章主要通過示例為大家詳細介紹一下介紹了SpringBoot參數(shù)校驗中@Valid的使用方法,文中的示例代碼講解詳細,需要的可以參考一下2022-06-06Java數(shù)據(jù)結(jié)構(gòu)之線段樹中的懶操作詳解
對于線段樹,若要求對區(qū)間中的所有點都進行更新,可以引入懶操作。懶操作包括區(qū)間更新和區(qū)間查詢操作。本文將通過一個示例和大家詳細聊聊線段樹中的懶操作,需要的可以參考一下2022-10-10