yyyy-MM-dd'T'HH:mm:ss.SSSXXX
。格林尼治時間已經再也不被做爲標準時間使用,UTC 是最主要的世界時間標準。html
Java提供了獲取當前時間的方法java
1970-01-01 00:00:00.000
的毫秒差值。返回的long值能夠用來初始化java.util.Date, java.sql.Date, java.sql.Timestamp和java.util.GregorianCalendar對象。例如,要測量一些代碼須要執行多長時間,實現以下,sql
long startTime = System.nanoTime(); //...the code being measured long estimatedTime = System.nanoTime() - startTime;
時間粒度
事實上System.currentTimeMillis()方法的時間粒度是大於1毫秒的。若是你反覆執行這個方法,你會發現短期內獲得的結果是相同的,隨後又忽然在某一次結果增長了幾十毫秒(也可能更多)。這是很正常的,畢竟這個方法確定不是世界上最精密的計時器。api
舊的時間API存在諸多問題,例如安全
java.util.Date類用於封裝日期及時間信息,通常僅用它顯示某個日期,不對他做任何操做處理,做處理推薦用Calendar類,計算方便。如下已過期的方法沒有列出,可自行查看jdk文檔多線程
構造方法oracle
Date() :分配 Date對象並初始化此對象,以表示分配它的時間(精確到毫秒)。app
Date(long date):分配 Date對象並初始化此對象,以表示自從標準基準時間(稱爲「曆元(epoch)」,即 1970 年 1 月 1 日 00:00:00 GMT)以來的指定毫秒數。學習
//一、使用Date類獲取當前系統時間 Date date = new Date(); System.out.println(date); //因爲Date類覆蓋了toString()方法,因此能夠直接輸出Date類型的對象 //輸出結果爲Fri May 31 10:51:18 GMT+08:00 2019 /*給Date設置年份須要減去 1900 *輸出結果Tue Jul 01 00:00:00 GMT+08:00 3919 *原來這裏存在一個起始年份 1900,實際年份是要在你的年份參數上加上個起始年份。 */ Date date1 = new Date(2019,5,31); System.out.println(date1); //2.分配 Date 對象並初始化此對象,以表示自從標準基準時間(稱爲「曆元(epoch)」,即 1970 年 1 月 1 日 00:00:00 GMT)以來的指定毫秒數。 Date date2 = new Date(System.currentTimeMillis());//參數爲19701月1日以來的毫秒數 Date date3 = new Date(1559284293556l); //long類型要加l System.out.println(date2); System.out.println(date3); //其餘Date方法摘要可查看api
java.util.Calendar類用於封裝日曆信息,其主做用在於其方法能夠對時間份量進行運算。Calendar類是一個抽象類,它爲特定瞬間與一組諸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日曆字段之間的轉換提供了一些方法,併爲操做日曆字段(例如得到下星期的日期)提供了一些方法。線程
因爲Calendar類是抽象類,且Calendar類的構造方法是protected的,因此沒法使用Calendar類的構造方法來建立對象,API中提供了getInstance方法用來建立對象。
Java只提供java.util.GregorianCalendar這一種java.util.Calendar的實現類,能夠直接新建出來使用:
Calendar calendar = new GregorianCalendar();//新建出來的calendar默認時間爲當前時間,或者說建立出這個對象的時間。
經過Calendar的靜態方法獲取一個實例該方法會根據當前系統所在地區來自行決定時區,幫咱們建立Calendar實例,這裏要注意,實際上根據不一樣的地區,Calendar有若干個子類實現。而Calendar自己是抽象類,不能被實例化!咱們不須要關心建立的具體實例爲哪一個子類,咱們只須要根據Calendar規定的方法來使用就能夠了。
日曆類所解決的根本問題是簡化日期的計算,要想表示某個日期還應該使用Date類描述。Calendar是能夠將其描述的時間轉化爲Date的,咱們只須要調用其getTime()方法就能夠獲取描述的日期的Date對象了。
經過日曆類計算時間:爲日曆類設置時間,日曆類設置時間使用通用方法set。set(int field,int value),field爲時間份量,Calendar提供了相應的常量值,value爲對應的值。
只有月份從0開始:0爲1月,以此類推,11爲12月,其餘時間是正常的從1開始。也可使用Calendar的常量 calendar.NOVEMBER……等。
Calendar.DAY_OF_MONTH 月裏邊的天---號; Calendar.DAY_OF_WEEK 星期裏的天---星期幾 Calendar.DAY_OF_YEAR 年裏的天 Calendar calendar=Calendar.getInstance();//構造出來表示當前時間的日曆類 Date now=calendar.getTime();//獲取日曆所描述的日期 calendar.set(Calendar.YEAR, 2019);//設置日曆表示2019年 calendar.set(Calendar.DAY_OF_MONTH,15);//設置日曆表示15號 calendar.add(Calendar.DAY_OF_YEAR, 22);//想獲得22天之後是哪天 calendar.add(Calendar.DAY_OF_YEAR, -5);//5天之前是哪天 calendar.add(Calendar.MONTH, 1);獲得1個月後是哪天 System.out.println(calendar.getTime());
獲取當前日曆表示的日期中的某個時間單位可使用get方法。
int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) int day = calendar.get(Calendar.DAY_OF_MONTH); System.out.println(year+"年"+(month+1)+"月"+day+"日");//month要處理
經常使用構造方法
SimpleDateFormat(String pattern),pattern -爲描述日期和時間格式的模式
用給定的模式和默認語言環境的日期格式符號構造 SimpleDateFormat。 注:此構造方法可能不支持全部語言環境。要覆蓋全部語言環境,請使用 DateFormat 類中的工廠方法。
經常使用方法
public final String format(Date date)將一個 Date 格式化爲日期/時間字符串 public Date parse(String source)throws ParseException從給定字符串的開始解析文本,以生成一個日期。
字符串轉成Date對象
//建立一個SimpleDateFormat而且告知它要讀取的字符串格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String dateFormat = "2019-05-31";//建立一個日期格式字符串 //將一個字符串轉換爲相應的Date對象 Date date = sdf.parse(dateFormat);//要先捕獲異常 System.out.println(date);//輸出這個Date對象
Date對象轉成字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date = new Date(); String dateStr = sdf.format(date);//把日期對象傳進去,繼承自DateFormat類的方法。將一個Date格式化爲日期/時間字符串
在日期格式中,-和空格無特殊意義。無特殊含義的都原樣輸出
//將當前系統時間轉換爲2012/05/14 17:05:22的效果 SimpleDateFormat format1 = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); dateStr=format1.format(date); System.out.println(dateStr);
java.text.DateFormat類(抽象類)是SimpleDateFormat類的父類,用的少,沒SimpleDateFormat靈活。
java.sql.Date繼承java.util.Date,爲了把前者轉爲後者,須要如下代碼
Date date = new Date(); //java.sql.Date 不支持Date參數的構造器,傳入long類型的時間 java.sql.Date d = new java.sql.Date(date.getTime()); System.out.println(d); System.out.println(d.getHours());
輸出結果
2019-05-31 Exception in thread "main" java.lang.IllegalArgumentException at java.sql.Date.getHours(Unknown Source) at DateTest.DateTest1.main(DateTest1.java:40)
這是因爲java.sql.Date是SQL中的單純的日期類型,沒有時分秒。故通常經過JDBC插入java.sql.Date數據時,會發現時分秒都沒有。所以,若是同時須要日期和時間,應該使用Timestamp。它也是 java.util.Date 的子類,Timestamp 則包含時間戳的完整信息。
java.sql.Timestamp是java.util.Date的派生類(繼承),因此在java.util.Date上能作的事,也能夠在java.sql.Timestamp上作。
若是當前是2019-06-01 14:35,你建立一個java.sql.Date 將只記下2019-06-01這個信息。若你須要保留時間進行JDBC操做,請使用java.sql.Timestamp代替。
long time = System.currentTimeMillis(); java.sql.Timestamp timestamp = new java.sql.Timestamp(time); timestamp.setNanos(123456); int nanos = timestamp.getNanos(); // nanos = 123456
如今的Date類中大部分方法已經棄用,如今通常使用舊的API,Date只負責存儲一個時間,並對Calendar和DateFormat提供操做接口。Calendar獲取Date中特定的信息,對日期時間進行操做,SimpleDateFormat對日期時間進行格式化輸入輸出。
總的來講,Date、Calendar 和 DateFormat 已經可以處理通常的時間日期問題了。可是不可避免的是,它們依然很繁瑣,很差用而且這些日期類都是可變且線程不安全的
詳情請查看https://www.ibm.com/developerworks/cn/java/j-jodatime.html
Java8日期時間的默認格式以下:yyyy-MM-dd-HH-mm-ss.zzz
幾個主要的核心類:
2018-01-14T02:20:13.592Z
下面看看這些類具體如何使用
LocalDate是不變的日期時間對象表明一個日期,每每被視爲年月日。其餘日期字段,如一年中的一天,一週和一週的一天,也能夠訪問。例如,「2007年10月2日」的值能夠被存儲在一個LocalDate。
LocalTime是不變的日期時間對象表明一個時間,每每被視爲小時分鐘秒。時間爲表明的納秒級精度。例如,值「13:45.30.123456789」能夠存儲在一個LocalTime。
LocalDateTime是不變的日期時間對象表明一個日期時間,每每被視爲年、月、日、時、分、秒。其餘日期和時間字段,如一年中的一天,一週和一週的一天,也能夠訪問。時間爲表明的納秒級精度。例如,值「2007年10月2日在13:45.30.123456789」能夠存儲在一個LocalDateTime。
//now()在默認時區中從系統時鐘獲取當前日期。 LocalDate today = LocalDate.now(); LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); //等價於 today.plusWeeks(1) //of(int year, int month, int dayOfMonth) 得到 LocalDate實例從一年、月、日。 LocalDate date = LocalDate.of(2019,5,31); LocalTime time = LocalTime.of(20,31,20); //of(LocalDate date, LocalTime time) 得到 LocalDateTime實例的日期和時間。 LocalDateTime dateTime = LocalDateTime.of(date,time); System.out.println(dateTime); //LocalDate結合LocalTime成一個LocalDateTime LocalDateTime dateTime2 = date.atTime(time); System.out.println(dateTime2); //2019-05-31T20:31:20
格式器用於解析日期字符串和格式化日期輸出,建立格式器最簡單的方法是經過 DateTimeFormatter 的靜態工廠方法以及常量。建立格式器通常有以下三種方式:
和舊的 java.util.DateFormat 相比較,全部的 DateTimeFormatter 實例都是線程安全的。
使用DateTimeFormatter完成格式化
//獲取默認時區中從系統時鐘獲取當前日期時間。 LocalDateTime localDateTime = LocalDateTime.now(); //建立一個格式化程序使用指定的模式。 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String formatDateTime = localDateTime.format(formatter); System.out.println(formatDateTime); //DateTimeFormatter提供了一些默認的格式化器,DateTimeFormatter.ISO_LOCAL_DATE_TIME 格式 yyyy-MM-ddTHH:mm:ss.SSS String dateTime2 = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); System.out.println(dateTime2);
使用DateTimeFormatter完成解析字符串
//得到 LocalDate實例,從使用特定格式的文本字符串解析,文字使用格式化程序解析,返回一個日期。 LocalDate localDate = LocalDate.parse("2018/11/11",DateTimeFormatter.ofPattern("yyyy/MM/dd")); System.out.println(localDate); //2018-11-11
Instant 表示時間線上的一點(與 Date 相似),它只是簡單地表示自 1970 年 1 月 1 日 0 時 0 分 0 秒(UTC)開始的秒數。
Instant 由兩部分組成,一是從原點開始到指定時間點的秒數 s, 二是距離該秒數 s 的納秒數。它以 Unix 時間戳的形式存儲日期時間,不提供處理人類意義上的時間單位(年月日等)。
你能夠經過Instant類的工廠方法建立一個Instant實例
//調用instant.now()來建立一個確切的表達當前時間的Instant對象.另外也有一些其它方法能建立Instant,具體請查閱Java官方文檔。 Instant now = Instant.now(); Instant later = now.plusSeconds(3); Instant earlier = now.minusSeconds(3); //第一個參數是秒,第二個是納秒參數,納秒的存儲範圍是0至999,999,999 //2s以後的在加上100萬納秒(1s) Instant instant = Instant.ofEpochSecond(2,1000000000); System.out.println(instant); //1970-01-01T00:00:03Z Instant instant1 = Instant.now(); System.out.println(instant1); //2019-05-31T16:19:28.719Z Instant instant2 = Instant.parse("2018-11-11T10:12:35.342Z"); System.out.println(instant2); //2018-11-11T10:12:35.342Z //java.util.Date與Instant可相互轉換 Instant timestamp = new Date().toInstant(); Date.from(Instant.now()); //爲了更好的顯示,代碼改寫爲 Date date = new Date(); Instant timestamp = date.toInstant(); System.out.println(date); System.out.println(timestamp); Instant now1 = Instant.now(); Date date1 = Date.from(now1); System.out.println(now1); System.out.println(date1); //輸出結果 Sat Jun 01 00:29:42 GMT+08:00 2019 2019-05-31T16:29:42.566Z 2019-05-31T16:29:42.588Z Sat Jun 01 00:29:42 GMT+08:00 2019
Clock用於查找當前時刻,能夠用來獲取某個時區下當前的日期和時間,也能夠用來代替舊的System.currentTimeMillis()方法和TimeZone.getDefault()方法。
//返回系統默認時間 Clock clock = Clock.systemDefaultZone(); System.out.println(clock.instant().toString()); //世界協調時UTC Clock clock = Clock.systemUTC(); //經過Clock獲取當前時刻 System.out.println("當前時刻爲:" + clock.instant()); //獲取clock對應的毫秒數,與System.currentTimeMillis()輸出相同 System.out.println(clock.millis()); System.out.println(System.currentTimeMillis());
一個Duration實例是不可變的,當建立出對象後就不能改變它的值了。你只能經過Duration的計算方法,來建立出一個新的Durtaion對象。你會在以後的教程中見到的。一個Duration對象表示兩個Instant間的一段時間。
建立Duration實例,使用Duration類的工廠方法來建立一個Duration對象
Instant first = Instant.now(); // wait some time while something happens Instant second = Instant.now(); Duration duration = Duration.between(first, second); //得到Duration表示秒數,而後得到在此期間的分鐘數、小時數、天數 Duration d = Duration.ofSeconds(6000); System.out.println("6000秒至關於" + d.toMinutes() + "分"); System.out.println("6000秒至關於" + d.toHours() + "小時"); System.out.println("6000秒至關於" + d.toDays() + "天");
訪問Duration的時間
一個Duration對象裏有兩個域:納秒值(小於一秒的部分),秒鐘值(一共有幾秒),他們的組合表達了時間長度。注意與使用System.getCurrentTimeMillis()時不一樣,Duration不包含毫秒這個屬性。
你能夠經過如下兩個方法獲得它們的值:getSeconds()和getNano()
Period 是以年月日來衡量一個時間段,用於計算兩個日期間隔,因此 between() 方法只能接收 LocalDate 類型的參數。
LocalDate start = LocalDate.of(2018, Month.JANUARY, 1); LocalDate end = LocalDate.of(2020, Month.NOVEMBER, 11); System.out.println("相隔月數:"+Period.between(start, end).getMonths()); System.out.println("相隔天數:"+Period.between(start, end).getDays()); //輸出結果 相隔月數:10 相隔天數:10
值得注意的是,Period 獲得的是差值的絕對值(對應年月日直接計算數學上的差值),而並不表示真正的區間距離。
long distanceMonth = start.until(end, ChronoUnit.MONTHS); long distanceDay= start.until(end, ChronoUnit.DAYS); System.out.println("相隔月數"+distanceMonth); System.out.println("相隔天數"+distanceDay); //輸出結果 相隔月數:34 相隔天數:1045
ZonedDateTime類是Java 8中日期時間功能裏,用於表示帶時區的日期與時間信息的類。ZonedDateTime 類的值是不可變的,因此其計算方法會返回一個新的ZonedDateTime 實例。
Java 使用 ZoneId 來標識不一樣的時區,從基準 UTC 開始的一個固定偏移。
建立一個ZonedDateTime實例
//使用當前時間做爲值新建對象 ZonedDateTime dateTime = ZonedDateTime.now(); //使用指定的年月日、時分、納秒以及時區ID來新建對象 //時區是用ZoneId類表示的,可使用ZoneId.now()或ZoneId.of(「xxx」)來實例化: //傳給of()方法的參數是時區的ID,如「UTC+1」指距離UTC(格林威治時間)有一小時的時差 ZoneId zoneId = ZoneId.of("UTC+1"); ZonedDateTime dateTime2 = ZonedDateTime.of(2019, 6, 1, 14, 40, 48, 1234, zoneId); //也可使用另外一種方式表示zone id,即便用地區名字 ZoneId zoneId2 = ZoneId.of("Europe/Copenhagen"); //GregorianCalendar與ZonedDateTime相互轉換 ZonedDateTime zonedDateTime = new GregorianCalendar().toZonedDateTime(); GregorianCalendar.from(zonedDateTime);
有的時候,你須要進行一些更加複雜的操做,好比,將日期調整到下個週日、下個工做日,或者是本月的最後一天。
簡單應用例子
LocalDate localDate = LocalDate.now(); // 1. 本月第一天 LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth()); // 2. 本月最後一天 LocalDate lastDayOfMonth = localDate.with(TemporalAdjusters.lastDayOfMonth()); // 3. 本年第一天 LocalDate firstDayOfYear = localDate.with(TemporalAdjusters.firstDayOfYear()); // 4. 下個月第一天 LocalDate firstDayOfNextMonth = localDate.with(TemporalAdjusters.firstDayOfNextMonth()); // 5. 本年度最後一天 LocalDate lastDayOfYear = localDate.with(TemporalAdjusters.lastDayOfYear()); System.out.println(firstDayOfMonth); System.out.println(lastDayOfMonth); System.out.println(firstDayOfYear); System.out.println(firstDayOfNextMonth); System.out.println(lastDayOfYear);
這時,你可使用重載版本的with方法,向其傳遞一個提供了更多定製化選擇的TemporalAdjuster對象,更加靈活地處理日期。TemporalAdjusters類經過靜態方法提供了大量的經常使用的TemporalAdjuster的實現供咱們使用。
/** * 時間校訂器TemporalAdjuster */ @Test public void Test() { LocalDateTime now1 = LocalDateTime.now(); //獲取月中的第一天 now1.with(TemporalAdjusters.firstDayOfMonth()); //獲取下一年的第一天 now1.with(TemporalAdjusters.firstDayOfNextYear()); //獲取年中第一天 now1.with(TemporalAdjusters.lastDayOfYear()); //獲取月中最後一天 now1.with(TemporalAdjusters.lastDayOfMonth()); //獲取下個星期一 now1.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); //自定時時間:下一個工做日,由於這裏須要一個接口,因此徹底能夠自定義方法 now1.with((e) -> { LocalDateTime now = (LocalDateTime)e; DayOfWeek dow = now.getDayOfWeek(); if (dow.equals(DayOfWeek.FRIDAY)) return now.plusDays(3); else if (dow.equals(DayOfWeek.SATURDAY)) return now.plusDays(2); return now.plusDays(1); }); }
將Date轉換爲LocalDate,LocalTime,LocalDateTime能夠藉助於ZonedDateTime和Instant,實現以下:
Date date = new Date(); System.out.println("current date: " + date); // Date -> LocalDateTime LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); System.out.println("localDateTime by Instant: " + localDateTime); // Date -> LocalDate LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); System.out.println("localDate by Instant: " + localDate); // Date -> LocalTime LocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime(); System.out.println("localTime by Instant: " + localTime); //2. Date -> LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); System.out.println("localDateTime by ofInstant: " + localDateTime);
因爲JDK8實現了向下兼容,因此Date裏在JDK8版本引入了2個方法,from和
toInstant,因此咱們能夠藉助這兩個方法來實現LocalDateTime到Date的轉換。將LocalDateTime轉爲Date以下:
LocalDateTime localDateTime = LocalDateTime.now(); System.out.println("localDateTime: " + localDateTime); // LocalDateTime -> Date Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); System.out.println("LocalDateTime -> current date: " + date); // LocalDate -> Date,時間默認都是00 LocalDate localDate = LocalDate.now(); date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); System.out.println("LocalDate -> current date: " + date);
經過LocalDate,LocalTime,LocalDateTime的parse方法和DateTimeFormatter來實現:
//字符串->日期 LocalDate localDate = LocalDate.parse("2018-09-09", DateTimeFormatter.ofPattern("yyyy-MM-dd")); LocalDateTime localDateTime = LocalDateTime.parse("2018-09-10 12:12:12", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); //日期->字符串 String localDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); String localDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // 也能夠經過DateTimeFormatter的format方法 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); localDateTime = dateTimeFormatter.format(LocalDateTime.now());
具體實現以下:
//時間戳->LocalDateTime public static LocalDateTime convertToDate(long timestamp) { // ofEpochSecond 以秒爲單位, ofEpochMilli 以毫秒爲單位 // Instant.ofEpochSecond(timestamp); Instant instant = Instant.ofEpochMilli(timestamp); return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); } //LocalDateTime->時間戳 public static long convertToTimestamp() { LocalDateTime localDateTime = LocalDateTime.now(); return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); }
更多方法使用請參考Java api文檔
參考文章:
http://www.importnew.com/14140.html
https://docs.oracle.com/javase/8/docs/api/
https://www.jianshu.com/p/f4abe1e38e09