gregoriancalendar.java
来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 989 行 · 第 1/3 页
JAVA
989 行
/**
* Converts the time field values (<code>fields</code>) to
* milliseconds since the epoch UTC (<code>time</code>).
*/
protected synchronized void computeTime() {
int era = isSet[ERA] ? fields[ERA] : AD;
int year = isSet[YEAR] ? fields[YEAR] : 1970;
if (era == BC)
year = 1 - year;
int[] daysOfYear = getDayOfYear(year);
int hour = 0;
if (isSet[HOUR_OF_DAY])
hour = fields[HOUR_OF_DAY];
else if (isSet[HOUR]) {
hour = fields[HOUR];
if (isSet[AM_PM] && fields[AM_PM] == PM)
hour += 12;
}
int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
int second = isSet[SECOND] ? fields[SECOND] : 0;
int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
int millisInDay;
if (isLenient()) {
// prevent overflow
long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L);
millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
} else {
if (hour < 0 || hour >= 24 || minute < 0 || minute > 59 || second < 0 || second > 59 || millis < 0 || millis >= 1000)
throw new IllegalArgumentException();
millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis;
}
time = getLinearTime(year, daysOfYear[0], millisInDay);
// Add the relative days after calculating the linear time, to
// get right behaviour when jumping over the gregorianCutover.
time += daysOfYear[1] * (24 * 60 * 60 * 1000L);
TimeZone zone = getTimeZone();
int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] : zone.getRawOffset();
int dayOfYear = daysOfYear[0] + daysOfYear[1];
int month = (dayOfYear * 5 + 3) / (31 + 30 + 31 + 30 + 31);
int day = (6 + (dayOfYear * 5 + 3) % (31 + 30 + 31 + 30 + 31)) / 5;
int weekday = ((int) (time / (24 * 60 * 60 * 1000L)) + THURSDAY) % 7;
if (weekday <= 0)
weekday += 7;
int dstOffset =
isSet[DST_OFFSET] ? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD, (year < 0) ? 1 - year : year, month, day, weekday, millisInDay) - zone.getRawOffset());
time -= rawOffset + dstOffset;
isTimeSet = true;
}
/**
* Determines if the given year is a leap year.
*
* The year should be positive and you can't give an ERA. But
* remember that before 4 BC there wasn't a consistent leap year
* rule, so who cares.
*
* @param year a year use nonnegative value for BC.
* @param gregorian if true, use gregorian leap year rule.
* @return true, if the given year is a leap year, false otherwise. */
private boolean isLeapYear(int year, boolean gregorian) {
if ((year & 3) != 0)
// Only years divisible by 4 can be leap years
return false;
if (!gregorian)
return true;
// We rely on AD area here.
return ((year % 100) != 0 || (year % 400) == 0);
}
/**
* Get the linear day in days since the epoch, using the
* Julian or Gregorian calendar as specified. If you specify a
* nonpositive year it is interpreted as BC as following: 0 is 1
* BC, -1 is 2 BC and so on.
*
* @param year the year of the date.
* @param dayOfYear the day of year of the date; 1 based.
* @param gregorian True, if we should use Gregorian rules.
* @return the days since the epoch, may be negative. */
private int getLinearDay(int year, int dayOfYear, boolean gregorian) {
// The 13 is the number of days, that were omitted in the Gregorian
// Calender until the epoch.
// We shift right by 2 instead of dividing by 4, to get correct
// results for negative years (and this is even more efficient).
int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear - ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
if (gregorian) {
// subtract the days that are missing in gregorian calendar
// with respect to julian calendar.
//
// Okay, here we rely on the fact that the gregorian
// calendar was introduced in the AD era. This doesn't work
// with negative years.
//
// The additional leap year factor accounts for the fact that
// a leap day is not seen on Jan 1 of the leap year.
int gregOffset = (year / 400) - (year / 100) + 2;
if (isLeapYear(year, true) && dayOfYear < 31 + 29)
--gregOffset;
julianDay += gregOffset;
}
return julianDay;
}
/**
* Converts the given linear day into era, year, month,
* day_of_year, day_of_month, day_of_week, and writes the result
* into the fields array.
* @param day the linear day.
*/
private void calculateDay(int day, boolean gregorian) {
// the epoch is a Thursday.
int weekday = (day + THURSDAY) % 7;
if (weekday <= 0)
weekday += 7;
fields[DAY_OF_WEEK] = weekday;
// get a first approximation of the year. This may be one
// year to big.
int year = 1970 + (gregorian ? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1) : ((day - 100) * 4) / (365 * 4 + 1));
if (day >= 0)
year++;
int firstDayOfYear = getLinearDay(year, 1, gregorian);
// Now look in which year day really lies.
if (day < firstDayOfYear) {
year--;
firstDayOfYear = getLinearDay(year, 1, gregorian);
}
day -= firstDayOfYear - 1; // day of year, one based.
fields[DAY_OF_YEAR] = day;
if (year <= 0) {
fields[ERA] = BC;
fields[YEAR] = 1 - year;
} else {
fields[ERA] = AD;
fields[YEAR] = year;
}
int leapday = isLeapYear(year, gregorian) ? 1 : 0;
if (day <= 31 + 28 + leapday) {
fields[MONTH] = day / 32; // 31->JANUARY, 32->FEBRUARY
fields[DAY_OF_MONTH] = day - 31 * fields[MONTH];
} else {
// A few more magic formulas
int scaledDay = (day - leapday) * 5 + 8;
fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
}
}
/**
* Converts the milliseconds since the epoch UTC
* (<code>time</code>) to time fields
* (<code>fields</code>).
*/
protected synchronized void computeFields() {
boolean gregorian = (time >= gregorianCutover);
TimeZone zone = getTimeZone();
fields[ZONE_OFFSET] = zone.getRawOffset();
long localTime = time + fields[ZONE_OFFSET];
int day = (int) (localTime / (24 * 60 * 60 * 1000L));
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
if (millisInDay < 0) {
millisInDay += (24 * 60 * 60 * 1000);
day--;
}
calculateDay(day, gregorian);
fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH], fields[DAY_OF_MONTH], fields[DAY_OF_WEEK], millisInDay) - fields[ZONE_OFFSET];
millisInDay += fields[DST_OFFSET];
if (millisInDay >= 24 * 60 * 60 * 1000) {
millisInDay -= 24 * 60 * 60 * 1000;
calculateDay(++day, gregorian);
}
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
// which day of the week are we (0..6), relative to getFirstDayOfWeek
int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 6) / 7;
int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
// Do the Correction: getMinimalDaysInFirstWeek() is always in the
// first week.
int minDays = getMinimalDaysInFirstWeek();
int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays) - getFirstDayOfWeek()) % 7;
if (minDays - firstWeekday < 1)
weekOfYear++;
fields[WEEK_OF_YEAR] = weekOfYear;
int hourOfDay = millisInDay / (60 * 60 * 1000);
fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
int hour = hourOfDay % 12;
fields[HOUR] = (hour == 0) ? 12 : hour;
fields[HOUR_OF_DAY] = hourOfDay;
millisInDay %= (60 * 60 * 1000);
fields[MINUTE] = millisInDay / (60 * 1000);
millisInDay %= (60 * 1000);
fields[SECOND] = millisInDay / (1000);
fields[MILLISECOND] = millisInDay % 1000;
areFieldsSet =
isSet[ERA] =
isSet[YEAR] =
isSet[MONTH] =
isSet[WEEK_OF_YEAR] =
isSet[WEEK_OF_MONTH] =
isSet[DAY_OF_MONTH] =
isSet[DAY_OF_YEAR] =
isSet[DAY_OF_WEEK] =
isSet[DAY_OF_WEEK_IN_MONTH] =
isSet[AM_PM] =
isSet[HOUR] =
isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
}
/**
* Compares the given calender with this.
* @param o the object to that we should compare.
* @return true, if the given object is a calendar, that represents
* the same time (but doesn't necessary have the same fields).
* @XXX Should we check if time zones, locale, cutover etc. are equal?
*/
public boolean equals(Object o) {
if (!(o instanceof GregorianCalendar))
return false;
GregorianCalendar cal = (GregorianCalendar)o;
return (cal.getTimeInMillis() == getTimeInMillis());
}
// /**
// * Compares the given calender with this.
// * @param o the object to that we should compare.
// * @return true, if the given object is a calendar, and this calendar
// * represents a smaller time than the calender o.
// */
// public boolean before(Object o) {
// if (!(o instanceof GregorianCalendar))
// return false;
// GregorianCalendar cal = (GregorianCalendar) o;
// return (cal.getTimeInMillis() < getTimeInMillis());
// }
// /**
// * Compares the given calender with this.
// * @param o the object to that we should compare.
// * @return true, if the given object is a calendar, and this calendar
// * represents a bigger time than the calender o.
// */
// public boolean after(Object o) {
// if (!(o instanceof GregorianCalendar))
// return false;
// GregorianCalendar cal = (GregorianCalendar) o;
// return (cal.getTimeInMillis() > getTimeInMillis());
// }
/**
* Adds the specified amount of time to the given time field. The
* amount may be negative to subtract the time. If the field overflows
* it does what you expect: Jan, 25 + 10 Days is Feb, 4.
* @param field the time field. One of the time field constants.
* @param amount the amount of time.
*/
public void add(int field, int amount) {
switch (field) {
case YEAR :
complete();
fields[YEAR] += amount;
isTimeSet = false;
break;
case MONTH :
complete();
int months = fields[MONTH] + amount;
fields[YEAR] += months / 12;
fields[MONTH] = months % 12;
if (fields[MONTH] < 0) {
fields[MONTH] += 12;
fields[YEAR]--;
}
isTimeSet = false;
int maxDay = getActualMaximum(DAY_OF_MONTH);
if (fields[DAY_OF_MONTH] > maxDay) {
fields[DAY_OF_MONTH] = maxDay;
isTimeSet = false;
}
break;
case DAY_OF_MONTH :
case DAY_OF_YEAR :
case DAY_OF_WEEK :
if (!isTimeSet)
computeTime();
time += amount * (24 * 60 * 60 * 1000L);
areFieldsSet = false;
break;
case WEEK_OF_YEAR :
case WEEK_OF_MONTH :
case DAY_OF_WEEK_IN_MONTH :
if (!isTimeSet)
computeTime();
time += amount * (7 * 24 * 60 * 60 * 1000L);
areFieldsSet = false;
break;
case AM_PM :
if (!isTimeSet)
computeTime();
time += amount * (12 * 60 * 60 * 1000L);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?