<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    seaairland

     

    JavaAPI的Date,Calendar日期處理相關類分析

    ?

    在計算機程序中精確的處理日期是困難的。不僅有顯而易見的(英語:?January,?法語:?Janvier,?德語:?Januar,?等)國際化需求,?而且得考慮不同的日期系統(并非所有的文化都用基督耶穌的生日作為紀年的開始)。如有高精度或非常大規模的時間需要被處理,?就有額外的方面需要被注意,比如閏秒或時間系統的變化。(公歷(陽歷,?格里高利歷法)在西方被普遍接受是在1582年,但并非所有的國家在同一天接受!)

    盡管有關于閏秒,?時區,?夏令時,?陰歷的問題,?度量時間卻是一個非常簡單的概念:?時間的進行是線性的很容易被忽略。一旦時間軸的區域被定義,?任何時間點被從起點時間的流逝就可以確定。這和地理位置或當地時區是獨立的?–?對任意指定的時間點,?對任意地區,?從起點的過程是相同的(忽略相對論的矯正)。


    --------------------------------------------------------------------------------

    可當我們試圖根據某些日歷解釋這一時間點的時候困難來了,?比如,?根據月,?日,?或者年來表示它。在這一步上地理信息變得相關:?在時間上的同一個點對應不同的天的某一時間,?依賴于區域?(比如:?時區)。基于解釋日期的修正經常是必要的(今天一個月以后是哪一天?)?并且增加了額外的困難:?上溢和下溢(12月15號的后一個月是下一年),?且不明確(1月30號后的一個月是哪一天?).

    在最初的JDK?1.0,?一個時間點,?通過把它解釋為java.util.Date類,?它被計算在一起來表示.?雖然相對容易處理,?但它并不支持國際化;?從JDK?1.1.4?或JDK?1.1.5,?多樣的負責處理日期的職責被分配到以下類中:

    java.util.Date
    代表一個時間點.

    abstract?java.util.Calendar
    java.util.GregorianCalendar?extends?java.util.Calendar
    解釋和處理Date.

    abstract?java.util.TimeZone
    java.util.SimpleTimeZone?extends?java.util.TimeZone
    代表一個任意的從格林威治的偏移量,?也包含了適用于夏令時(daylight?savings?rules)的信息.

    abstract?java.text.DateFormat?extends?java.text.Format
    java.text.SimpleDateFormat?extends?java.text.DateFormat
    變形到格式良好的,?可打印的String,?反之亦然.

    java.text.DateFormatSymbols
    月份,?星期等的翻譯,?作為從Locale取得信息的一種替代選擇.

    java.sql.Date?extends?java.util.Date
    java.sql.Time?extends?java.util.Date
    java.sql.Timestamp?extends?java.util.Date
    代表時間點,?同時為了在sql語句中使用也包含適當的格式.


    注意:?DateFormat?和相關的類在java.text.*包.?所有的java.sql.*包中日期處理相關類繼承了java.util.Date類.?所有的其它類在java.util.*包中.

    這些"新"類來自三個分離的繼承層次,?其頂層類(Calendar,?TimeZone,?and?DateFormat)是抽象的.?針對每一個抽象類,?Java標準類庫提供了一個具體的實現.

    java.util.Date

    類java.util.Date?代表一個時間點.?在許多應用中,?此種抽象被稱為"TimeStamp."?在標準的Java類庫實現中,?這個時間點代表Unix紀元January?1,?1970,?00:00:00?GMT開始的毫秒數.?因而概念上來說,?這個類是long的簡單封裝.

    根據此種解釋,?類中僅有的沒有過期的(除了那些毫秒數的get和set方法)是那些排序方法.

    這個類依靠System.currentTimeMillis()?來取得當前的時間點.?因此它的準確度和精度由System的實現和它所調用底層(本質是操作系統)決定.

    The?java.util.Date?API

    在最初的?Date類使用中名字和約定引起了無盡的混淆.?然而用0-11計算月,?從1900計算年的決定模仿了C標準類庫的習慣,?調用函數?getTime()返回起始于Unix紀元的毫秒數和?getDate()返回星期的決定顯然是Java類設計者自己的.


    java.util.Calendar

    語義

    Calendar代表一個時間點(一個"Date"),?用以在特定的區域和時區適當的解釋器.?每一個Calendar?實例有一個包含了自紀元開始的代表時間點的long變量.

    這意味著Calendar?不是一個(無狀態)?變換者或解釋器,?也不是一個修改dates的工廠.?它不支持如下方式:

    Month?Interpreter.getMonth(inputDate)?or

    Date?Factory.addMonth(inputDate)

    Instead,?Calendar實例必須被初始化到特定的Date.?此Calendar實例可以被修改或查詢interpreted屬性.

    奇怪的是,?此類的instances?總是被初始化為當前時間.?獲得一個初始化為任意Date的Calendar?實例是不可能的—API強制程序員通過一系列的在實例上的方法調用,?比如setTime(date)來顯式的設置日期.

    訪問Interpreted?字段和類常量

    Calendar?類遵從一不常用的方式來訪問interpreted?date實例的單個字段.?而不是提供一些dedicated屬性?getters和setters方法(比如getMonth()),?它僅提供了一個,?使用一個標示作為參數來獲取請求的屬性的方法:

    int?get(Calendar.MONTH)?等等.

    注意這個函數總是返回一個int!

    這些字段的標示符被定義為Calendar類的public?static?final變量.?(這些identifiers是raw的整數,?沒有被封裝為一個枚舉抽象.)

    除了對應這些字段標示(鍵值),?Calendar?類定義了許多附加的public?static?final?變量來保存這些字段的值.?因此,?為測試某一特定date?(由Calendar?的實例calendar表示)?是否在一年的第一個月,?會有像如下的代碼:

    if?(calendar.get(Calendar.MONTH)?==?Calendar.JANUARY)?{...}

    注意月份被叫做?JANUARY,?FEBRUARY,?等等,?不管location(相對更中性的名字比如:?MONTH_1,?MONTH_2,?等等).?也有一個字段UNDECIMBER,?被一些(非公歷(陽歷,?格里高利歷法))日歷使用,?代表一年的第十三個月.

    不幸的是,?鍵值和值既沒有通過名字也沒分組成嵌套的inerface來區分.

    處理

    Calendar?提供了三種辦法來修改當前實例代表的日期:?set(),?add(),?和roll().?set()方法簡單的設置特定的字段為期望的值.?add()?和?roll()?的不同在于它們處理over-?and?underflows:?add()?傳遞變更到"較小"或"較大"的字段,?而roll()不影響其它字段.?比如,?當給代表12月15號的Calendar實例增加一個月,?當add()使用年會增加,?但使用roll()不會發生任何變化.?為每一種case對應一個函數的決定的動機是,?它們可能在GUI中不同的使用情形.

    由于?Calendar的實現的方式,?它包含冗余的數據:?所有的字段都可以從給定的時區和紀元開始的毫秒數計算出來,反之亦然.?這個類為這些操作分別定義了抽象方法computeFields()和computeTime(),?又定義了complete()方法執行完全的來回旅程.?因為有兩套冗余的數據,?這兩套數據可能不同步.?根據類的JavaDoc文檔,?當發生變更的時候依賴的數據以lazily?的方式重新計算.?當重新計算需要的時候,?子類必須維護一套臟數據標志作為符號.


    --------------------------------------------------------------------------------

    實現的Leakage

    對于一個”新”的日期相關處理類,?不得不說實現的細節在某種程度上被泄漏到了API中.?在這點上,?這是它們有意用作基類的自定義開發的反映,?但它也偶然看出是不充分清晰設計一個公共接口的結果.Calendar?抽象是否維護兩個冗余數據集合完全是一個實現的細節,?因而應當對客戶類隱藏.?這也包括打算通過繼承來重用此類.


    附加的功能

    Calendar基類提供的附加功能分成三類.?幾個靜態的工廠方法來獲得用任意時區和locales初始化的實例.?如前面提到的,?所有以這種方式獲得實例已經被初始化為當前時間.?沒有工廠方法被提供來獲得初始化為任意時間點的實例.

    第二組包含before(Object)和after(Object)方法.?它們接受Object類型的參數,?因而允許這些方法被子類以任意類型的參數覆蓋掉.

    最后,?有許多附加的方法來獲得設置附加的屬性,?比如當前的時區.?當中有幾個用以查詢特定字段在當前Calendar實現下的可能和實際的最大、最小值.


    java.util.GregorianCalendar


    GregorianCalendar?是僅有可用的Calendar的子類.?它提供了基礎Calendar抽象適合于根據在西方的習慣解釋日期的實現.?它增加了許多public的構造函數,?也有針對于Gregorian?Calendars的方法,?比如isLeapYear().


    java.util.TimeZone?和?java.util.SimpleTimeZone


    TimeZone?類和其子類是輔助類,?被Calendar用以根據選擇的時區來解釋日期.?按字面意思來說,?一個時區表示加到GMT上后到當前時區的一定的偏移.?顯然,?這個偏移在夏令時有效的時候會發生變化.?因而為了計算對于給定日期和時間的本地時間,?TimeZone抽象不僅需要明白當DST有效時的額外偏移,?而且還需明白什么時候DST有效的規則.


    抽象基類?TimeZone?提供了基本的處理"raw"(沒有考慮夏令時)實際偏移(用毫秒數!)的方法,?但任何關于DST規則的功能實現被留給了子類,?比如SimpleTimeZone.?后者提供了許多方法來指定控制DST開始和結束的規則,?比如在一個月中明確的某一天或某一天隨后的周幾.?每一個TimeZone?有一個可讀的,?本地無關的顯示名.?顯示名以兩種風格:?LONG和SHORT呈現.

    星期的開始?

    Calendar?的文檔投入了相當的文字來正確的計算月或年中的weeks.?weekday?被認為是一周的開始在因國家的不同而不同.?在美國,?一周通常被認為從周日開始.?在部分歐洲國家一周從周一開始結束于周日.這將影響到哪一周被認為是在一年(或月)第一個完整的周,?和計算一年的周數.


    時區由一標示字符串明確的決定.?基類提供靜態方法String[]?getAvailableIDs()來獲得所有已知安裝(JDK內帶有)的標準時區.?(在我的安裝內有557個,?JDK1.4.1)?假如需要,?JavaDoc?定義了嚴格的建立自定義時區標示符的語法.?也提供了靜態工廠方法用以獲取?—?指定ID或缺省的當前時區的TimeZone?實例.?SimpleTimeZone提供了一些公有的構造函數,?奇怪的是對于一個抽象類,?如TimeZone.?(JavaDoc?寫到?"子類構造函數調用."?顯然,?應該聲明為protected.)

    java.text.DateFormat

    盡管Calendar和相關類處理locale-specific日期的解釋,仍有DateFormat?類輔助日期和(人類)可閱讀字符串之間的變換.?表示一個時間點時,?會出現附加的本地化問題:?不僅僅在語言,?而且日期格式是地區獨立的(美國:?Month/Day/Year,德國:?Day.Month.Year,?等等).?DateFormat?盡力地為程序員管理這些不同.

    抽象基類DateFormat不需要(且不允許)?任意的,?程序員定義的日期格式.?作為替代,?它定義了四種格式化風格:?SHORT,?MEDIUM,?LONG,?和FULL?(以冗余增加的順序).對一給定locale和style,?程序員可依靠此類獲取適當的日期格式.

    抽象基類DateFormat?沒有定義靜態方法來完成文本和日期之間的格式化和轉換.?作為替代,?它定義了幾個靜態工廠方法來獲取被初始化為給定locale和選定style的實例.?既然標準的格式化總是包含日期和時間,?附加工廠方法可用來獲取僅處理時間或日期部分的實例.?String?format(Date)和Date?parse(String)?方法然后執行變形.?注意具體的子類可以選擇打破這種習慣.

    在其內部使用,?解釋日期的Calendar對象是可訪問和修改的,?TimeZone和NumberFormat對象也同樣.?然而,?一旦DateFormat?被實例化locale和style就不能再修改.

    亦有可用的(抽象的)用以拼接的字符串解析和格式化的方法,?分別接受額外的ParsePosition或FieldPosition參數.?這些方法的每一個都有兩個版本.?一個接受或返回Date實例另一個接受或返回普通的Object,?來允許在子類中有選擇性的處理Date.?它定義了一些以_FIELD?結尾的public?static變量來標示多種可能和FieldPosition一起使用的變量(cf.?java.util.Format的Javadoc).

    僅有且最常用的DateFormat類的具體實現是SimpleDateFormat.?它提供了所有上述的功能,?且允許定義任意的時間格式.?有一套豐富語法來指定格式化模式;?JavaDoc提供了所有細節.?模式可以被指定為構造函數的參數或顯式的設置.

    Printing?a?Timestamp:?A?Cut-and-Paste?Example

    想象你要用用戶定義的格式打印當前的時間;?比如,?到log文件.?以下就是做這些的:

    //?創建以下格式的模式:?Hour(0-23):Minute:Second

    SimpleDateFormat?formatter?=?new?SimpleDateFormat(?"HH:mm:ss"?);

    Date?now?=?new?Date();

    String?logEntry?=?formatter.format(now);


    //?從后端讀入

    try?{

    Date?sometime?=?formatter.parse(logEntry);

    }?catch?(?ParseException?exc?)?{

    exc.printStackTrace();

    }

    注意需要被catch的ParseException.?當輸入的字符串不能被parse的時候被拋出.


    java.sql.*相關類

    在java.sql.*包中的日期時間處理類都繼承了java.util.Date.?事實上它們三個反映了三種標準SQL92模型的類型需要DATE,?TIME,?and?TIMESTAMP.

    像java.util.Date,?SQL包中的這三個類是表示一個時間點的數字的簡單封裝.?分別地Date和Time類忽略關于一天中的時間或日歷的日期.

    可Timestamp類,?不僅包含到毫秒精度,?通常的時間和日期,?而且允許存儲附加的精確到納秒精度的時間點的數據.?(納秒是一秒的十億分之一)

    除了影射對應的SQL數據類型,?這些類處理與SQL一致的字符串表示的轉換.?在這一點,?這三個類中的每一個覆蓋了toString()方法.?此外,?每個類提供了靜態的工廠方法,?valueOf(String),?返回被初始化為傳遞參數字符串表示的時間的當前調用類的實例.?這三個方法的字符串表示的格式已被SQL標準選定,?且不能被程序員改變.

    存儲納秒需要的額外數據,?沒有很好的與在Timestamp中其它通常的時間和日期信息的表示一致.?比如,?在Timestamp實例上調用?getTime()?將返回自Unix紀元開始的毫秒數,忽略了納秒數據.?簡單地,?根據JavaDoc文檔,?hashCode()?方法在子類中沒有被覆蓋,?因而也忽略了納秒數據.

    java.sql.Timestamp的JavaDoc指出"inheritance?relationship?(...)?實際表示實現的繼承,?而不是類型繼承(這違反了繼承的初衷).?但即使這句話是錯誤的,?既然Java沒有私有繼承的概念(也即繼承實現).?所有java.sql.*包中的類應該被設計為封裝一個java.util.Date對象,?而不是繼承它,?僅暴露需要的方法?—?最起碼,?方法比如hashCode()?應該被適當的覆蓋.

    最后一個評論是關于數據庫引擎的時區的處理.?在java.sql.*包中的類不允許顯式的設置時區.?數據庫服務器(或驅動)?可自由的依據服務器server的當地時區解釋這些信息,?且其可能被影響而變化(比如,?因為夏令時).

    總結

    通過前面的討論,?很清楚,?Java的日期處理相關類并非很復雜,?但是沒有被很好設計.?封裝被疏漏,?APIs結構復雜且沒有被很好的組織,?且非常見的思路經常被無緣由的使用.?實現更有其它的莫名奇妙(提議看看Calendar.getInstance(Locale)對于所有可用locale實際返回對象的類型!)?另一方面,?the?classes?manage?to?treat?all?of?the?difficulties?inherent?in?internationalized?date?handling?and,?in?any?case,?are?here?to?stay.?希望這篇文章對幫助你搞清它們的用法有所幫助.


    posted on 2006-05-02 14:58 chenhui 閱讀(1250) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    介紹 IOC

    友情鏈接

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 又色又污又黄无遮挡的免费视| 一区二区三区免费电影| 亚洲午夜福利717| 全免费一级毛片在线播放| 成人免费福利视频| 久99久精品免费视频热77| 国产精品免费看久久久香蕉| MM1313亚洲精品无码久久| 亚洲真人无码永久在线观看| 亚洲综合久久综合激情久久| 亚洲精品中文字幕无码蜜桃| 亚洲人成中文字幕在线观看| 亚洲中文久久精品无码1| 亚洲理论在线观看| 亚洲欧洲在线播放| 亚洲欧美自偷自拍另类视| 老牛精品亚洲成av人片| 久久午夜夜伦鲁鲁片免费无码| 日本免费一区二区三区 | 免费在线观看a级毛片| 亚洲尹人香蕉网在线视颅| 亚洲av永久中文无码精品 | 亚洲久热无码av中文字幕| 三级网站在线免费观看| 国产在线观看无码免费视频| 国产一区二区免费| 一级毛片在线观看免费| 亚洲精品国产va在线观看蜜芽| 亚洲欧洲精品成人久久曰影片| 亚洲区视频在线观看| 亚洲av永久无码精品秋霞电影秋 | 美女羞羞喷液视频免费| 日本亚洲高清乱码中文在线观看| 久久综合国产乱子伦精品免费| 亚洲第一网站男人都懂| 亚洲午夜国产精品无码| 色屁屁www影院免费观看视频| 精品久久久久国产免费| 免费精品国产自产拍观看| 亚洲日韩国产成网在线观看| 亚洲国产成人片在线观看无码|