gregoriancalendar.java
来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 1,497 行 · 第 1/5 页
JAVA
1,497 行
* @param date the value used to set the DATE time field in the calendar.
* @param hour the value used to set the HOUR_OF_DAY time field
* in the calendar.
* @param minute the value used to set the MINUTE time field
* in the calendar.
* @param second the value used to set the SECOND time field
* in the calendar.
*/
public GregorianCalendar(int year, int month, int date, int hour,
int minute, int second)
{
super(TimeZone.getDefault(), Locale.getDefault());
this.set(ERA, AD);
this.set(YEAR, year);
this.set(MONTH, month);
this.set(DATE, date);
this.set(HOUR_OF_DAY, hour);
this.set(MINUTE, minute);
this.set(SECOND, second);
}
/**
* Compares this calendar to the specified object.
* The result is <code>true</code> if and only if the argument is
* not <code>null</code> and is a <code>Calendar</code> object that
* represents the same calendar as this object.
* @param obj the object to compare with.
* @return <code>true</code> if the objects are the same;
* <code>false</code> otherwise.
*/
public boolean equals(Object obj) {
// This body moves to Calendar in 1.2
if (this == obj)
return true;
if (!(obj instanceof Calendar))
return false;
Calendar that = (Calendar)obj;
return getTimeInMillis() == that.getTimeInMillis() &&
isLenient() == that.isLenient() &&
getFirstDayOfWeek() == that.getFirstDayOfWeek() &&
getMinimalDaysInFirstWeek() == that.getMinimalDaysInFirstWeek() &&
getTimeZone().equals(that.getTimeZone());
}
/**
* Compares the time field records.
* Equivalent to comparing result of conversion to UTC.
* @param when the Calendar to be compared with this Calendar.
* @return true if the current time of this Calendar is before
* the time of Calendar when; false otherwise.
*/
public boolean before(Object when) {
// This body moves to Calendar in 1.2
return when instanceof Calendar &&
getTimeInMillis() < ((Calendar) when).getTimeInMillis();
}
/**
* Compares the time field records.
* Equivalent to comparing result of conversion to UTC.
* @param when the Calendar to be compared with this Calendar.
* @return true if the current time of this Calendar is after
* the time of Calendar when; false otherwise.
*/
public boolean after(Object when) {
// This body moves to Calendar in 1.2
return when instanceof Calendar &&
getTimeInMillis() > ((Calendar) when).getTimeInMillis();
}
/**
* Sets the GregorianCalendar change date. This is the point when the
* switch from Julian dates to Gregorian dates occurred. Default is
* 00:00:00 local time, October 15, 1582. Previous to this time and date
* will be Julian dates.
*
* @param date the given Gregorian cutover date.
*/
public void setGregorianChange(Date date)
{
gregorianCutover = date.getTime();
}
/**
* Gets the Gregorian Calendar change date. This is the point when the
* switch from Julian dates to Gregorian dates occurred. Default is
* 00:00:00 local time, October 15, 1582. Previous to
* this time and date will be Julian dates.
* @return the Gregorian cutover time for this calendar.
*/
public final Date getGregorianChange()
{
return new Date(gregorianCutover);
}
private static final int julianDayToDayOfWeek(long julian)
{
// If julian is negative, then julian%7 will be negative, so we adjust
// accordingly. We add 1 because Julian day 0 is Monday.
int dayOfWeek = (int)((julian + 1) % 7);
return dayOfWeek + ((dayOfWeek < 0) ? (7 + SUNDAY) : SUNDAY);
}
/**
* Convert the time as milliseconds to the "big" fields. Millis must be
* given as local wall millis to get the correct local day. For example,
* if it is 11:30 pm Standard, and DST is in effect, the correct DST millis
* must be passed in to get the right date.
*
* Fields that are completed by this method: ERA, YEAR, MONTH, DATE,
* DAY_OF_WEEK, DAY_OF_YEAR, WEEK_OF_YEAR, WEEK_OF_MONTH,
* DAY_OF_WEEK_IN_MONTH.
*/
private final void timeToFields(long theTime)
{
int year, month, date, dayOfWeek, dayOfYear, weekCount, era = AD;
//---------------------------------------------------------------------
// BEGIN modified caldat()
//---------------------------------------------------------------------
// The following variable names are somewhat cryptic. Unfortunately,
// they are from the original program cited above, and no explanation
// for their meaning is given. Given that the algorithm is cryptic too,
// perhaps it doesn't matter...
long ja, jb, jd;
long jc, je; // changed from int to fix number overflow problem.
long julian = millisToJulianDay(theTime);
if (theTime >= gregorianCutover)
{
long jalpha = (long) (((double) (julian - 1867216) - 0.25)
* INV1); /*ibm.7853*/
ja = julian + 1 + jalpha - (long) (0.25 * jalpha);
}
else
{
ja = julian;
}
jb = ja + 1524;
jc = (long) Math.floor(6680.0 + ((double) (jb - 2439870) - 122.1)
* INV2); /*ibm.7853*/
jd = (long) Math.floor(365*jc + (0.25 * jc));
je = (long) ((jb-jd) * INV3); /*ibm.7853*/
date = (int) (jb-jd-(long) (30.6001 * je));
month = (int) je - 1;
if (month > 12)
month -= 12;
year = (int) (jc-4715);
if (month > 2)
--year;
if (year <= 0)
{
era = BC;
year = 1-year;
}
//---------------------------------------------------------------------
// END modified caldat()
//---------------------------------------------------------------------
internalSet(ERA, era);
internalSet(YEAR, year);
internalSet(MONTH, month-1); // 0-based
internalSet(DATE, date);
dayOfWeek = julianDayToDayOfWeek(julian);
internalSet(DAY_OF_WEEK, dayOfWeek); // CLH, 8-7-96
if (isLeapYear(year))
dayOfYear = LEAP_NUM_DAYS[month-1] + date; // month: 0-based
else
dayOfYear = NUM_DAYS[month-1] + date; // month: 0-based
internalSet(DAY_OF_YEAR, dayOfYear);
internalSet(WEEK_OF_YEAR, weekNumber(dayOfYear, dayOfWeek));
internalSet(WEEK_OF_MONTH, weekNumber(date, dayOfWeek));
internalSet(DAY_OF_WEEK_IN_MONTH, (date-1) / 7 + 1);
}
/**
* Return the week number of a day, within a period. This may be the week number in
* a year, or the week number in a month. Usually this will be a value >= 1, but if
* some initial days of the period are excluded from week 1, because
* minimalDaysInFirstWeek is > 1, then the week number will be zero for those
* initial days. Requires the day of week for the given date in order to determine
* the day of week of the first day of the period.
*
* @param dayOfPeriod Day-of-year or day-of-month. Should be 1 for first day of period.
* @param day Day-of-week for given dayOfPeriod. 1-based with 1=Sunday.
* @return Week number, one-based, or zero if the day falls in part of the
* month before the first week, when there are days before the first
* week because the minimum days in the first week is more than one.
*/
private int weekNumber(int dayOfPeriod, int dayOfWeek)
{
// Determine the day of the week of the first day of the period
// in question (either a year or a month). Zero represents the
// first day of the week on this calendar.
int periodStartDayOfWeek = (dayOfWeek - getFirstDayOfWeek() - dayOfPeriod + 1) % 7;
if (periodStartDayOfWeek < 0) periodStartDayOfWeek += 7;
// Compute the week number. Initially, ignore the first week, which
// may be fractional (or may not be). We add periodStartDayOfWeek in
// order to fill out the first week, if it is fractional.
int weekNo = (dayOfPeriod + periodStartDayOfWeek - 1)/7;
// If the first week is long enough, then count it. If
// the minimal days in the first week is one, or if the period start
// is zero, we always increment weekNo.
if ((7 - periodStartDayOfWeek) >= getMinimalDaysInFirstWeek()) ++weekNo;
return weekNo;
}
/**
* Determines if the given year is a leap year. Returns true if the
* given year is a leap year.
* @param year the given year.
* @return true if the given year is a leap year; false otherwise.
*/
public boolean isLeapYear(int year)
{
// Compute the rough millis for the year. We only need this number to be
// good enough to compare it against JULIAN_ONSET.
long equivalent_millis = (long)((year - 1970) * 365.2422 * millisPerDay);
// No leap years before onset of Julian calendar
if (equivalent_millis < JULIAN_ONSET)
return false;
return (equivalent_millis > gregorianCutover) ?
((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))) : // Gregorian
(year%4 == 0); // Julian
}
/**
* Overrides Calendar
* Converts UTC as milliseconds to time field values.
* The time is <em>not</em>
* recomputed first; to recompute the time, then the fields, call the
* <code>complete</code> method.
* @see Calendar#complete
*/
protected void computeFields()
{
int gmtOffset = getTimeZone().getRawOffset();
long localMillis = time + gmtOffset;
// Time to fields takes the wall millis (Standard or DST).
timeToFields(localMillis);
int era = internalGet(ERA);
int year = internalGet(YEAR);
int month = internalGet(MONTH);
int date = internalGet(DATE);
int dayOfWeek = internalGet(DAY_OF_WEEK);
long days = (long) (localMillis / millisPerDay);
int millisInDay = (int) (localMillis - (days * millisPerDay));
if (millisInDay < 0) millisInDay += millisPerDay;
// Call getOffset() to get the TimeZone offset. The millisInDay value must
// be standard local millis.
int dstOffset = getTimeZone().getOffset(era,year,month,date,dayOfWeek,millisInDay) -
gmtOffset;
// Adjust our millisInDay for DST, if necessary.
millisInDay += dstOffset;
// If DST has pushed us into the next day, we must call timeToFields() again.
// This happens in DST between 12:00 am and 1:00 am every day. The call to
// timeToFields() will give the wrong day, since the Standard time is in the
// previous day.
if (millisInDay >= millisPerDay)
{
millisInDay -= millisPerDay;
localMillis += dstOffset;
timeToFields(localMillis);
}
// Fill in all time-related fields based on millisInDay. Call internalSet()
// so as not to perturb flags.
internalSet(MILLISECOND, millisInDay % 1000);
millisInDay /= 1000;
internalSet(SECOND, millisInDay % 60);
millisInDay /= 60;
internalSet(MINUTE, millisInDay % 60);
millisInDay /= 60;
internalSet(HOUR_OF_DAY, millisInDay);
internalSet(AM_PM, millisInDay / 12);
internalSet(HOUR, millisInDay % 12);
internalSet(ZONE_OFFSET, gmtOffset);
internalSet(DST_OFFSET, dstOffset);
// Careful here: We are manually setting the time stamps[] flags to
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?