Java8新時間API

Java8日期/時間APIJSR-310(Java Specification Requests)的實現(xiàn)微饥,它的實現(xiàn)目標(biāo)是克服舊的日期時間實現(xiàn)中所有的缺陷,利用它可以更加方便我們?nèi)ヌ幚頃r間和日期的計算等問題。

設(shè)計原則

新的日期/時間API它遵循以下的設(shè)計原則:

  • 不變性:在新的日期/時間API中蟀淮,所有的類都被設(shè)計成不可變的蚪腐,這在多線程環(huán)境下也是沒有問題的。
  • 關(guān)注點分離:在Java8中侨糟,相比于之前舊的時間和日歷類碍扔,較大的改變是將人可讀的日期時間和機(jī)器時間(unix timestamp)明確分離,為日期(Date)秕重、時間(Time)不同、日期時間(DateTime)、時間戳(unix timestamp)以及時區(qū)定義了不同的類溶耘。
  • 清晰:在所有的類中二拐,方法都被明確定義用以完成相同的行為。舉個例子凳兵,要拿到當(dāng)前實例我們可以使用now()方法百新,在所有的類中都定義了format()parse()方法,而不是像以前那樣專門有一個獨立的類庐扫。為了更好的處理問題饭望,所有的類都使用了工廠模式和策略模式,一旦你使用了其中某個類的方法形庭,與其他類協(xié)同工作并不困難铅辞。
  • 實用操作:所有新的日期/時間API類都實現(xiàn)了一系列方法用以完成通用的任務(wù),如:加碘勉、減巷挥、 格式化、解析验靡、從日期/時間中提取單獨部分倍宾,等等雏节。
  • 可擴(kuò)展性: 新的日期/時間API是工作在ISO-8601日歷系統(tǒng)上的,但我們也可以將其應(yīng)用在非ISO的日歷上高职。

time 包

java.time包中的是類是不可變且線程安全的钩乍,下面是一些比較常用的類:

  • Instant:表示時間戳。
  • LocalDate:不包含具體時間點的日期怔锌。
  • LocalTime:不包含日期的時間點寥粹。
  • LocalDateTime:具體的日期時間點,不帶時區(qū)埃元。
  • ZonedDateTime:包含時區(qū)的完整的日期時間點涝涤,偏移量是以UTC/格林威治時間為基準(zhǔn)的。

常見用法

對于這些類岛杀,它們都有以下一些方法:

  • of:靜態(tài)工廠方法阔拳。
  • parse:靜態(tài)工廠方法,關(guān)注于解析类嗤。
  • get:獲取某些東西的值糊肠。
  • is:檢查某些東西的是否是true。
  • with:不可變的setter等價物遗锣。
  • plus:加一些量到某個對象货裹。
  • minus:從某個對象減去一些量。
  • to:轉(zhuǎn)換到另一個類型精偿。
  • at:把這個對象與另一個對象組合起來弧圆。

下面我們就來看看他們具體都是怎么用的。

計算日期/時間

獲取當(dāng)前時間/日期

以前有Date類可以獲取當(dāng)前時間还最,有Calendar類來做日歷相關(guān)操作墓阀。而在Java8中毡惜,提供了多個類來獲取當(dāng)前的日期拓轻、時間、時間戳等信息经伙。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前日期
        System.out.println(LocalDate.now());
        // 獲取當(dāng)前時間點
        System.out.println(LocalTime.now());
        // 獲取當(dāng)前時間點去掉納秒
        System.out.println(LocalTime.now().withNano(0));
        // 獲取當(dāng)前的日期時間
        System.out.println(LocalDateTime.now());
        // 獲取當(dāng)前年
        System.out.println(LocalDate.now().getYear());
    }
}

輸出:

2017-09-04
22:03:49.502
22:03:49
2017-09-04T22:03:49.502
2017

不要在意這個雞毛年份扶叉,文章寫于N久前,最近改改重新發(fā)出來的帕膜。

判斷兩個日期是否相等

Java8的眾多類中枣氧,它們都重寫了toString()方法。所以對于日期是否相同的判斷垮刹,我們可以直接使用它的equals()方法达吞。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前日期
        LocalDate today = LocalDate.now();
        // 構(gòu)建2017-09-03
        LocalDate date = LocalDate.of(2017, 9, 3);
        // 判斷是否相等
        System.out.println(today.equals(date));
    }
}

輸出:

false

判斷一個日期是否在另一個日期之前

有時候可能會有這樣的需求,需要判斷一個日期在另一個日期的前面還是后面荒典,這時候就會用到isBefore()isAfter()方法酪劫,這樣就可以方便的作出判斷吞鸭。

public class Test {
    public static void main(String[] args) {
        // 構(gòu)建2017-09-04
        LocalDate d1 = LocalDate.of(2017, 9, 4);
        // 構(gòu)建2017-09-03
        LocalDate d2 = LocalDate.of(2017, 9, 3);
        // 判斷d1是否在d2后面
        System.out.println(d1.isAfter(d2));
        // 判斷d1是否在d2前面
        System.out.println(d1.isBefore(d2));
    }
}

輸出:

true
false

可以看到我們直接可以使用isBefore()isAfter()來判斷兩個日期誰前誰后了,而不需要向之前使用Calendar來進(jìn)行麻煩的操作了覆糟。

檢查重復(fù)日期

對于一些特定的日期刻剥,比如生日、紀(jì)念日等滩字,我們可以輕易來判斷某一日期是不是我們需要的特定日期造虏。

public class Test {
    public static void main(String[] args) {
        LocalDate dateOfBirth = LocalDate.of(1992, 9, 4);
        MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
        MonthDay currentMonthDay = MonthDay.from(LocalDate.now());
        if(currentMonthDay.equals(birthday)){
            System.out.println("Happy Birthday !");
        }else{
            System.out.println("Sorry, today is not your birthday!");
        }
    }
}

輸出:

Happy Birthday !

判斷某個日期是不是周幾

同樣麦箍,我們可以很方便的來判斷某天是周幾漓藕。DayOfWeek構(gòu)建的是周幾,然后使用from()方法挟裂,來構(gòu)建某一日期為周幾撵术,這樣我們就可以輕松判斷出某一日期是周幾,而不必向以前一樣麻煩话瞧。

public class Test {
    public static void main(String[] args) {
        DayOfWeek dayOfWeek = DayOfWeek.of(2);
        DayOfWeek from = DayOfWeek.from(LocalDate.now());
        System.out.println(from.equals(dayOfWeek));
    }
}

輸出:

true

延遲或者推前時間

有時候我們可能會需要用到一些日期計算嫩与,比如,昨天交排,前天划滋,明天,一周前埃篓,一年前等处坪。在Java8中可以輕松實現(xiàn),因為這些類中已經(jīng)提供了相關(guān)方法架专。plus開頭的表示往后算同窘,minus表示往前算。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前日期
        LocalDate today = LocalDate.now();
        System.out.println(today);
        // 推前一天
        System.out.println(today.minusDays(1));
        // 延后一天
        System.out.println(today.plusDays(1));
    }
}

輸出:

2017-09-04
2017-09-03
2017-09-05

時鐘

Java8提供了時鐘類部脚,利用時鐘類可以實現(xiàn)和System.currentTimeMillis()一樣的功能想邦,還能夠獲取當(dāng)前時區(qū)。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前時間戳
        System.out.println(Clock.systemUTC().millis());
        // 獲取當(dāng)前時間戳
        System.out.println(System.currentTimeMillis());
        // 獲取當(dāng)前系統(tǒng)默認(rèn)時區(qū)
        System.out.println(Clock.systemDefaultZone().getZone());
    }
}

輸出:

1504478880531
1504478880531
Asia/Shanghai

檢查閏年

可以使用isLeapYear()方法直接判斷是否為閏年委刘,而不用我們再自己去計算丧没。

public class Test {
    public static void main(String[] args) {
        System.out.println(LocalDate.of(2020, 1, 1).isLeapYear());
    }
}

輸出:

true

帶時區(qū)計算

Java 8不僅將日期和時間進(jìn)行了分離,同時還有時區(qū)∥疲現(xiàn)在已經(jīng)有好幾組與時區(qū)相關(guān)的類了呕童,比如ZonId代表的是某個特定的時區(qū),而ZonedDateTime代表的是帶時區(qū)的時間淆珊。它等同于Java 8以前的GregorianCalendar類夺饲。使用這個類,你可以將本地時間轉(zhuǎn)換成另一個時區(qū)中的對應(yīng)時間。用ZoneOffset類來代表某個時區(qū)往声,比如印度是GMT或者UTC5:30茫蛹,你可以使用它的靜態(tài)方法ZoneOffset.of()方法來獲取對應(yīng)的時區(qū)。只要獲取到了這個偏移量烁挟,你就可以拿LocalDateTime和這個偏移量創(chuàng)建出一個OffsetDateTime婴洼。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前時間
        LocalDateTime now = LocalDateTime.now();
        // 設(shè)置時區(qū)
        ZonedDateTime zonedDateTime = ZonedDateTime.of(now, ZoneId.of("Australia/Darwin"));
        System.out.println("Current date and time in a particular timezone : " + zonedDateTime);

        // 構(gòu)建一個時間
        LocalDateTime datetime = LocalDateTime.of(2017, Month.SEPTEMBER, 5, 7, 50);
        // 設(shè)置偏移量
        ZoneOffset offset = ZoneOffset.of("+05:30");
        // 構(gòu)建帶偏移量的日期和時間
        OffsetDateTime date = OffsetDateTime.of(datetime, offset);
        System.out.println("Date and Time with timezone offset in Java : " + date);
    }
}

輸出:

Current date and time in a particular timezone : 2017-09-05T07:50:43.187+09:30[Australia/Darwin]
Date and Time with timezone offset in Java : 2017-09-05T07:50+05:30

OffSetDateTime主要是給機(jī)器來理解的,如果是給人看的撼嗓,可以使用ZoneDateTime類柬采。

固定日期

在前面我們用過一個MonthDay的類,用來構(gòu)建特定的幾月幾日且警。這里用到了另一個YearMonth粉捻,它表示某年某月,我們可以它來知道某年某月有多少天斑芜,使用YearMonthlengthOfMonth()方法肩刃。

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前年月
        YearMonth current = YearMonth.now();
        System.out.println(current);
        // 獲取這個月有多少天
        System.out.println(current.lengthOfMonth());
        // 構(gòu)建一個固定日期
        YearMonth expire = YearMonth.of(2017, Month.NOVEMBER);
        System.out.println(expire);
    }
}

輸出:

2017-09
30
2017-11

格式化日期

public class Test {
    public static void main(String[] args) {
        String dayAfterTomorrow = "20170905";
        LocalDate formatted = LocalDate.parse(dayAfterTomorrow,
                DateTimeFormatter.BASIC_ISO_DATE);
        System.out.printf("Date generated from String %s is %s %n", dayAfterTomorrow, formatted);

        String goodFriday = "Sep 05 2017";
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
            LocalDate holiday = LocalDate.parse(goodFriday, formatter);
            System.out.printf("Successfully parsed String %s, date is %s%n", goodFriday, holiday);
        } catch (DateTimeParseException ex) {
            System.out.printf("%s is not parsable!%n", goodFriday);
            ex.printStackTrace();
        }

        LocalDateTime arrivalDate = LocalDateTime.now();
        try {
            DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm a");
            String landing = arrivalDate.format(format);
            System.out.printf("Arriving at : %s %n", landing);
        } catch (DateTimeException ex) {
            System.out.printf("%s can't be formatted!%n", arrivalDate);
            ex.printStackTrace();
        }

    }
}

輸出:

Date generated from String 20170905 is 2017-09-05 
Successfully parsed String Sep 05 2018, date is 2017-09-05
Arriving at : Sep 06 2017 07:47 AM

計算時間間隔

Java8為我們提供了三個類來方便計算時間間隔,分別是

  • Duration:計算秒杏头、納秒盈包。
  • ChronoUnit:計算天、時醇王、分呢燥、秒。
  • Period:計算年寓娩、月叛氨、日。

秒棘伴、納秒

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前時間戳
        Instant i1 = Instant.now();
        // 當(dāng)前時間推后10s
        Instant i2 = i1.plusSeconds(10);
        // 獲取時間差
        Duration between = Duration.between(i1, i2);
        // 獲取時間差的毫秒值
        System.out.println(between.toMillis());
        // 獲取時間差的納秒值
        System.out.println(between.toNanos());
        // 獲取時間差的天數(shù)值
        System.out.println(between.toDays());
        // 獲取時間差的小時值
        System.out.println(between.toHours());
        // 獲取時間差的分鐘值
        System.out.println(between.toMinutes());
        // 獲取時間差的秒數(shù)值
        System.out.println(between.getSeconds());
    }
}

輸出:

10000
10000000000
0
0
0
10

天寞埠、時、分焊夸、秒

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前時間
        LocalDateTime d1 = LocalDateTime.now();
        // 當(dāng)前時間延后90000s
        LocalDateTime d2 = d1.plusSeconds(90000);
        // 獲取兩個時間之間隔了幾個半天
        long b1 = ChronoUnit.HALF_DAYS.between(d1, d2);
        System.out.println(b1);
        // 獲取兩個時間之間隔了幾個小時
        long b2 = ChronoUnit.HOURS.between(d1, d2);
        System.out.println(b2);
        // 獲取兩個時間之間隔了多少毫秒
        long b3 = ChronoUnit.MILLIS.between(d1, d2);
        System.out.println(b3);
    }
}

輸出:

2
25
90000000

年仁连、月、日

public class Test {
    public static void main(String[] args) {
        // 獲取當(dāng)前日期
        LocalDate d1 = LocalDate.now();
        // 構(gòu)建2018-10-01
        LocalDate d2 = LocalDate.of(2018, 10, 1);
        // 獲取兩個日期的差值
        Period between = Period.between(d1, d2);
        // 獲取兩個日期隔了多少年
        System.out.println(between.getYears());
        // 獲取兩個日期隔了多少月
        System.out.println(between.getMonths());
        // 獲取兩個日期隔了多少天
        System.out.println(between.getDays());
    }
}

輸出:

0
0
26

獲取某天的日期

比如有時候我們還會有這樣的需求淳地,獲取當(dāng)前日期所在的周一怖糊,那么這種又該怎么處理呢帅容;

public class Test {
  public static void main(String[] args) {
        LocalDate now = LocalDate.now();
        LocalDate date = now.with(DayOfWeek.MONDAY);
        System.out.println(date);
  }
}

輸出:

2017-09-04

結(jié)語

好了颇象,常用的用法就講到這里,time包下的類搭配起來可以有更多的用法并徘,需要同學(xué)們在使用過程中去摸索了遣钳,這里只是列舉了部分常見的用法,可能在日常開發(fā)中能夠用到麦乞,這也是我平時在開發(fā)中常用到的一些API蕴茴。這里再提供兩個工具類供參考一些格式化時間的方式以及一些常用轉(zhuǎn)換處理劝评,戳這里查看詳情

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倦淀,一起剝皮案震驚了整個濱河市蒋畜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌撞叽,老刑警劉巖姻成,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愿棋,居然都是意外死亡科展,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門糠雨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才睹,“玉大人,你說我怎么就攤上這事甘邀±湃粒” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵松邪,是天一觀的道長乎澄。 經(jīng)常有香客問我,道長测摔,這世上最難降的妖魔是什么置济? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮锋八,結(jié)果婚禮上浙于,老公的妹妹穿的比我還像新娘。我一直安慰自己挟纱,他們只是感情好羞酗,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著紊服,像睡著了一般檀轨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欺嗤,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天参萄,我揣著相機(jī)與錄音,去河邊找鬼煎饼。 笑死讹挎,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播筒溃,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼马篮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怜奖?” 一聲冷哼從身側(cè)響起浑测,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎歪玲,沒想到半個月后尽爆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡读慎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年漱贱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夭委。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡幅狮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出株灸,到底是詐尸還是另有隱情崇摄,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布慌烧,位于F島的核電站逐抑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏屹蚊。R本人自食惡果不足惜厕氨,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汹粤。 院中可真熱鬧命斧,春花似錦、人聲如沸嘱兼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芹壕。三九已至汇四,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踢涌,已是汗流浹背通孽。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留斯嚎,地道東北人利虫。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓挨厚,卻偏偏與公主長得像堡僻,于是被迫代替她去往敵國和親糠惫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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