Java跟蹤日期和時間JDateTime
譯者:阿邱 原文鏈接
JDateTime 是一個優雅的,開發者友好的類并且也一種非常精巧的跟蹤日期和時間的一種方式。它使用一種非常清晰并且被廣泛證明的算法去進行時間的操作。每個被JDK中Calendar深深虐過的人都將發現這是多麼好的一劑良藥。
Julian day
Julian day 或者 Julian day number(JDN)表示距離格林威治時間公元前 4713年 1月1日 星期一正午12點有多少個整數天。Julian Date(JD)則表示距離同樣的時間過了多少天(有小數位的天)。JDs 是被推薦的方式當在天文學上表示時間時。
Julian Day number 可以被認為是一種簡單的日歷:日期是他的整數位,時間是它的小數位。這樣它可以非常方便的被引用,計算或者轉換。實際上JD 的設計之美正是它可以非常容易的去計算時間的范圍進而去根據時間滾動日期,僅僅通過簡單的數學加減法。JD允許通過簡單的減法去計算兩個歷史日期之間的時間差。
Julian Day 系統被天文學家引進用來在兩個不同的日歷中去統一不同的歷史年代表時提供統一的的日期系統。
除了零點的選取和名字的與眾不同外,Julian Day 和Julian Date 不是直接的關聯到Julian Calendar,盡管它可以從將一個日歷的任何日期轉換到另一個日歷。
精度
JDateTime 內部使用JD去表示當前的日期和時間,它根據被證明并很好地測試過的天文學算法去做所有的計算。JDateTime 在所有的計算中提供精確到1毫秒的精度。
日期和時間設置
JDateTime 可以通過多種方式創建:通過制定想要的日期和時間,或者通過傳入一個JDK中日期時間相關類的引用,或者通過指定系統的毫秒數等等。
JDateTime 能夠通過指定日期和時間數據來創建,一旦被創建,日期和時間可以通過不同的方式來改變,可以通過完整的日期/時間信息來改變(等同于創建新的JDateInstance)或者僅僅改變一部分(僅僅 天或者分鐘…)
使用構造函數:
JDateTime jdt = new JDateTime(); // current date and time jdt = new JDateTime(2012, 12, 21): // 21st December 2012, midnight jdt = new JDateTime(System.currentTimeMillis()); // current date and time jdt = new JDateTime(2012, 12, 21, 11, 54, 22, 124); // 21.Dec.2012,11:54:22.124 jdt = new JDateTime("2012-12-21 11:54:22.124"); // -//- jdt = new JDateTime("12/21/2012", "MM/DD/YYYY"); // 21st Dec. 2012, midnight
使用方法:
JDateTime jdt = new JDateTime(); // current date and time jdt.set(2012, 12, 21, 11, 54, 22, 124); // 21st December 2012, 11:54:22.124 jdt.set(2012, 12, 21); // 21st December 2012, midnight jdt.setDate(2012, 12, 21); // change just date to 21st Dec. 2012 jdt.setCurrentTime(); // set current date and time jdt.setYear(1973); // change the year jdt.setHour(22); // change the hour jdt.setTime(18, 00 12, 853); // change just time
讀取時間和日期
當然,它可以通過JDateTime讀取時間和日期信息,每個部分:年,月,時等等都有對應的getter方法,天和月是從1開始計數的,所以,JDateTime.JNUARY 是1.
除了讀取單個日期時間信息單個部分的方法,這里還有須有方便的方法去返回日期和時間信息。
getDateTimeStamp()內部使用JDateTIme返回DateTimeStamp 實例,這個類一次性返回了所有的日期/時間信息。
getJulianDate()內部使用JDateTIme返回JulianDateStamp實例。JulianDateStamp持有當前JD的信息。由于小數位的精度問題,JD 信息通過兩個單獨的字段進行存儲:integer 和 fraction(JD=integer+fraction). 你也就可以得到一個Double類型值得JD,但是它不精確(忽略掉時間),由于當integer部分非常大的時候會導致fraction部分精度丟失。
時間計算
JDateTime 提供了多個方法在當前的日期/時間上加減指定的時間。它可以僅僅改變單個部分的日期/時間信息或者一次改變多個部分。
jdt.add(1, 2, 3, 4, 5, 6, 7); // add 1 year, 2 months, 3 days, 4 hours... jdt.add(4, 2, 0); // add 4 years and 2 months jdt.addMonth(-120); // go back 120 months jdt.subYear(1); // go back one year jdt.addHour(1234); // add 1234 hours
由于性能的原因,最好是通過一個方法調用按照順序一次性改變多個時間部分,比如,如果同時要在當前時間上加一定數量的months,minutes和秒,通過add(0, months, 0, 0, minutes, seconds, 0); 一次性改變而不是調用三個單獨的方法去改變將使速度更快。
由于每個月的長度是變化的月份的增加是不可靠的,這里有兩種方式可以被考慮當進行月份增加的時候,下面的例子將顯示什么:從2003-01-31加一個月后的時間是什么?
JDateTime 有一個monthFix的標志去表示加法后的月份,當這個標志關閉時,一個月的天數被近似的認為是31天,所以結果是:2003-01-31 + 0-1-0 = 2003-03-03.
當monthFix的標志是關閉的時候(默認也是這樣),月份的長度會被忽略,在這種情況下,添加一個月總是得到的是下一個月:2003-01-31 + 0-1-0 = 2003-02-28.
因為月份天數的補丁導致添加月份是不可靠的,所以最佳實踐是用添加天數來代替。
周期
通過JDateTime 可以非常容易的去計算周期時間,僅僅通過兩個時間相減接口得到去計算周期時間。但是如果要包括小時,分鐘,秒和毫秒,更簡單并且快速的方式是使用Period類。
轉換
JDateTime 可以 非常容易的在其他時間相關的類之間進行轉換:GregorianCalendar, java.util.Date, java.sql.Date, Timestamp,DateTimeStamp
不僅如此,他可以從存在的實例設置日期和時間,而不是創建一個新的。
Calendar c = jdt.convertToCalendar(); jdt.convertToGregorianCalendar(); jdt.convertTo(GregorianCalendar.class); // generic way of conversion jdt = new JDateTime(gregCalInstance); // create from GregorianCalendar jdt.loadFrom(gregCalInstance); // load time data from GregorianCalendar jdt.storeTo(gregCalInstance); // store time data to GregorianCalendar
不僅如此,根據自己需要定義自定義的轉換也是非常容易的。
字符串轉換
特別注意的是日期/時間與字符串之間的轉換。這里有兩種通用的方式去轉換:
通過JDateTime實例進行轉換或者通過傳遞一個JDateTime實例給一些格式化的類。
對所有內部的轉換和解析,JDateTime使用所謂的formatters,比如 JdtFormatter的實現。Formatters 遵循簡單的協議(接口)僅僅兩個方法:定義如何轉換為字符串和如何解析字符串為指定的格式。格式通常是一個包含一些模式的字符串模板。因此一個formatter的實例可以用在整個應用中。JDateTime持有formatter和默認的格式用來進行轉換和解析。當在轉換和解析時沒有指定格式則使用默認格式。
假如一個應用程序不得不在多個formatter之間頻繁切換,那么你使用JdtFormat來進行轉換和解析將更方便-這是一個不可變的類持有formatter-format對。
最后,由于JDateTime可以非常方便的轉換為Date,所以你也可以使用JDK的DateFormatter來進行日期時間和字符串的轉換。
DefaultFormatter是JDateTime默認使用的格式化類。它在ISO 8601規范的基礎上增強了模式,同時對轉換和解析-解析支持的模式少一些。
轉換的模板字符串除了上訴的文本外還可以包含其他的文本,甚至完整的句子。它可以轉義某些模板部分來防止被轉換。轉義文本通過單引號。任何在引號區域內的兩個單引號會北替換為一個單引號,此外,如果一些模式無法被識別它將忽略。
使用例子:
JDateTime jdt = new JDateTime(1975, 1, 1); jdt.toString(); // "1975-01-01 00:00:00.000" jdt.toString("YYYY.MM.DD"); // "1975.01.01" jdt.toString("MM: MML (MMS)"); // "01: January (Jan)" jdt.toString("DD is D: DL (DS)"); // "01 is 3: Wednesday (Wed)" JDateTime jdt = new JDateTime(1968, 9, 30); jdt.toString("'''' is a sign, W is a week number and 'W' is a letter"); // "' is a sign, 5 is a week number and W is a letter"jdt.parse("2003-11-24 23:18:38.173"); jdt.parse("2003-11-23"); // 2003-11-23 00:00:00.000 jdt.parse("01.01.1975", "DD.MM.YYYY"); // 1975-01-01 jdt.parse("2001-01-31", "YYYY-MM-***"); // 2001-01-01, since day is not parsed JDateTime jdt = new JDateTime(); JdtFormatter fmt = new DefaultFormatter(); fmt.convert(jdt, "YYYY-MM.DD"); // external conversion JdtFormat format = new JdtFormat(new DefaultFormatter(), "YYYY+DD+MM"); jdt.toString(format); format.convert(jdt); DateFormat df = new SimpleDateFormat(); df.format(jdt.convertToDate()); // date formatter</pre> <h2>本地化 </h2>
通過在JDateTime中設置locale,可以在結果字符串中返回本地化的名稱,比如月份和長短日期的名稱,當沒有指定locale時,JDateTime使用系統默認的locale。
星期定義
JdateTime提供了兩種方式去定義星期,即定義星期的第一天和定義一年的第一個星期(用來周的計數)。
setWeekDefinition(start,must)定義一個星期的起始天和一周的那一天必須在一年中來計算該周屬于那一年。
setWeekDefinitionAlt(start, min) 是另一個定義方式來定義一周的起始天和該周屬于該年時必須有的最小的天數。JD供選方案
由于JD的起始時間是如此的久遠,JD的數值非常的大和笨重,一個距離現在更近的起始點通常會被用到,比如丟棄掉一些數字位來在保證足夠的精度的同時適應有限的計算機內存。
JDateTime 可以將JD在下面的類之間進行轉換:
- 簡化的 Julian Day (RJD),
- 改良的 Julian Day (MJD), and
- 截短的 Julian Day (TJD), NASA提出的定義 </ul>
時區和DST(夏時制)
Julian Date,根據定義,是與時區和夏時制無關的。但是,JDateTime支持時區,當時區改變時(并且改變到不同的時區)時間將進行一定的偏移。當JDateTime創建時,系統默認的時區就被使用,當設置新的時區是,當前時間將根據時區的不同而改變,下面的例子表示當前的日本時間:
JDateTime jdt = new JDateTime(); jdt.setTimeZone(TimeZone.getTimeZone("Japan";)); System.out.println(jdt);
此外,可以僅僅去設置時區,而不改變當前的時間。有時在改變時區時會很用,通過changeTimeZone()方法即可。
DST僅僅被部分支持,現在默認情況下DST跟蹤是關閉的(標志:trackDST)。當DST跟蹤打開時,JDateTime將跟蹤DST僅僅當加減時間時,最后一點,它可以設置一個無效的時間(比如說不存在的時間)。
原創文章,轉載請注明: 轉載自并發編程網 – ifeve.com