Java中的Calendar日历API用法完全解析
|
第一部分 Calendar介绍
public abstract class Calendar implements Serializable,Cloneable,Comparable<Calendar> {}
Calendar 可以看作是一个抽象类。
public static Calendar getInstance()
{
// 调用createCalendar()创建日历
Calendar cal = createCalendar(TimeZone.getDefaultRef(),Locale.getDefault());
cal.sharedZone = true;
return cal;
}
public static Calendar getInstance(TimeZone zone)
{
// 调用createCalendar()创建日历
return createCalendar(zone,Locale.getDefault());
}
public static Calendar getInstance(Locale aLocale) {
// 调用createCalendar()创建日历
Calendar cal = createCalendar(TimeZone.getDefaultRef(),aLocale);
cal.sharedZone = true;
return cal;
}
public static Calendar getInstance(TimeZone zone,Locale aLocale)
{
// 调用createCalendar()创建日历
return createCalendar(zone,aLocale);
}
private static Calendar createCalendar(TimeZone zone,Locale aLocale)
{
// (01) 若地区是“th”,则返回BuddhistCalendar对象
// (02) 若地区是“JP”,则返回JapaneseImperialCalendar对象
if ("th".equals(aLocale.getLanguage())
&& ("TH".equals(aLocale.getCountry()))) {
return new sun.util.BuddhistCalendar(zone,aLocale);
} else if ("JP".equals(aLocale.getVariant())
&& "JP".equals(aLocale.getCountry())
&& "ja".equals(aLocale.getLanguage())) {
return new JapaneseImperialCalendar(zone,aLocale);
}
// (03) 否则,返回GregorianCalendar对象
return new GregorianCalendar(zone,aLocale);
}
当我们获取Calendar实例之后,就可以通过Calendar提供的一些列方法来操作日历。 第二部分 Calendar的原理和思想 // time 是当前时间,单位是毫秒。 // 它是当前时间距离“January 1,1970,0:00:00 GMT”的差值。 protected long time; Calendar就是根据 time 计算出 “Calendar的年、月、日、星期、时、分、秒”等等信息。 2. Calendar 各个字段的定义和初始化
// 保存这17个字段的数组
protected int fields[];
// 数组的定义函数
protected Calendar(TimeZone zone,Locale aLocale)
{
// 初始化“fields数组”
fields = new int[FIELD_COUNT];
isSet = new boolean[FIELD_COUNT];
stamp = new int[FIELD_COUNT];
this.zone = zone;
setWeekCountData(aLocale);
}
protected Calendar(TimeZone zone,Locale aLocale) 这是Calendar的构造函数。它会被它的子类的构造函数调用到,从而新建“保存Calendar的17个字段数据”的数组。 3. Calendar 各个字段值的计算
public int get(int field) {
// 计算各个字段的值
complete();
// 返回field字段的值
return internalGet(field);
}
说明:get(int field)的代码很简单。先通过 complete() 计算各个字段的值,然后在通过 internalGet(field) 返回“field字段的值”。
protected void complete()
{
if (!isTimeSet)
updateTime();
if (!areFieldsSet || !areAllFieldsSet) {
computeFields(); // fills in unset fields
areAllFieldsSet = areFieldsSet = true;
}
}
private void updateTime() {
computeTime();
isTimeSet = true;
}
updateTime() 调用到的 computeTime() 定义在 Calendar.java的实现类中。下面,我列出GregorianCalendar.java中computeTime()的实现:
protected void computeTime() {
// In non-lenient mode,perform brief checking of calendar
// fields which have been set externally. Through this
// checking,the field values are stored in originalFields[]
// to see if any of them are normalized later.
if (!isLenient()) {
if (originalFields == null) {
originalFields = new int[FIELD_COUNT];
}
for (int field = 0; field < FIELD_COUNT; field++) {
int value = internalGet(field);
if (isExternallySet(field)) {
// Quick validation for any out of range values
if (value < getMinimum(field) || value > getMaximum(field)) {
throw new IllegalArgumentException(getFieldName(field));
}
}
originalFields[field] = value;
}
}
// Let the super class determine which calendar fields to be
// used to calculate the time.
int fieldMask = selectFields();
// The year defaults to the epoch start. We don't check
// fieldMask for YEAR because YEAR is a mandatory field to
// determine the date.
int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
int era = internalGetEra();
if (era == BCE) {
year = 1 - year;
} else if (era != CE) {
// Even in lenient mode we disallow ERA values other than CE & BCE.
// (The same normalization rule as add()/roll() could be
// applied here in lenient mode. But this checking is kept
// unchanged for compatibility as of 1.5.)
throw new IllegalArgumentException("Invalid era");
}
// If year is 0 or negative,we need to set the ERA value later.
if (year <= 0 && !isSet(ERA)) {
fieldMask |= ERA_MASK;
setFieldsComputed(ERA_MASK);
}
// Calculate the time of day. We rely on the convention that
// an UNSET field has 0.
long timeOfDay = 0;
if (isFieldSet(fieldMask,HOUR_OF_DAY)) {
timeOfDay += (long) internalGet(HOUR_OF_DAY);
} else {
timeOfDay += internalGet(HOUR);
// The default value of AM_PM is 0 which designates AM.
if (isFieldSet(fieldMask,AM_PM)) {
timeOfDay += 12 * internalGet(AM_PM);
}
}
timeOfDay *= 60;
timeOfDay += internalGet(MINUTE);
timeOfDay *= 60;
timeOfDay += internalGet(SECOND);
timeOfDay *= 1000;
timeOfDay += internalGet(MILLISECOND);
// Convert the time of day to the number of days and the
// millisecond offset from midnight.
long fixedDate = timeOfDay / ONE_DAY;
timeOfDay %= ONE_DAY;
while (timeOfDay < 0) {
timeOfDay += ONE_DAY;
--fixedDate;
}
// Calculate the fixed date since January 1,1 (Gregorian).
calculateFixedDate: {
long gfd,jfd;
if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
gfd = fixedDate + getFixedDate(gcal,year,fieldMask);
if (gfd >= gregorianCutoverDate) {
fixedDate = gfd;
break calculateFixedDate;
}
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(),fieldMask);
} else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(),fieldMask);
if (jfd < gregorianCutoverDate) {
fixedDate = jfd;
break calculateFixedDate;
}
gfd = fixedDate + getFixedDate(gcal,fieldMask);
} else {
gfd = fixedDate + getFixedDate(gcal,fieldMask);
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(),fieldMask);
}
// Now we have to determine which calendar date it is.
if (gfd >= gregorianCutoverDate) {
if (jfd >= gregorianCutoverDate) {
fixedDate = gfd;
} else {
// The date is in an "overlapping" period. No way
// to disambiguate it. Determine it using the
// previous date calculation.
if (calsys == gcal || calsys == null) {
fixedDate = gfd;
} else {
fixedDate = jfd;
}
}
} else {
if (jfd < gregorianCutoverDate) {
fixedDate = jfd;
} else {
// The date is in a "missing" period.
if (!isLenient()) {
throw new IllegalArgumentException("the specified date doesn't exist");
}
// Take the Julian date for compatibility,which
// will produce a Gregorian date.
fixedDate = jfd;
}
}
}
// millis represents local wall-clock time in milliseconds.
long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
// Compute the time zone offset and DST offset. There are two potential
// ambiguities here. We'll assume a 2:00 am (wall time) switchover time
// for discussion purposes here.
// 1. The transition into DST. Here,a designated time of 2:00 am - 2:59 am
// can be in standard or in DST depending. However,2:00 am is an invalid
// representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
// We assume standard time.
// 2. The transition out of DST. Here,a designated time of 1:00 am - 1:59 am
// can be in standard or DST. Both are valid representations (the rep
// jumps from 1:59:59 DST to 1:00:00 Std).
// Again,we assume standard time.
// We use the TimeZone object,unless the user has explicitly set the ZONE_OFFSET
// or DST_OFFSET fields; then we use those fields.
TimeZone zone = getZone();
if (zoneOffsets == null) {
zoneOffsets = new int[2];
}
int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
if (zone instanceof ZoneInfo) {
((ZoneInfo)zone).getOffsetsByWall(millis,zoneOffsets);
} else {
int gmtOffset = isFieldSet(fieldMask,ZONE_OFFSET) ?
internalGet(ZONE_OFFSET) : zone.getRawOffset();
zone.getOffsets(millis - gmtOffset,zoneOffsets);
}
}
if (tzMask != 0) {
if (isFieldSet(tzMask,ZONE_OFFSET)) {
zoneOffsets[0] = internalGet(ZONE_OFFSET);
}
if (isFieldSet(tzMask,DST_OFFSET)) {
zoneOffsets[1] = internalGet(DST_OFFSET);
}
}
// Adjust the time zone offset values to get the UTC time.
millis -= zoneOffsets[0] + zoneOffsets[1];
// Set this calendar's time in milliseconds
time = millis;
int mask = computeFields(fieldMask | getSetStateFields(),tzMask);
if (!isLenient()) {
for (int field = 0; field < FIELD_COUNT; field++) {
if (!isExternallySet(field)) {
continue;
}
if (originalFields[field] != internalGet(field)) {
// Restore the original field values
System.arraycopy(originalFields,fields,fields.length);
throw new IllegalArgumentException(getFieldName(field));
}
}
}
setFieldsNormalized(mask);
}
下面,我们看看internalGet(field)的定义。如下:
protected final int internalGet(int field) {
return fields[field];
}
(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
