You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.1 KiB
180 lines
5.1 KiB
/*
|
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package java.text;
|
|
|
|
import java.util.Calendar;
|
|
import static java.util.GregorianCalendar.*;
|
|
|
|
/**
|
|
* {@code CalendarBuilder} keeps field-value pairs for setting
|
|
* the calendar fields of the given {@code Calendar}. It has the
|
|
* {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
|
|
* support. Also {@code ISO_DAY_OF_WEEK} is used to specify
|
|
* {@code DAY_OF_WEEK} in the ISO day of week numbering.
|
|
*
|
|
* <p>{@code CalendarBuilder} retains the semantic of the pseudo
|
|
* timestamp for fields. {@code CalendarBuilder} uses a single
|
|
* int array combining fields[] and stamp[] of {@code Calendar}.
|
|
*
|
|
* @author Masayoshi Okutsu
|
|
*/
|
|
class CalendarBuilder {
|
|
/*
|
|
* Pseudo time stamp constants used in java.util.Calendar
|
|
*/
|
|
private static final int UNSET = 0;
|
|
private static final int COMPUTED = 1;
|
|
private static final int MINIMUM_USER_STAMP = 2;
|
|
|
|
private static final int MAX_FIELD = FIELD_COUNT + 1;
|
|
|
|
public static final int WEEK_YEAR = FIELD_COUNT;
|
|
public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
|
|
|
|
// stamp[] (lower half) and field[] (upper half) combined
|
|
private final int[] field;
|
|
private int nextStamp;
|
|
private int maxFieldIndex;
|
|
|
|
CalendarBuilder() {
|
|
field = new int[MAX_FIELD * 2];
|
|
nextStamp = MINIMUM_USER_STAMP;
|
|
maxFieldIndex = -1;
|
|
}
|
|
|
|
CalendarBuilder set(int index, int value) {
|
|
if (index == ISO_DAY_OF_WEEK) {
|
|
index = DAY_OF_WEEK;
|
|
value = toCalendarDayOfWeek(value);
|
|
}
|
|
field[index] = nextStamp++;
|
|
field[MAX_FIELD + index] = value;
|
|
if (index > maxFieldIndex && index < FIELD_COUNT) {
|
|
maxFieldIndex = index;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
CalendarBuilder addYear(int value) {
|
|
field[MAX_FIELD + YEAR] += value;
|
|
field[MAX_FIELD + WEEK_YEAR] += value;
|
|
return this;
|
|
}
|
|
|
|
boolean isSet(int index) {
|
|
if (index == ISO_DAY_OF_WEEK) {
|
|
index = DAY_OF_WEEK;
|
|
}
|
|
return field[index] > UNSET;
|
|
}
|
|
|
|
CalendarBuilder clear(int index) {
|
|
if (index == ISO_DAY_OF_WEEK) {
|
|
index = DAY_OF_WEEK;
|
|
}
|
|
field[index] = UNSET;
|
|
field[MAX_FIELD + index] = 0;
|
|
return this;
|
|
}
|
|
|
|
Calendar establish(Calendar cal) {
|
|
boolean weekDate = isSet(WEEK_YEAR)
|
|
&& field[WEEK_YEAR] > field[YEAR];
|
|
if (weekDate && !cal.isWeekDateSupported()) {
|
|
// Use YEAR instead
|
|
if (!isSet(YEAR)) {
|
|
set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
|
|
}
|
|
weekDate = false;
|
|
}
|
|
|
|
cal.clear();
|
|
// Set the fields from the min stamp to the max stamp so that
|
|
// the field resolution works in the Calendar.
|
|
for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
|
|
for (int index = 0; index <= maxFieldIndex; index++) {
|
|
if (field[index] == stamp) {
|
|
cal.set(index, field[MAX_FIELD + index]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (weekDate) {
|
|
int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
|
|
int dayOfWeek = isSet(DAY_OF_WEEK) ?
|
|
field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
|
|
if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
|
|
if (dayOfWeek >= 8) {
|
|
dayOfWeek--;
|
|
weekOfYear += dayOfWeek / 7;
|
|
dayOfWeek = (dayOfWeek % 7) + 1;
|
|
} else {
|
|
while (dayOfWeek <= 0) {
|
|
dayOfWeek += 7;
|
|
weekOfYear--;
|
|
}
|
|
}
|
|
dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
|
|
}
|
|
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
|
|
}
|
|
return cal;
|
|
}
|
|
|
|
public String toString() {
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append("CalendarBuilder:[");
|
|
for (int i = 0; i < field.length; i++) {
|
|
if (isSet(i)) {
|
|
sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
|
|
}
|
|
}
|
|
int lastIndex = sb.length() - 1;
|
|
if (sb.charAt(lastIndex) == ',') {
|
|
sb.setLength(lastIndex);
|
|
}
|
|
sb.append(']');
|
|
return sb.toString();
|
|
}
|
|
|
|
static int toISODayOfWeek(int calendarDayOfWeek) {
|
|
return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
|
|
}
|
|
|
|
static int toCalendarDayOfWeek(int isoDayOfWeek) {
|
|
if (!isValidDayOfWeek(isoDayOfWeek)) {
|
|
// adjust later for lenient mode
|
|
return isoDayOfWeek;
|
|
}
|
|
return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
|
|
}
|
|
|
|
static boolean isValidDayOfWeek(int dayOfWeek) {
|
|
return dayOfWeek > 0 && dayOfWeek <= 7;
|
|
}
|
|
}
|