接觸java不久,感覺java真的挺好玩的。
Calendar
類是一個抽象類,它為特定瞬間與一組諸如 YEAR
、MONTH
、DAY_OF_MONTH
、HOUR
等日歷字段之間的轉換提供了一些方法,並為操作日歷字段(例如獲得下星期的日期)提供了一些方法。
在書上看到一個挺好玩的代碼,通過這個代碼淺淺的研究了下java中的Calendar類
輸出的結果是:
PS:為了學習和理解方便,我將時間調回2011年,因為2012年剛好1月1號剛好是周日。
字段操作:
三種:set(),add(),roll();
set(f, value)
將日歷字段f
更改為value
。此外,它設置了一個內部成員變量,以指示日歷字段f
已經被更改。盡管日歷字段f
是立即更改的,但是直到下次調用get()
、getTime()
、getTimeInMillis()
、add()
或roll()
時才會重新計算日歷的時間值(以毫秒為單位)。因此,多次調用set()
不會觸發多次不必要的計算。使用set()
更改日歷字段的結果是,其他日歷字段也可能發生更改,這取決於日歷字段、日歷字段值和日歷系統。此外,在重新計算日歷字段之后,get(f)
沒必要通過調用set
方法返回value
集合。具體細節是通過具體的日歷類確定的。
示例:假定
GregorianCalendar
最初被設置為 1999 年 8 月 31 日。調用set(Calendar.MONTH, Calendar.SEPTEMBER)
將該日期設置為 1999 年 9 月 31 日。如果隨后調用getTime()
,那么這是解析 1999 年 10 月 1 日的一個暫時內部表示。但是,在調用getTime()
之前調用set(Calendar.DAY_OF_MONTH, 30)
會將該日期設置為 1999 年 9 月 30 日,因為在調用set()
之后沒有發生重新計算。
個人建議先跳過規則看下示例,然后再回過來理解。
add(f, delta)
將delta
添加到f
字段中。這等同於調用set(f, get(f) + delta)
,但要帶以下兩個調整:Add 規則 1。調用后
f
字段的值減去調用前f
字段的值等於delta
,以字段f
中發生的任何溢出為模。溢出發生在字段值超出其范圍時,結果,下一個更大的字段會遞增或遞減,並將字段值調整回其范圍內。Add 規則 2。如果期望某一個更小的字段是不變的,但讓它等於以前的值是不可能的,因為在字段
f
發生更改之后,或者在出現其他約束之后,比如時區偏移量發生更改,它的最大值和最小值也在發生更改,然后它的值被調整為盡量接近於所期望的值。更小的字段表示一個更小的時間單元。HOUR
是一個比DAY_OF_MONTH
小的字段。對於不期望是不變字段的更小字段,無需進行任何調整。日歷系統會確定期望不變的那些字段。此外,與
set()
不同,add()
強迫日歷系統立即重新計算日歷的毫秒數和所有字段。
示例:假定
GregorianCalendar
最初被設置為 1999 年 8 月 31 日。調用add(Calendar.MONTH, 13)
將日歷設置為 2000 年 9 月 30 日。Add 規則 1 將MONTH
字段設置為 September,因為向 August 添加 13 個月得出的就是下一年的 September。因為在GregorianCalendar
中,DAY_OF_MONTH
不可能是 9 月 31 日,所以 add 規則 2 將DAY_OF_MONTH
設置為 30,即最可能的值。盡管它是一個更小的字段,但不能根據規則 2 調整DAY_OF_WEEK
,因為在GregorianCalendar
中的月份發生變化時,該值也需要發生變化。
以下是代碼,書上的代碼及注釋+我自己的理解和調試觀察。
import java.text.DateFormatSymbols;
import java.util.*;
/**
* @version 1.4 2007-04-07
* @author Cay Horstmann
*/
public class CalendarTest
{
public static void main(String[] args)
{
// construct d as current date
//GregorianCalendar 是 Calendar 的一個具體子類,提供了世界上大多數國家/地區使用的標准日歷系統。
//用來表示默認地區。默認時區的當前時間。
GregorianCalendar d = new GregorianCalendar();
int today = d.get(Calendar.DAY_OF_MONTH);
int month = d.get(Calendar.MONTH);//0為第一個月
//以下一段代碼是測試,類里面的一些方法,測試娛樂。
/*
* int hour = d.get(Calendar.HOUR_OF_DAY);//0~23
* int minute = d.get(Calendar.MINUTE); //0~59
* int second = d.get(Calendar.SECOND); //0~59
* System.out.println(month+1+"月"+today+"日"+hour+"時"+minute+"分"+second+"秒");
*/
// set d to start date of the month
d.set(Calendar.DAY_OF_MONTH, 1);
//Sunday==1; 1<=weekday<=7;
int weekday = d.get(Calendar.DAY_OF_WEEK);
//因為是周六,所以weekday == 7;
//System.out.println(weekday);
// get first day of week (Sunday in the U.S.)
int firstDayOfWeek = d.getFirstDayOfWeek();
//firstDayOfWeek==1;
// determine the required indentation for the first line
int indent = 0;
//一周的第一天是否是月的第一天,如果不是,則追溯到上個月找到這個周的第一天所在的時間。
while (weekday != firstDayOfWeek)
{
indent++;
d.add(Calendar.DAY_OF_MONTH, -1);
weekday = d.get(Calendar.DAY_OF_WEEK);
//int temp=d.get(Calendar.DAY_OF_MONTH);
//System.out.println(temp);
}
/*
* DateFormatSymbols 是用於壓縮本地化的日期_時間格式化數據,如月份名稱、星期名稱和時區數據的公有類。
*
* public String[] getShortWeekdays()
* 獲得短型工作日字符串。 例如:"Sun", "Mon" 等。
* 返回值:短型工作日字符串。
*/
// print weekday names
String[] weekdayNames = new DateFormatSymbols().getShortWeekdays();
/*
* 以下循環操作類似於這個,但是前面一系列操作用於確定第一天是從周幾開始(因地區而異)。所以不用我下面這兩行程序
* for(int i=1; i<=7; i++)
* System.out.printf("%s", weekdayNames[i]);
*
* 此時:weekday == firstDayOfWeek
* 但地下循環為先執行后判斷,即從周的選定的第一天 開始循環7次
*/
do
{
System.out.printf("%4s", weekdayNames[weekday]);
d.add(Calendar.DAY_OF_MONTH, 1);
weekday = d.get(Calendar.DAY_OF_WEEK);
}while (weekday != firstDayOfWeek);
System.out.println();
//月的1號一般不是從周的第一天開始。比如:周的第一天是周日,而2011年的第一天是周六,空出前6天的位置。
for (int i = 1; i <= indent; i++)
System.out.print(" ");
d.set(Calendar.DAY_OF_MONTH, 1);
do
{
// print day
int day = d.get(Calendar.DAY_OF_MONTH);
System.out.printf("%3d", day);
// mark current day with *
if (day == today) System.out.print("*");
else System.out.print(" ");
// advance d to the next day
d.add(Calendar.DAY_OF_MONTH, 1);
weekday = d.get(Calendar.DAY_OF_WEEK);
// start a new line at the start of the week
if (weekday == firstDayOfWeek) System.out.println();
}while (d.get(Calendar.MONTH) == month);
// the loop exits when d is day 1 of the next month
// print final end of line if necessary
if (weekday != firstDayOfWeek) System.out.println();
}
}