LocalDateTime用法

轉(zhuǎn)自:java8 — 新日期時間API篇

前言

最近看別人項目源碼豺撑,發(fā)現(xiàn)Java8新的日期時間API很方便強(qiáng)大,所以轉(zhuǎn)載該入門介紹博客,記錄一下桃煎。

使用新時間日期API的必要性

在java8以前零蓉,或許:

  • 當(dāng)你在做有關(guān)時間日期的操作時笤受,你會想到用Date;
  • 當(dāng)你在做日期、月份敌蜂、天數(shù)相加減時箩兽,你會想到用Calendar;
  • 當(dāng)你需要對時間日期進(jìn)行格式化時,你會想到使用SimpleDateFormat或DateFormat下的其他子類章喉;
    ……

但是汗贫,你必須知道身坐,以上有關(guān)的時間日期操作對象,都是可變的芳绩、線程不安全的掀亥,同時,如果作為一個經(jīng)常寫過類似代碼的人來說妥色,盡管有相關(guān)對象提供某些操作搪花,但并不能很快、很簡單的就能得到最終想要的結(jié)果嘹害,如:要計算兩個時間點之間相差的年撮竿、月、日笔呀、周幢踏、時、分许师、秒等房蝉,這些計算盡管原有API也能夠?qū)崿F(xiàn),但原有API除了線程不安全之外微渠,另外一個不足之處就是代碼繁瑣搭幻,性能低!

為何我們總提多線程下逞盆,線程不安全檀蹋?對于初學(xué)者來說,可能覺得能夠簡單實現(xiàn)出功能就已經(jīng)足夠云芦,但是真正的開發(fā)項目是不可能僅僅考慮功能的實現(xiàn)的俯逾,還要考慮項目的安全性、穩(wěn)定性舅逸、高性能桌肴、高可用性等等!因此琉历,作為java開發(fā)者识脆,多線程的知識是必不可少的。而也正因為多線程善已,才會出現(xiàn)一大堆問題(簡稱線程安全性問題)灼捂,作為開發(fā)者,就應(yīng)該寫出不僅能實現(xiàn)功能的代碼换团,還要是線程安全的代碼悉稠。那么,學(xué)習(xí)并熟悉掌握新的線程安全的API就顯得非常重要了艘包!

沒錯的猛,java8出的新的時間日期API都是線程安全的耀盗,并且性能更好,代碼更簡潔卦尊!

新時間日期API常用叛拷、重要對象介紹

  • ZoneId: 時區(qū)ID,用來確定Instant和LocalDateTime互相轉(zhuǎn)換的規(guī)則
  • Instant: 用來表示時間線上的一個點(瞬時)
  • LocalDate: 表示沒有時區(qū)的日期, LocalDate是不可變并且線程安全的
  • LocalTime: 表示沒有時區(qū)的時間, LocalTime是不可變并且線程安全的
  • LocalDateTime: 表示沒有時區(qū)的日期時間, LocalDateTime是不可變并且線程安全的
  • Clock: 用于訪問當(dāng)前時刻岂却、日期忿薇、時間,用到時區(qū)
  • Duration: 用秒和納秒表示時間的數(shù)量(長短)躏哩,用于計算兩個日期的“時間”間隔
  • Period: 用于計算兩個“日期”間隔

其中署浩,LocalDate、LocalTime扫尺、LocalDateTime是新API里的基礎(chǔ)對象筋栋,絕大多數(shù)操作都是圍繞這幾個對象來進(jìn)行的,有必要搞清楚:

LocalDate : 只含年月日的日期對象
LocalTime :只含時分秒的時間對象
LocalDateTime : 同時含有年月日時分秒的日期對象

本文將以實例講解日常開發(fā)中常用到的時間日期操作正驻,如:

獲取當(dāng)前日期弊攘、時間
指定時間日期創(chuàng)建對應(yīng)的對象
計算兩個時間點的間隔
判斷兩個時間的前后
時間日期的格式化
獲取時間戳
時間、日期相加減
獲取給定時間點的年份姑曙、月份襟交、周、星期等
……

新時間日期API詳解與示例

獲取當(dāng)前時間
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);

運行結(jié)果:


image.png
根據(jù)指定日期/時間創(chuàng)建對象
LocalDate localDate = LocalDate.of(2018, 1, 13);
LocalTime localTime = LocalTime.of(9, 43, 20);
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 13, 9, 43, 20);
System.out.println(localDate);
System.out.println(localTime);
System.out.println(localDateTime);

運行結(jié)果:


image.png
日期時間的加減
  • 對于LocalDate,只有精度大于或等于日的加減渣磷,如年、月授瘦、日醋界;
  • 對于LocalTime,只有精度小于或等于時的加減,如時提完、分形纺、秒、納秒徒欣;
  • 對于LocalDateTime,則可以進(jìn)行任意精度的時間相加減逐样;
LocalDateTime localDateTime = LocalDateTime.now();
//以下方法的參數(shù)都是long型,返回值都是LocalDateTime
LocalDateTime plusYearsResult = localDateTime.plusYears(2L);
LocalDateTime plusMonthsResult = localDateTime.plusMonths(3L);
LocalDateTime plusDaysResult = localDateTime.plusDays(7L);
LocalDateTime plusHoursResult = localDateTime.plusHours(2L);
LocalDateTime plusMinutesResult = localDateTime.plusMinutes(10L);
LocalDateTime plusSecondsResult = localDateTime.plusSeconds(10L);
        
System.out.println("當(dāng)前時間是 : " + localDateTime + "\n"
        + "當(dāng)前時間加2年后為 : " + plusYearsResult + "\n"
        + "當(dāng)前時間加3個月后為 : " + plusMonthsResult + "\n"
        + "當(dāng)前時間加7日后為 : " + plusDaysResult + "\n"
        + "當(dāng)前時間加2小時后為 : " + plusHoursResult + "\n"
        + "當(dāng)前時間加10分鐘后為 : " + plusMinutesResult + "\n"
        + "當(dāng)前時間加10秒后為 : " + plusSecondsResult + "\n"
        );
    
//也可以以另一種方式來相加減日期打肝,即plus(long amountToAdd, TemporalUnit unit)
//                  參數(shù)1 : 相加的數(shù)量脂新, 參數(shù)2 : 相加的單位
LocalDateTime nextMonth = localDateTime.plus(1, ChronoUnit.MONTHS);
LocalDateTime nextYear = localDateTime.plus(1, ChronoUnit.YEARS);
LocalDateTime nextWeek = localDateTime.plus(1, ChronoUnit.WEEKS);
        
System.out.println("now : " + localDateTime + "\n"
        + "nextYear : " + nextYear + "\n"
        + "nextMonth : " + nextMonth + "\n"
        + "nextWeek :" + nextWeek + "\n"
        );
        
//日期的減法用法一樣,在此不再舉例

運行結(jié)果:


image.png
將年粗梭、月争便、日等修改為指定的值,并返回新的日期(時間)對象

析: 其效果與時間日期相加減差不多断医,如今天是2018-01-13滞乙,要想變?yōu)?018-01-20有兩種方式
a. localDate.plusDays(20L) -> 相加指定的天數(shù)
b. localDate.withDayOfYear(20) -> 直接指定到哪一天

LocalDate localDate = LocalDate.now();
//當(dāng)前時間基礎(chǔ)上奏纪,指定本年當(dāng)中的第幾天,取值范圍為1-365,366
LocalDate withDayOfYearResult = localDate.withDayOfYear(200);
//當(dāng)前時間基礎(chǔ)上斩启,指定本月當(dāng)中的第幾天序调,取值范圍為1-29,30,31
LocalDate withDayOfMonthResult = localDate.withDayOfMonth(5);
//當(dāng)前時間基礎(chǔ)上,直接指定年份
LocalDate withYearResult = localDate.withYear(2017);
//當(dāng)前時間基礎(chǔ)上兔簇,直接指定月份
LocalDate withMonthResult = localDate.withMonth(5);
System.out.println("當(dāng)前時間是 : " + localDate + "\n"
        + "指定本年當(dāng)中的第200天 : " + withDayOfYearResult + "\n"
        + "指定本月當(dāng)中的第5天 : " + withDayOfMonthResult + "\n"
        + "直接指定年份為2017 : " + withYearResult + "\n"
        + "直接指定月份為5月 : " + withMonthResult + "\n"
        );

運行結(jié)果:


image.png
獲取日期的年月日周時分秒
LocalDateTime localDateTime = LocalDateTime.now();
int dayOfYear = localDateTime.getDayOfYear();
int dayOfMonth = localDateTime.getDayOfMonth();
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
System.out.println("今天是" + localDateTime + "\n"
        + "本年當(dāng)中第" + dayOfYear + "天" + "\n"
        + "本月當(dāng)中第" + dayOfMonth + "天" + "\n"
        + "本周中星期" + dayOfWeek.getValue() + "-即" + dayOfWeek + "\n");
        
//獲取當(dāng)天時間的年月日時分秒
int year = localDateTime.getYear();
Month month = localDateTime.getMonth();
int day = localDateTime.getDayOfMonth();
int hour = localDateTime.getHour();
int minute = localDateTime.getMinute();
int second = localDateTime.getSecond();
System.out.println("今天是" + localDateTime + "\n"
        + "年 : " + year + "\n"
        + "月 : " + month.getValue() + "-即 "+ month + "\n"
        + "日 : " + day + "\n"
        + "時 : " + hour + "\n"
        + "分 : " + minute + "\n"
        + "秒 : " + second + "\n"
        );

運行結(jié)果:

image.png
時間日期前后的比較與判斷
//判斷兩個時間點的前后
LocalDate localDate1 = LocalDate.of(2017, 8, 8);
LocalDate localDate2 = LocalDate.of(2018, 8, 8);
boolean date1IsBeforeDate2 = localDate1.isBefore(localDate2);
System.out.println("date1IsBeforeDate2 : " + date1IsBeforeDate2);
// date1IsBeforeDate2 == true
判斷是否為閏年
LocalDate now = LocalDate.now();
System.out.println("now : " + now + ", is leap year ? " + );
java8時鐘 : clock()
//返回當(dāng)前時間发绢,根據(jù)系統(tǒng)時間和UTC
Clock clock = Clock.systemUTC();
// 運行結(jié)果: SystemClock[Z]
System.out.println(clock);
時間戳

事實上Instant就是java8以前的Date,
可以使用以下兩個類中的方法在這兩個類型之間進(jìn)行轉(zhuǎn)換男韧,
比如Date.from(Instant)就是用來把Instant轉(zhuǎn)換成java.util.date的朴摊,
而new Date().toInstant()就是將Date轉(zhuǎn)換成Instant的

Instant instant = Instant.now();
//2019-06-08T16:50:19.174Z
System.out.println(instant);
Date date = Date.from(instant);
Instant instant2 = date.toInstant();
//Sun Jun 09 00:50:19 CST 2019
System.out.println(date);
//2019-06-08T16:50:19.174Z
System.out.println(instant2);
計算時間、日期間隔

Duration:用于計算兩個“時間”間隔
Period:用于計算兩個“日期”間隔

//計算兩個日期的日期間隔-年月日
LocalDate date1 = LocalDate.of(2018, 2, 13);
LocalDate date2 = LocalDate.of(2017, 3, 12);
//內(nèi)部是用date2-date1此虑,所以得到的結(jié)果是負(fù)數(shù)
Period period = Period.between(date1, date2);
System.out.println("相差年數(shù) : " + period.getYears());
System.out.println("相差月數(shù) : " + period.getMonths());
System.out.println("相差日數(shù) : " + period.getDays());
//還可以這樣獲取相差的年月日
System.out.println("-------------------------------");
long years = period.get(ChronoUnit.YEARS);
long months = period.get(ChronoUnit.MONTHS);
long days = period.get(ChronoUnit.DAYS);
System.out.println("相差的年月日分別為 : " + years + "," + months + "," + days);
//注意甚纲,當(dāng)獲取兩個日期的間隔時,并不是單純的年月日對應(yīng)的數(shù)字相加減朦前,而是會先算出具體差多少天介杆,在折算成相差幾年幾月幾日的
        
//計算兩個時間的間隔
System.out.println("-------------------------------");
LocalDateTime date3 = LocalDateTime.now();
LocalDateTime date4 = LocalDateTime.of(2018, 1, 13, 22, 30, 10);
Duration duration = Duration.between(date3, date4);
System.out.println(date3 + " 與 " + date4 + " 間隔  " + "\n"
        + " 天 :" + duration.toDays() + "\n"
        + " 時 :" + duration.toHours() + "\n"
        + " 分 :" + duration.toMinutes() + "\n"
        + " 毫秒 :" + duration.toMillis() + "\n"
        + " 納秒 :" + duration.toNanos() + "\n"
        );
//注意,并沒有獲得秒差的韭寸,但既然可以獲得毫秒春哨,秒就可以自行獲取了

運行結(jié)果:


image.png

當(dāng)計算程序的運行時間時,應(yīng)當(dāng)使用時間戳Instant

Instant ins1 = Instant.now();
for (int i = 0; i < 10000000; i++) {
            //循環(huán)一百萬次
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println("程序運行耗時為 : " + duration.toMillis() + "毫秒");
時間日期的格式化(格式化后返回的類型是String)
1. 使用jdk自身配置好的日期格式
//使用jdk自身配置好的日期格式
DateTimeFormatter formatter1 = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime date1 = LocalDateTime.now();
//反過來調(diào)用也可以 : date1.format(formatter1);
String date1Str = formatter1.format(date1);
System.out.println(date1Str);

運行結(jié)果:


image.png
2. 使用自定義格式
LocalDateTime date1 = LocalDateTime.now();
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String date2Str = formatter2.format(date1);
System.out.println(date2Str);

運行結(jié)果:


image.png

注:自定義轉(zhuǎn)化的格式一定要與日期類型對應(yīng)

  • LocalDate只能設(shè)置僅含年月日的格式
  • LocalTime只能設(shè)置僅含時分秒的格式
  • LocalDateTime可以設(shè)置含年月日時分秒的格式

代碼如下:

DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(formatter3.format(LocalDate.now()));
        
System.out.println("-------------------------------");
        
DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(formatter4.format(LocalTime.now()));

運行結(jié)果:


image.png
將時間字符串形式轉(zhuǎn)化為日期對象
String datetime =  "2018-01-13 21:27:30";  
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse(datetime, dtf);  
System.out.println(ldt);  

運行結(jié)果:


image.png

注:格式的寫法必須與字符串的形式一樣
2018-01-13 21:27:30 對應(yīng) yyyy-MM-dd HH:mm:ss
20180113213328 對應(yīng) yyyyMMddHHmmss
否則會報運行時異常恩伺!

但要記赘氨场:得到的最終結(jié)果都是類似2018-01-13T21:27:30的格式

因為在輸出LocalDateTime對象時,會調(diào)用其重寫的toString方法晶渠。

@Override
    public String toString() {
        return date.toString() + 'T' + time.toString();
    }
將時間日期對象轉(zhuǎn)為格式化后的時間日期對象
//新的格式化API中凰荚,格式化后的結(jié)果都默認(rèn)是String,有時我們也需要返回經(jīng)過格式化的同類型對象
LocalDateTime ldt1 = LocalDateTime.now();
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String temp = dtf1.format(ldt1);
LocalDateTime formatedDateTime = LocalDateTime.parse(temp, dtf1);
System.out.println(formatedDateTime);

運行結(jié)果:

image.png
long毫秒值轉(zhuǎn)換為日期
System.out.println("---------long毫秒值轉(zhuǎn)換為日期---------");
DateTimeFormatter df= DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String longToDateTime = df.format(LocalDateTime.ofInstant(
   Instant.ofEpochMilli(System.currentTimeMillis()),ZoneId.of("Asia/Shanghai")));
System.out.println(longToDateTime);

運行結(jié)果:


image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末褒脯,一起剝皮案震驚了整個濱河市便瑟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌番川,老刑警劉巖到涂,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颁督,居然都是意外死亡践啄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門沉御,熙熙樓的掌柜王于貴愁眉苦臉地迎上來往核,“玉大人,你說我怎么就攤上這事嚷节∧羧澹” “怎么了虎锚?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衩婚。 經(jīng)常有香客問我窜护,道長,這世上最難降的妖魔是什么非春? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任柱徙,我火速辦了婚禮,結(jié)果婚禮上奇昙,老公的妹妹穿的比我還像新娘护侮。我一直安慰自己,他們只是感情好储耐,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布羊初。 她就那樣靜靜地躺著,像睡著了一般什湘。 火紅的嫁衣襯著肌膚如雪长赞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天闽撤,我揣著相機(jī)與錄音得哆,去河邊找鬼。 笑死哟旗,一個胖子當(dāng)著我的面吹牛贩据,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闸餐,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼饱亮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绎巨?” 一聲冷哼從身側(cè)響起近尚,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蠕啄,失蹤者是張志新(化名)和其女友劉穎场勤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歼跟,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡和媳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哈街。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片留瞳。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骚秦,靈堂內(nèi)的尸體忽然破棺而出她倘,到底是詐尸還是另有隱情璧微,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布硬梁,位于F島的核電站前硫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荧止。R本人自食惡果不足惜屹电,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望跃巡。 院中可真熱鬧危号,春花似錦、人聲如沸素邪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽娘香。三九已至苍狰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烘绽,已是汗流浹背淋昭。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留安接,地道東北人翔忽。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像盏檐,于是被迫代替她去往敵國和親歇式。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容