Path: blob/master/src/java.base/share/classes/java/text/CalendarBuilder.java
41152 views
/*1* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.text;2627import java.util.Calendar;28import java.util.StringJoiner;29import static java.util.GregorianCalendar.*;3031/**32* {@code CalendarBuilder} keeps field-value pairs for setting33* the calendar fields of the given {@code Calendar}. It has the34* {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year35* support. Also {@code ISO_DAY_OF_WEEK} is used to specify36* {@code DAY_OF_WEEK} in the ISO day of week numbering.37*38* <p>{@code CalendarBuilder} retains the semantic of the pseudo39* timestamp for fields. {@code CalendarBuilder} uses a single40* int array combining fields[] and stamp[] of {@code Calendar}.41*42* @author Masayoshi Okutsu43*/44class CalendarBuilder {45/*46* Pseudo time stamp constants used in java.util.Calendar47*/48private static final int UNSET = 0;49private static final int COMPUTED = 1;50private static final int MINIMUM_USER_STAMP = 2;5152private static final int MAX_FIELD = FIELD_COUNT + 1;5354public static final int WEEK_YEAR = FIELD_COUNT;55public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index5657// stamp[] (lower half) and field[] (upper half) combined58private final int[] field;59private int nextStamp;60private int maxFieldIndex;6162CalendarBuilder() {63field = new int[MAX_FIELD * 2];64nextStamp = MINIMUM_USER_STAMP;65maxFieldIndex = -1;66}6768CalendarBuilder set(int index, int value) {69if (index == ISO_DAY_OF_WEEK) {70index = DAY_OF_WEEK;71value = toCalendarDayOfWeek(value);72}73field[index] = nextStamp++;74field[MAX_FIELD + index] = value;75if (index > maxFieldIndex && index < FIELD_COUNT) {76maxFieldIndex = index;77}78return this;79}8081CalendarBuilder addYear(int value) {82field[MAX_FIELD + YEAR] += value;83field[MAX_FIELD + WEEK_YEAR] += value;84return this;85}8687boolean isSet(int index) {88if (index == ISO_DAY_OF_WEEK) {89index = DAY_OF_WEEK;90}91return field[index] > UNSET;92}9394CalendarBuilder clear(int index) {95if (index == ISO_DAY_OF_WEEK) {96index = DAY_OF_WEEK;97}98field[index] = UNSET;99field[MAX_FIELD + index] = 0;100return this;101}102103Calendar establish(Calendar cal) {104boolean weekDate = isSet(WEEK_YEAR)105&& field[WEEK_YEAR] > field[YEAR];106if (weekDate && !cal.isWeekDateSupported()) {107// Use YEAR instead108if (!isSet(YEAR)) {109set(YEAR, field[MAX_FIELD + WEEK_YEAR]);110}111weekDate = false;112}113114cal.clear();115// Set the fields from the min stamp to the max stamp so that116// the field resolution works in the Calendar.117for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {118for (int index = 0; index <= maxFieldIndex; index++) {119if (field[index] == stamp) {120cal.set(index, field[MAX_FIELD + index]);121break;122}123}124}125126if (weekDate) {127int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;128int dayOfWeek = isSet(DAY_OF_WEEK) ?129field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();130if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {131if (dayOfWeek >= 8) {132dayOfWeek--;133weekOfYear += dayOfWeek / 7;134dayOfWeek = (dayOfWeek % 7) + 1;135} else {136while (dayOfWeek <= 0) {137dayOfWeek += 7;138weekOfYear--;139}140}141dayOfWeek = toCalendarDayOfWeek(dayOfWeek);142}143cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);144}145return cal;146}147148public String toString() {149StringJoiner sj = new StringJoiner(",", "CalendarBuilder:[", "]");150for (int i = 0; i < MAX_FIELD; i++) {151if (isSet(i)) {152sj.add(i + "=" + field[i] + ":" + field[MAX_FIELD + i]);153}154}155return sj.toString();156}157158static int toISODayOfWeek(int calendarDayOfWeek) {159return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;160}161162static int toCalendarDayOfWeek(int isoDayOfWeek) {163if (!isValidDayOfWeek(isoDayOfWeek)) {164// adjust later for lenient mode165return isoDayOfWeek;166}167return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;168}169170static boolean isValidDayOfWeek(int dayOfWeek) {171return dayOfWeek > 0 && dayOfWeek <= 7;172}173}174175176