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 + -
显示快捷键?