跟上 Java 8 : 日期和時間實用技巧

當(dāng)你開始使用Java操作日期和時間的時候阱当,會有一些棘手斗蒋。你也許會通過System.currentTimeMillis() 來返回1970年1月1日到今天的毫秒數(shù)辑舷∮钪牵或者使用Date類來操作日期砾莱;當(dāng)遇到加減月份瑞筐、天數(shù)的時候 你又需要用到Calendar類;當(dāng)需要格式化日期的時候需要使用java.text.DateFormat類腊瑟。 總而言之在Java中操作日期不是很方便聚假,以至于很多開發(fā)者不得不使用第三方庫,比如: joda-time闰非。

現(xiàn)有API存在的問題

線程安全: Date和Calendar不是線程安全的膘格,你需要編寫額外的代碼處理線程安全問題

API設(shè)計和易用性: 由于Date和Calendar的設(shè)計不當(dāng)你無法完成日常的日期操作

ZonedDate和Time: 你必須編寫額外的邏輯處理時區(qū)和那些舊的邏輯

好在JSR 310規(guī)范中為Java8添加了新的API, 在java.time包中财松,新的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ù)量

最常用的就是LocalDate舶掖、LocalTime球昨、LocalDateTime了,從它們的名字就可以看出是操作日期 和時間的访锻。這些類是主要用于當(dāng)時區(qū)不需要顯式地指定的上下文褪尝。在本章節(jié)中我們將討論最常用的api。

LocalDate

LocalDate代表一個IOS格式(yyyy-MM-dd)的日期期犬,可以存儲 生日河哑、紀(jì)念日等日期。 獲取當(dāng)前的日期:

LocalDate localDate = LocalDate.now();

System.out.println("localDate: " + localDate);

localDate: 2017-07-20

LocalDate可以指定特定的日期龟虎,調(diào)用of或parse方法返回該實例:

LocalDate.of(2017, 07, 20);

LocalDate.parse("2017-07-20");

當(dāng)然它還有一些其他方法璃谨,我們一起來看看:

為今天添加一天,也就是獲取明天

LocalDate tomorrow = LocalDate.now().plusDays(1);

從今天減去一個月

LocalDate prevMonth = LocalDate.now().minus(1, ChronoUnit.MONTHS);

下面寫兩個例子,分別解析日期 2017-07-20佳吞,獲取每周中的星期和每月中的日:

DayOfWeek thursday = LocalDate.parse("2017-07-20").getDayOfWeek();

System.out.println("周四: " + thursday);

int twenty = LocalDate.parse("2017-07-20").getDayOfMonth();

System.out.println("twenty: " + twenty);

試試今年是不是閏年:

boolean leapYear = LocalDate.now().isLeapYear();

System.out.println("是否閏年: " + leapYear);

判斷是否在日期之前或之后:

boolean notBefore = LocalDate.parse("2017-07-20")

.isBefore(LocalDate.parse("2017-07-22"));

System.out.println("notBefore: " + notBefore);

boolean isAfter = LocalDate.parse("2017-07-20").isAfter(LocalDate.parse("2017-07-22"));

System.out.println("isAfter: " + isAfter);

獲取這個月的第一天:

LocalDate firstDayOfMonth = LocalDate.parse("2017-07-20")

.with(TemporalAdjusters.firstDayOfMonth());

System.out.println("這個月的第一天: " + firstDayOfMonth);

firstDayOfMonth = firstDayOfMonth.withDayOfMonth(1);

System.out.println("這個月的第一天: " + firstDayOfMonth);

判斷今天是否是我的生日拱雏,例如我的生日是 2009-07-20

LocalDate birthday = LocalDate.of(2009, 07, 20);

MonthDay birthdayMd = MonthDay.of(birthday.getMonth(), birthday.getDayOfMonth());

MonthDay today = MonthDay.from(LocalDate.now());

System.out.println("今天是否是我的生日: " + today.equals(birthdayMd));

LocalTime

LocalTime表示一個時間,而不是日期底扳,下面介紹一下它的使用方法铸抑。

獲取現(xiàn)在的時間,輸出15:01:22.144

LocalTime now = LocalTime.now();

System.out.println("現(xiàn)在的時間: " + now);

將一個字符串時間解析為LocalTime衷模,輸出15:02

LocalTime nowTime = LocalTime.parse("15:02");

System.out.println("時間是: " + nowTime);

使用靜態(tài)方法of創(chuàng)建一個時間

LocalTime nowTime = LocalTime.of(15, 02);

System.out.println("時間是: " + nowTime);

使用解析字符串的方式并添加一小時鹊汛,輸出16:02

LocalTime nextHour = LocalTime.parse("15:02").plus(1, ChronoUnit.HOURS);

System.out.println("下一個小時: " + nextHour);

獲取時間的小時、分鐘

int hour = LocalTime.parse("15:02").getHour();

System.out.println("小時: " + hour);

int minute = LocalTime.parse("15:02").getMinute();

System.out.println("分鐘: " + minute);

我們也可以通過之前類似的API檢查一個時間是否在另一個時間之前阱冶、之后

boolean isBefore = LocalTime.parse("15:02").isBefore(LocalTime.parse("16:02"));

boolean isAfter = LocalTime.parse("15:02").isAfter(LocalTime.parse("16:02"));

System.out.println("isBefore: " + isBefore);

System.out.println("isAfter: " + isAfter);

輸出 isBefore: true, isAfter: false刁憋。

在LocalTime類中也將每天的開始和結(jié)束作為常量供我們使用:

System.out.println(LocalTime.MAX);

System.out.println(LocalTime.MIN);

輸出:

23:59:59.999999999

00:00

LocalTime就這些了,下面我們來了解一下LocalDateTime

LocalDateTime

LocalDateTime是用來表示日期和時間的木蹬,這是一個最常用的類之一至耻。

獲取當(dāng)前的日期和時間:

LocalDateTime now = LocalDateTime.now();

System.out.println("現(xiàn)在: " + now);

輸出

現(xiàn)在: 2017-07-20T15:17:19.926

下面使用靜態(tài)方法和字符串的方式分別創(chuàng)建LocalDateTime對象

LocalDateTime.of(2017, Month.JULY, 20, 15, 18);

LocalDateTime.parse("2017-07-20T15:18:00");

``

同時`LocalDateTime`也提供了相關(guān)API來對日期和時間進行增減操作:

```java

LocalDateTime tomorrow = now.plusDays(1);

System.out.println("明天的這個時間: " + tomorrow);

LocalDateTime minusTowHour = now.minusHours(2);

System.out.println("兩小時前: " + minusTowHour);

這個類也提供一系列的get方法來獲取特定單位:

Month month = now.getMonth();

System.out.println("當(dāng)前月份: " + month);

日期格式化

在日常開發(fā)中我們用到最多的也許就是日期、時間的格式化了镊叁,那在Java8種該如何操作呢尘颓?

LocalDateTime now = LocalDateTime.now();

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

System.out.println("默認(rèn)格式化: " + now);

System.out.println("自定義格式化: " + now.format(dateTimeFormatter));

LocalDateTime localDateTime = LocalDateTime.parse("2017-07-20 15:27:44", dateTimeFormatter);

System.out.println("字符串轉(zhuǎn)LocalDateTime: " + localDateTime);

也可以使用DateTimeFormatter的format方法將日期、時間格式化為字符串

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

String dateString = dateTimeFormatter.format(LocalDate.now());

System.out.println("日期轉(zhuǎn)字符串: " + dateString);

日期周期

Period類用于修改給定日期或獲得的兩個日期之間的區(qū)別意系。

給初始化的日期添加5天:

LocalDate initialDate = LocalDate.parse("2017-07-20");

LocalDate finalDate = initialDate.plus(Period.ofDays(5));

System.out.println("初始化日期: " + initialDate);

System.out.println("加日期之后: " + finalDate);

周期API中提供給我們可以比較兩個日期的差別泥耀,像下面這樣獲取差距天數(shù):

long between = ChronoUnit.DAYS.between(initialDate, finalDate);

System.out.println("差距天數(shù): " + between);

上面的代碼會返回5,當(dāng)然你想獲取兩個日期相差多少小時也是簡單的蛔添。

與遺留代碼轉(zhuǎn)換

在之前的代碼中你可能出現(xiàn)了大量的Date類痰催,如何將它轉(zhuǎn)換為Java8種的時間類呢?

Date和Instant互相轉(zhuǎn)換

Date date = Date.from(Instant.now());

Instant instant = date.toInstant();

Date轉(zhuǎn)換為LocalDateTime

LocalDateTime localDateTime = LocalDateTime.from(new Date());

System.out.println(localDateTime);

LocalDateTime轉(zhuǎn)Date

Date date =

Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

LocalDate轉(zhuǎn)Date

Date date =

Date.from(LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迎瞧,一起剝皮案震驚了整個濱河市夸溶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凶硅,老刑警劉巖缝裁,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異足绅,居然都是意外死亡捷绑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門氢妈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粹污,“玉大人,你說我怎么就攤上這事首量∽撤裕” “怎么了进苍?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸭叙。 經(jīng)常有香客問我觉啊,道長,這世上最難降的妖魔是什么沈贝? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任杠人,我火速辦了婚禮,結(jié)果婚禮上宋下,老公的妹妹穿的比我還像新娘搜吧。我一直安慰自己,他們只是感情好杨凑,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著摆昧,像睡著了一般撩满。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绅你,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天伺帘,我揣著相機與錄音,去河邊找鬼忌锯。 笑死伪嫁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偶垮。 我是一名探鬼主播张咳,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼似舵!你這毒婦竟也來了脚猾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤砚哗,失蹤者是張志新(化名)和其女友劉穎龙助,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛛芥,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡提鸟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仅淑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片称勋。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漓糙,靈堂內(nèi)的尸體忽然破棺而出铣缠,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布蝗蛙,位于F島的核電站蝇庭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏捡硅。R本人自食惡果不足惜哮内,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壮韭。 院中可真熱鬧北发,春花似錦、人聲如沸喷屋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屯曹。三九已至狱庇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恶耽,已是汗流浹背密任。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留偷俭,地道東北人浪讳。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像涌萤,于是被迫代替她去往敵國和親淹遵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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