JDK源碼(二十三):Calendar

java.util.Calendar類是一個抽象類,它提供了在特定的時間戳和一組Calendar字段之間進行轉換的方法,例如年,月,日,小時等等,以及用於操作日曆字段的方法,比如下星期的日期。時間的戳可以用毫秒值表示,該值是從1970年1月1日格林尼治標準時間00:00:00.000(公曆)開始的偏移量。該類還提供了用於在包外實現具體日曆系統的其他字段和方法。這些字段和方法被定義爲protected。

Calendar對象可以生成實現特定語言和日曆樣式的日期時間格式所需的所有日曆字段值。Calendar定義某些日曆字段返回的值的範圍及其含義。例如,對於所有日曆,日曆系統的第一個月都有值month==JANUARY。其他值由具體的子類定義。可以通過調用set方法設置日曆字段值。在需要計算其時間值(從紀元開始的毫秒數)或日曆字段的值之前,在日曆中設置的任何字段值都不會被解釋。

Calendar有兩種解釋日曆字段的模式,容錯和非容錯。當日歷處於容錯模式時,它接受的日曆字段值範圍比它產生的值範圍更廣。當日歷重新計算日曆字段值以通過get()返回時,所有日曆字段都將規範化。例如,容錯的GregorianCalendar將MONTH=一月,DAY=32解釋爲二月一日。

當日歷處於非容錯模式時,如果日曆字段中存在任何不一致,它將引發異常。例如,GregorianCalendar總是生成介於1和月長之間的DAY_OF_MONTH。如果設置了任何超出範圍的字段值,則非容錯的GregorianCalendar在計算其時間或日曆字段值時引發異常。

類名

public abstract class Calendar 
        implements Serializable, Cloneable, Comparable<Calendar>

變量

/**
     * 此日曆當前設置時間的日曆字段值.
     */
    @SuppressWarnings("ProtectedField")
    protected int           fields[];

    /**
     * 指示是否設置了日曆的指定日曆字段的標誌。
	 * 新對象沒有設置字段。在第一次調用生成字段的方法之後,
	 * 這些字段都保持設置不變
     */
    @SuppressWarnings("ProtectedField")
    protected boolean       isSet[];

    /**
     * 指定每個字段設置時間的僞時間戳。
	 * 有兩個特殊值,UNSET和COMPUTED。
	 * 從MINIMUM_USER_SET到Integer.MAX_VALUE的值是合法的用戶設置值。
     */
    transient private int   stamp[];

    /**
     * 此日曆的當前設置時間,
	 * 以1970年1月1日0:00:00 GMT之後的毫秒爲單位。
     */
    @SuppressWarnings("ProtectedField")
    protected long          time;

    /**
     * 如果time的值有效,則爲True
     */
    @SuppressWarnings("ProtectedField")
    protected boolean       isTimeSet;

    /**
     * 如果fields[]與當前設置的時間同步,則爲True。
	 * 如果爲false,則下一次嘗試獲取字段值時將強制從當前值time重新計算所有字段。
     */
    @SuppressWarnings("ProtectedField")
    protected boolean       areFieldsSet;

    /**
     * 如果已設置所有fields,則爲True。
     */
    transient boolean       areAllFieldsSet;

    /**
     * 如果此日曆允許在從fields[]計算時間期間字段值超出範圍,則爲True。
     */
    private boolean         lenient = true;

除了上面這些變量,Calendar還提供了很多時間相關的靜態變量,如YEAR、MONTH、WEEK_OF_YEAR ...

實例

Calendar calendar = Calendar.getInstance();

由於Calendar是抽象類,不能使用new關鍵字。在getInstance()方法中會根據TimeZone時區類型和Locale地區類型創建Calendar對象。

getInstance()

public static Calendar getInstance()
{
    return createCalendar(TimeZone.getDefault(), 
            Locale.getDefault(Locale.Category.FORMAT));
}

createCalendar(TimeZone zone, Locale aLocale)

private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                 .getCalendarProvider();
        if (provider != null) {
            try {
				//使用Builder創建Calendar
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
            }
        }

        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
				//佛曆
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
				//日本歷
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
				//公曆
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        if (cal == null) {
            // 如果沒有顯式指定已知的日曆類型,請執行創建日曆的傳統方法
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }

獲取日期

set(int field, int value)

public void set(int field, int value)
    {
        // 如果字段部分規範化,請在更改任何字段之前計算所有字段.
        if (areFieldsSet && !areAllFieldsSet) {
            computeFields();
        }
		//設置時間屬性值
        internalSet(field, value);
        isTimeSet = false;
        areFieldsSet = false;
        isSet[field] = true;
		//指定每個字段設置時間的僞時間戳
        stamp[field] = nextStamp++;
        if (nextStamp == Integer.MAX_VALUE) {
			//在nextStamp溢出之前調整stamp[]值。
            adjustStamp();
        }
    }

set方法是將給定的日曆字段設置爲給定值,internalSet方法中只有一句,fields[field] = value;將value值賦值到fields[]屬性中。例如set(Calendar.YEAR, 2019)則表示將年份設置成2019年。

get(int field)

public int get(int field)
    {
		//填寫日曆字段中任何未設置的字段
        complete();
		//返回field數組中的值
        return internalGet(field);
    }

get方法用來獲取實例化的Calendar對象儲存的年月日時分秒星期等等信息,complete方法主要是對所有日期字段的值進行計算並賦值給相應變量。方法的參數通過Calendar.XXXX的形式填寫,比如要想獲取年份信息就用Calendar.YEAR、月份Calendar.MONTH、日期Calendar.Date、時Calendar.HOUR、分Calendar.MINUTE、秒Calendar.SECOND等等。

add(int field, int amount)

abstract public void add(int field, int amount);

add方法根據日曆的規則,向給定日曆字段添加或減去指定的時間量。此方法是抽象方法,調用的時候根據生成的Calendar對象調用對應的add方法。

前一天

        Calendar calendar = Calendar.getInstance();
        Date time = calendar.getTime();
        System.out.println(time);// Fri Feb 28 20:39:10 CST 2020
        //昨天
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        System.out.println(calendar.getTime());

更多精彩內容請關注微信公衆號:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章