📄 gregoriancalendar.java
字号:
fdm += 7; } // Get the first day of the first full week of the month, // including phantom days, if any. Figure out if the first week // counts or not; if it counts, then fill in phantom days. If // not, advance to the first real full week (skip the partial week). int start; if ((7 - fdm) < getMinimalDaysInFirstWeek()) { start = 8 - fdm; // Skip the first partial week } else { start = 1 - fdm; // This may be zero or negative } // Get the day of the week (normalized for locale) for the last // day of the month. int monthLen = monthLength(internalGet(MONTH)); int ldm = (monthLen - internalGet(DAY_OF_MONTH) + dow) % 7; // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here. // Get the limit day for the blocked-off rectangular month; that // is, the day which is one past the last day of the month, // after the month has already been filled in with phantom days // to fill out the last week. This day has a normalized DOW of 0. int limit = monthLen + 7 - ldm; // Now roll between start and (limit - 1). gap = limit - start; int day_of_month = (internalGet(DAY_OF_MONTH) + amount*7 - start) % gap; if (day_of_month < 0) { day_of_month += gap; } day_of_month += start; // Finally, pin to the real start and end of the month. if (day_of_month < 1) { day_of_month = 1; } if (day_of_month > monthLen) { day_of_month = monthLen; } // Set the DAY_OF_MONTH. We rely on the fact that this field // takes precedence over everything else (since all other fields // are also set at this point). If this fact changes (if the // disambiguation algorithm changes) then we will have to unset // the appropriate fields here so that DAY_OF_MONTH is attended // to. set(DAY_OF_MONTH, day_of_month); return; } case DAY_OF_MONTH: max = monthLength(internalGet(MONTH)); break; case DAY_OF_YEAR: { // Roll the day of year using millis. Compute the millis for // the start of the year, and get the length of the year. long delta = amount * ONE_DAY; // Scale up from days to millis long min2 = time - (internalGet(DAY_OF_YEAR) - 1) * ONE_DAY; int yearLength = yearLength(); time = (time + delta - min2) % (yearLength*ONE_DAY); if (time < 0) { time += yearLength*ONE_DAY; } long dst = internalGet(DST_OFFSET); setTimeInMillis(time + min2); dst -= internalGet(DST_OFFSET); if (dst != 0) { setTimeInMillis(time + dst); } return; } case DAY_OF_WEEK: { // Roll the day of week using millis. Compute the millis for // the start of the week, using the first day of week setting. // Restrict the millis to [start, start+7days). long delta = amount * ONE_DAY; // Scale up from days to millis // Compute the number of days before the current day in this // week. This will be a value 0..6. int leadDays = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek(); if (leadDays < 0) { leadDays += 7; } long min2 = time - leadDays * ONE_DAY; time = (time + delta - min2) % ONE_WEEK; if (time < 0) { time += ONE_WEEK; } long dst = internalGet(DST_OFFSET); setTimeInMillis(time + min2); dst -= internalGet(DST_OFFSET); if (dst != 0) { setTimeInMillis(time + dst); } return; } case DAY_OF_WEEK_IN_MONTH: { // Roll the day of week in the month using millis. Determine // the first day of the week in the month, and then the last, // and then roll within that range. long delta = amount * ONE_WEEK; // Scale up from weeks to millis // Find the number of same days of the week before this one // in this month. int preWeeks = (internalGet(DAY_OF_MONTH) - 1) / 7; // Find the number of same days of the week after this one // in this month. int postWeeks = (monthLength(internalGet(MONTH)) - internalGet(DAY_OF_MONTH)) / 7; // From these compute the min and gap millis for rolling. long min2 = time - preWeeks * ONE_WEEK; long gap2 = ONE_WEEK * (preWeeks + postWeeks + 1); // Must add 1! // Roll within this range time = (time + delta - min2) % gap2; if (time < 0) { time += gap2; } long dst = internalGet(DST_OFFSET); setTimeInMillis(time + min2); dst -= internalGet(DST_OFFSET); if (dst != 0) { setTimeInMillis(time + dst); } return; } case ZONE_OFFSET: case DST_OFFSET: default: // These fields cannot be rolled throw new IllegalArgumentException(); } // These are the standard roll instructions. These work for all // simple cases, that is, cases in which the limits are fixed, such // as the hour, the month, and the era. gap = max - min + 1; int value = internalGet(field) + amount; value = (value - min) % gap; if (value < 0) { value += gap; } value += min; set(field, value); } /** * Returns minimum value for the given field. * e.g. for Gregorian DAY_OF_MONTH, 1 * Please see Calendar.getMinimum for descriptions on parameters and * the return value. */ public int getMinimum(int field) { return MIN_VALUES[field]; } /** * Returns maximum value for the given field. * e.g. for Gregorian DAY_OF_MONTH, 31 * Please see Calendar.getMaximum for descriptions on parameters and * the return value. */ public int getMaximum(int field) { return MAX_VALUES[field]; } /** * Returns highest minimum value for the given field if varies. * Otherwise same as getMinimum(). For Gregorian, no difference. * Please see Calendar.getGreatestMinimum for descriptions on parameters * and the return value. */ public int getGreatestMinimum(int field) { return MIN_VALUES[field]; } /** * Returns lowest maximum value for the given field if varies. * Otherwise same as getMaximum(). For Gregorian DAY_OF_MONTH, 28 * Please see Calendar.getLeastMaximum for descriptions on parameters and * the return value. */ public int getLeastMaximum(int field) { return LEAST_MAX_VALUES[field]; } /** * Return the minimum value that this field could have, given the current date. * For the Gregorian calendar, this is the same as getMinimum() and getGreatestMinimum(). * @since 1.2 */ public int getActualMinimum(int field) { return getMinimum(field); } /** * Return the maximum value that this field could have, given the current date. * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar, * for some years the actual maximum for MONTH is 12, and for others 13. * @since 1.2 */ public int getActualMaximum(int field) { /* It is a known limitation that the code here (and in getActualMinimum) * won't behave properly at the extreme limits of GregorianCalendar's * representable range (except for the code that handles the YEAR * field). That's because the ends of the representable range are at * odd spots in the year. For calendars with the default Gregorian * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT * zones. As a result, if the calendar is set to Aug 1 292278994 AD, * the actual maximum of DAY_OF_MONTH is 17, not 30. If the date is Mar * 31 in that year, the actual maximum month might be Jul, whereas is * the date is Mar 15, the actual maximum might be Aug -- depending on * the precise semantics that are desired. Similar considerations * affect all fields. Nonetheless, this effect is sufficiently arcane * that we permit it, rather than complicating the code to handle such * intricacies. - liu 8/20/98 */ switch (field) { // we have functions that enable us to fast-path number of days in month // of year case DAY_OF_MONTH: return monthLength(get(MONTH)); case DAY_OF_YEAR: return yearLength(); // for week of year, week of month, or day of week in month, we // just fall back on the default implementation in Calendar (I'm not sure // we could do better by having special calculations here) case WEEK_OF_YEAR: case WEEK_OF_MONTH: case DAY_OF_WEEK_IN_MONTH: return super.getActualMaximum(field); case YEAR: /* The year computation is no different, in principle, from the * others, however, the range of possible maxima is large. In * addition, the way we know we've exceeded the range is different. * For these reasons, we use the special case code below to handle * this field. * * The actual maxima for YEAR depend on the type of calendar: * * Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD * Julian = Dec 2, 292269055 BC - Jan 3, 292272993 AD * Hybrid = Dec 2, 292269055 BC - Aug 17, 292278994 AD * * We know we've exceeded the maximum when either the month, date, * time, or era changes in response to setting the year. We don't * check for month, date, and time here because the year and era are * sufficient to detect an invalid year setting. NOTE: If code is * added to check the month and date in the future for some reason, * Feb 29 must be allowed to shift to Mar 1 when setting the year. */ { Calendar cal = (Calendar)this.clone(); cal.setLenient(true); int era = cal.get(ERA); Date d = cal.getTime(); /* Perform a binary search, with the invariant that lowGood is a * valid year, and highBad is an out of range year. */ int lowGood = LEAST_MAX_VALUES[YEAR]; int highBad = MAX_VALUES[YEAR] + 1; while ((lowGood + 1) < highBad) { int y = (lowGood + highBad) / 2; cal.set(YEAR, y); if (cal.get(YEAR) == y && cal.get(ERA) == era) { lowGood = y; } else { highBad = y; cal.setTime(d); // Restore original fields } } return lowGood; } // and we know none of the other fields have variable maxima in // GregorianCalendar, so we can just return the fixed maximum default: return getMaximum(field); } }//////////////////////// Proposed public API////////////////////// /** * Return true if the current time for this Calendar is in Daylignt * Savings Time. * * Note -- MAKE THIS PUBLIC AT THE NEXT API CHANGE. POSSIBLY DEPRECATE * AND REMOVE TimeZone.inDaylightTime(). */ boolean inDaylightTime() { if (!getTimeZone().useDaylightTime()) { return false; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -