1311 month1 = fd - internalGet(DAY_OF_MONTH) + 1; |
1311 month1 = fd - internalGet(DAY_OF_MONTH) + 1; |
1312 monthLength = calsys.getMonthLength(cdate); |
1312 monthLength = calsys.getMonthLength(cdate); |
1313 } |
1313 } |
1314 |
1314 |
1315 // the first day of week of the month. |
1315 // the first day of week of the month. |
1316 long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(month1 + 6, |
1316 long monthDay1st = BaseCalendar.getDayOfWeekDateOnOrBefore(month1 + 6, |
1317 getFirstDayOfWeek()); |
1317 getFirstDayOfWeek()); |
1318 // if the week has enough days to form a week, the |
1318 // if the week has enough days to form a week, the |
1319 // week starts from the previous month. |
1319 // week starts from the previous month. |
1320 if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) { |
1320 if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) { |
1321 monthDay1st -= 7; |
1321 monthDay1st -= 7; |
1322 } |
1322 } |
2483 if (weekOfYear >= 52) { |
2483 if (weekOfYear >= 52) { |
2484 long nextJan1 = fixedDateJan1 + 365; |
2484 long nextJan1 = fixedDateJan1 + 365; |
2485 if (cdate.isLeapYear()) { |
2485 if (cdate.isLeapYear()) { |
2486 nextJan1++; |
2486 nextJan1++; |
2487 } |
2487 } |
2488 long nextJan1st = calsys.getDayOfWeekDateOnOrBefore(nextJan1 + 6, |
2488 long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6, |
2489 getFirstDayOfWeek()); |
2489 getFirstDayOfWeek()); |
2490 int ndays = (int)(nextJan1st - nextJan1); |
2490 int ndays = (int)(nextJan1st - nextJan1); |
2491 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { |
2491 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { |
2492 // The first days forms a week in which the date is included. |
2492 // The first days forms a week in which the date is included. |
2493 weekOfYear = 1; |
2493 weekOfYear = 1; |
2494 } |
2494 } |
2516 } else { |
2516 } else { |
2517 nextJan1 = gregorianCutoverDate; |
2517 nextJan1 = gregorianCutoverDate; |
2518 calForJan1 = gcal; |
2518 calForJan1 = gcal; |
2519 } |
2519 } |
2520 |
2520 |
2521 long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6, |
2521 long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6, |
2522 getFirstDayOfWeek()); |
2522 getFirstDayOfWeek()); |
2523 int ndays = (int)(nextJan1st - nextJan1); |
2523 int ndays = (int)(nextJan1st - nextJan1); |
2524 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { |
2524 if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) { |
2525 // The first days forms a week in which the date is included. |
2525 // The first days forms a week in which the date is included. |
2526 weekOfYear = 1; |
2526 weekOfYear = 1; |
2527 } |
2527 } |
2541 * |
2541 * |
2542 * @param fixedDay1 the fixed date of the first day of the period |
2542 * @param fixedDay1 the fixed date of the first day of the period |
2543 * @param fixedDate the fixed date of the last day of the period |
2543 * @param fixedDate the fixed date of the last day of the period |
2544 * @return the number of weeks of the given period |
2544 * @return the number of weeks of the given period |
2545 */ |
2545 */ |
2546 private final int getWeekNumber(long fixedDay1, long fixedDate) { |
2546 private int getWeekNumber(long fixedDay1, long fixedDate) { |
2547 // We can always use `gcal' since Julian and Gregorian are the |
2547 // We can always use `gcal' since Julian and Gregorian are the |
2548 // same thing for this calculation. |
2548 // same thing for this calculation. |
2549 long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6, |
2549 long fixedDay1st = Gregorian.getDayOfWeekDateOnOrBefore(fixedDay1 + 6, |
2550 getFirstDayOfWeek()); |
2550 getFirstDayOfWeek()); |
2551 int ndays = (int)(fixedDay1st - fixedDay1); |
2551 int ndays = (int)(fixedDay1st - fixedDay1); |
2552 assert ndays <= 7; |
2552 assert ndays <= 7; |
2553 if (ndays >= getMinimalDaysInFirstWeek()) { |
2553 if (ndays >= getMinimalDaysInFirstWeek()) { |
2554 fixedDay1st -= 7; |
2554 fixedDay1st -= 7; |
2555 } |
2555 } |
2816 fixedDate += internalGet(DAY_OF_MONTH); |
2816 fixedDate += internalGet(DAY_OF_MONTH); |
2817 fixedDate--; |
2817 fixedDate--; |
2818 } |
2818 } |
2819 } else { |
2819 } else { |
2820 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) { |
2820 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) { |
2821 long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6, |
2821 long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6, |
2822 getFirstDayOfWeek()); |
2822 getFirstDayOfWeek()); |
2823 // If we have enough days in the first week, then |
2823 // If we have enough days in the first week, then |
2824 // move to the previous week. |
2824 // move to the previous week. |
2825 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { |
2825 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { |
2826 firstDayOfWeek -= 7; |
2826 firstDayOfWeek -= 7; |
2827 } |
2827 } |
2828 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { |
2828 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { |
2829 firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, |
2829 firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, |
2830 internalGet(DAY_OF_WEEK)); |
2830 internalGet(DAY_OF_WEEK)); |
2831 } |
2831 } |
2832 // In lenient mode, we treat days of the previous |
2832 // In lenient mode, we treat days of the previous |
2833 // months as a part of the specified |
2833 // months as a part of the specified |
2834 // WEEK_OF_MONTH. See 4633646. |
2834 // WEEK_OF_MONTH. See 4633646. |
2835 fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1); |
2835 fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1); |
2848 dowim = internalGet(DAY_OF_WEEK_IN_MONTH); |
2848 dowim = internalGet(DAY_OF_WEEK_IN_MONTH); |
2849 } else { |
2849 } else { |
2850 dowim = 1; |
2850 dowim = 1; |
2851 } |
2851 } |
2852 if (dowim >= 0) { |
2852 if (dowim >= 0) { |
2853 fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1, |
2853 fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1, |
2854 dayOfWeek); |
2854 dayOfWeek); |
2855 } else { |
2855 } else { |
2856 // Go to the first day of the next week of |
2856 // Go to the first day of the next week of |
2857 // the specified week boundary. |
2857 // the specified week boundary. |
2858 int lastDate = monthLength(month, year) + (7 * (dowim + 1)); |
2858 int lastDate = monthLength(month, year) + (7 * (dowim + 1)); |
2859 // Then, get the day of week date on or before the last date. |
2859 // Then, get the day of week date on or before the last date. |
2860 fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1, |
2860 fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1, |
2861 dayOfWeek); |
2861 dayOfWeek); |
2862 } |
2862 } |
2863 } |
2863 } |
2864 } |
2864 } |
2865 } else { |
2865 } else { |
2866 if (year == gregorianCutoverYear && cal == gcal |
2866 if (year == gregorianCutoverYear && cal == gcal |
2875 if (isFieldSet(fieldMask, DAY_OF_YEAR)) { |
2875 if (isFieldSet(fieldMask, DAY_OF_YEAR)) { |
2876 // Add the offset, then subtract 1. (Make sure to avoid underflow.) |
2876 // Add the offset, then subtract 1. (Make sure to avoid underflow.) |
2877 fixedDate += internalGet(DAY_OF_YEAR); |
2877 fixedDate += internalGet(DAY_OF_YEAR); |
2878 fixedDate--; |
2878 fixedDate--; |
2879 } else { |
2879 } else { |
2880 long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6, |
2880 long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6, |
2881 getFirstDayOfWeek()); |
2881 getFirstDayOfWeek()); |
2882 // If we have enough days in the first week, then move |
2882 // If we have enough days in the first week, then move |
2883 // to the previous week. |
2883 // to the previous week. |
2884 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { |
2884 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) { |
2885 firstDayOfWeek -= 7; |
2885 firstDayOfWeek -= 7; |
2886 } |
2886 } |
2887 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { |
2887 if (isFieldSet(fieldMask, DAY_OF_WEEK)) { |
2888 int dayOfWeek = internalGet(DAY_OF_WEEK); |
2888 int dayOfWeek = internalGet(DAY_OF_WEEK); |
2889 if (dayOfWeek != getFirstDayOfWeek()) { |
2889 if (dayOfWeek != getFirstDayOfWeek()) { |
2890 firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, |
2890 firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6, |
2891 dayOfWeek); |
2891 dayOfWeek); |
2892 } |
2892 } |
2893 } |
2893 } |
2894 fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1); |
2894 fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1); |
2895 } |
2895 } |
2896 } |
2896 } |
2901 /** |
2901 /** |
2902 * Returns this object if it's normalized (all fields and time are |
2902 * Returns this object if it's normalized (all fields and time are |
2903 * in sync). Otherwise, a cloned object is returned after calling |
2903 * in sync). Otherwise, a cloned object is returned after calling |
2904 * complete() in lenient mode. |
2904 * complete() in lenient mode. |
2905 */ |
2905 */ |
2906 private final GregorianCalendar getNormalizedCalendar() { |
2906 private GregorianCalendar getNormalizedCalendar() { |
2907 GregorianCalendar gc; |
2907 GregorianCalendar gc; |
2908 if (isFullyNormalized()) { |
2908 if (isFullyNormalized()) { |
2909 gc = this; |
2909 gc = this; |
2910 } else { |
2910 } else { |
2911 // Create a clone and normalize the calendar fields |
2911 // Create a clone and normalize the calendar fields |
2956 * @param date the date for which the first day of the year is |
2956 * @param date the date for which the first day of the year is |
2957 * calculated. The date has to be in the cut-over year (Gregorian |
2957 * calculated. The date has to be in the cut-over year (Gregorian |
2958 * or Julian). |
2958 * or Julian). |
2959 * @param fixedDate the fixed date representation of the date |
2959 * @param fixedDate the fixed date representation of the date |
2960 */ |
2960 */ |
2961 private final long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) { |
2961 private long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) { |
2962 assert date.getNormalizedYear() == gregorianCutoverYear || |
2962 assert date.getNormalizedYear() == gregorianCutoverYear || |
2963 date.getNormalizedYear() == gregorianCutoverYearJulian; |
2963 date.getNormalizedYear() == gregorianCutoverYearJulian; |
2964 if (gregorianCutoverYear != gregorianCutoverYearJulian) { |
2964 if (gregorianCutoverYear != gregorianCutoverYearJulian) { |
2965 if (fixedDate >= gregorianCutoverDate) { |
2965 if (fixedDate >= gregorianCutoverDate) { |
2966 // Dates before the cutover date don't exist |
2966 // Dates before the cutover date don't exist |
2982 * @param date the date for which the first day of the month is |
2982 * @param date the date for which the first day of the month is |
2983 * calculated. The date has to be in the cut-over year (Gregorian |
2983 * calculated. The date has to be in the cut-over year (Gregorian |
2984 * or Julian). |
2984 * or Julian). |
2985 * @param fixedDate the fixed date representation of the date |
2985 * @param fixedDate the fixed date representation of the date |
2986 */ |
2986 */ |
2987 private final long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) { |
2987 private long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) { |
2988 assert date.getNormalizedYear() == gregorianCutoverYear || |
2988 assert date.getNormalizedYear() == gregorianCutoverYear || |
2989 date.getNormalizedYear() == gregorianCutoverYearJulian; |
2989 date.getNormalizedYear() == gregorianCutoverYearJulian; |
2990 BaseCalendar.Date gCutover = getGregorianCutoverDate(); |
2990 BaseCalendar.Date gCutover = getGregorianCutoverDate(); |
2991 if (gCutover.getMonth() == BaseCalendar.JANUARY |
2991 if (gCutover.getMonth() == BaseCalendar.JANUARY |
2992 && gCutover.getDayOfMonth() == 1) { |
2992 && gCutover.getDayOfMonth() == 1) { |
3021 /** |
3021 /** |
3022 * Returns a CalendarDate produced from the specified fixed date. |
3022 * Returns a CalendarDate produced from the specified fixed date. |
3023 * |
3023 * |
3024 * @param fd the fixed date |
3024 * @param fd the fixed date |
3025 */ |
3025 */ |
3026 private final BaseCalendar.Date getCalendarDate(long fd) { |
3026 private BaseCalendar.Date getCalendarDate(long fd) { |
3027 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem(); |
3027 BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem(); |
3028 BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE); |
3028 BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE); |
3029 cal.getCalendarDateFromFixedDate(d, fd); |
3029 cal.getCalendarDateFromFixedDate(d, fd); |
3030 return d; |
3030 return d; |
3031 } |
3031 } |
3032 |
3032 |
3033 /** |
3033 /** |
3034 * Returns the Gregorian cutover date as a BaseCalendar.Date. The |
3034 * Returns the Gregorian cutover date as a BaseCalendar.Date. The |
3035 * date is a Gregorian date. |
3035 * date is a Gregorian date. |
3036 */ |
3036 */ |
3037 private final BaseCalendar.Date getGregorianCutoverDate() { |
3037 private BaseCalendar.Date getGregorianCutoverDate() { |
3038 return getCalendarDate(gregorianCutoverDate); |
3038 return getCalendarDate(gregorianCutoverDate); |
3039 } |
3039 } |
3040 |
3040 |
3041 /** |
3041 /** |
3042 * Returns the day before the Gregorian cutover date as a |
3042 * Returns the day before the Gregorian cutover date as a |
3043 * BaseCalendar.Date. The date is a Julian date. |
3043 * BaseCalendar.Date. The date is a Julian date. |
3044 */ |
3044 */ |
3045 private final BaseCalendar.Date getLastJulianDate() { |
3045 private BaseCalendar.Date getLastJulianDate() { |
3046 return getCalendarDate(gregorianCutoverDate - 1); |
3046 return getCalendarDate(gregorianCutoverDate - 1); |
3047 } |
3047 } |
3048 |
3048 |
3049 /** |
3049 /** |
3050 * Returns the length of the specified month in the specified |
3050 * Returns the length of the specified month in the specified |
3051 * year. The year number must be normalized. |
3051 * year. The year number must be normalized. |
3052 * |
3052 * |
3053 * @see #isLeapYear(int) |
3053 * @see #isLeapYear(int) |
3054 */ |
3054 */ |
3055 private final int monthLength(int month, int year) { |
3055 private int monthLength(int month, int year) { |
3056 return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month]; |
3056 return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month]; |
3057 } |
3057 } |
3058 |
3058 |
3059 /** |
3059 /** |
3060 * Returns the length of the specified month in the year provided |
3060 * Returns the length of the specified month in the year provided |
3061 * by internalGet(YEAR). |
3061 * by internalGet(YEAR). |
3062 * |
3062 * |
3063 * @see #isLeapYear(int) |
3063 * @see #isLeapYear(int) |
3064 */ |
3064 */ |
3065 private final int monthLength(int month) { |
3065 private int monthLength(int month) { |
3066 int year = internalGet(YEAR); |
3066 int year = internalGet(YEAR); |
3067 if (internalGetEra() == BCE) { |
3067 if (internalGetEra() == BCE) { |
3068 year = 1 - year; |
3068 year = 1 - year; |
3069 } |
3069 } |
3070 return monthLength(month, year); |
3070 return monthLength(month, year); |
3071 } |
3071 } |
3072 |
3072 |
3073 private final int actualMonthLength() { |
3073 private int actualMonthLength() { |
3074 int year = cdate.getNormalizedYear(); |
3074 int year = cdate.getNormalizedYear(); |
3075 if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) { |
3075 if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) { |
3076 return calsys.getMonthLength(cdate); |
3076 return calsys.getMonthLength(cdate); |
3077 } |
3077 } |
3078 BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone(); |
3078 BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone(); |
3092 |
3092 |
3093 /** |
3093 /** |
3094 * Returns the length (in days) of the specified year. The year |
3094 * Returns the length (in days) of the specified year. The year |
3095 * must be normalized. |
3095 * must be normalized. |
3096 */ |
3096 */ |
3097 private final int yearLength(int year) { |
3097 private int yearLength(int year) { |
3098 return isLeapYear(year) ? 366 : 365; |
3098 return isLeapYear(year) ? 366 : 365; |
3099 } |
3099 } |
3100 |
3100 |
3101 /** |
3101 /** |
3102 * Returns the length (in days) of the year provided by |
3102 * Returns the length (in days) of the year provided by |
3103 * internalGet(YEAR). |
3103 * internalGet(YEAR). |
3104 */ |
3104 */ |
3105 private final int yearLength() { |
3105 private int yearLength() { |
3106 int year = internalGet(YEAR); |
3106 int year = internalGet(YEAR); |
3107 if (internalGetEra() == BCE) { |
3107 if (internalGetEra() == BCE) { |
3108 year = 1 - year; |
3108 year = 1 - year; |
3109 } |
3109 } |
3110 return yearLength(year); |
3110 return yearLength(year); |
3114 * After adjustments such as add(MONTH), add(YEAR), we don't want the |
3114 * After adjustments such as add(MONTH), add(YEAR), we don't want the |
3115 * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar |
3115 * month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar |
3116 * 3, we want it to go to Feb 28. Adjustments which might run into this |
3116 * 3, we want it to go to Feb 28. Adjustments which might run into this |
3117 * problem call this method to retain the proper month. |
3117 * problem call this method to retain the proper month. |
3118 */ |
3118 */ |
3119 private final void pinDayOfMonth() { |
3119 private void pinDayOfMonth() { |
3120 int year = internalGet(YEAR); |
3120 int year = internalGet(YEAR); |
3121 int monthLen; |
3121 int monthLen; |
3122 if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) { |
3122 if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) { |
3123 monthLen = monthLength(internalGet(MONTH)); |
3123 monthLen = monthLength(internalGet(MONTH)); |
3124 } else { |
3124 } else { |
3133 |
3133 |
3134 /** |
3134 /** |
3135 * Returns the fixed date value of this object. The time value and |
3135 * Returns the fixed date value of this object. The time value and |
3136 * calendar fields must be in synch. |
3136 * calendar fields must be in synch. |
3137 */ |
3137 */ |
3138 private final long getCurrentFixedDate() { |
3138 private long getCurrentFixedDate() { |
3139 return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate); |
3139 return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate); |
3140 } |
3140 } |
3141 |
3141 |
3142 /** |
3142 /** |
3143 * Returns the new value after 'roll'ing the specified value and amount. |
3143 * Returns the new value after 'roll'ing the specified value and amount. |
3144 */ |
3144 */ |
3145 private static final int getRolledValue(int value, int amount, int min, int max) { |
3145 private static int getRolledValue(int value, int amount, int min, int max) { |
3146 assert value >= min && value <= max; |
3146 assert value >= min && value <= max; |
3147 int range = max - min + 1; |
3147 int range = max - min + 1; |
3148 amount %= range; |
3148 amount %= range; |
3149 int n = value + amount; |
3149 int n = value + amount; |
3150 if (n > max) { |
3150 if (n > max) { |