/** * Gets a copy of this date with the specified field set to a new value. * * <p>If this partial did not previously support the field, the new one will. Contrast this * behaviour with {@link #withField(DateTimeFieldType, int)}. * * <p>For example, if the field type is <code>dayOfMonth</code> then the day would be * changed/added in the returned instance. * * @param fieldType the field type to set, not null * @param value the value to set * @return a copy of this instance with the field set * @throws IllegalArgumentException if the value is null or invalid */ public Partial with(DateTimeFieldType fieldType, int value) { if (fieldType == null) { throw new IllegalArgumentException("The field type must not be null"); } int index = indexOf(fieldType); if (index == -1) { DateTimeFieldType[] newTypes = new DateTimeFieldType[iTypes.length + 1]; int[] newValues = new int[newTypes.length]; // find correct insertion point to keep largest-smallest order int i = 0; DurationField unitField = fieldType.getDurationType().getField(iChronology); if (unitField.isSupported()) { for (; i < iTypes.length; i++) { DateTimeFieldType loopType = iTypes[i]; DurationField loopUnitField = loopType.getDurationType().getField(iChronology); if (loopUnitField.isSupported()) { int compare = unitField.compareTo(loopUnitField); if (compare > 0) { break; } else if (compare == 0) { if (fieldType.getRangeDurationType() == null) { break; } if (loopType.getRangeDurationType() == null) { continue; } DurationField rangeField = fieldType.getRangeDurationType().getField(iChronology); DurationField loopRangeField = loopType.getRangeDurationType().getField(iChronology); if (rangeField.compareTo(loopRangeField) > 0) { break; } } } } } System.arraycopy(iTypes, 0, newTypes, 0, i); System.arraycopy(iValues, 0, newValues, 0, i); newTypes[i] = fieldType; newValues[i] = value; System.arraycopy(iTypes, i, newTypes, i + 1, newTypes.length - i - 1); System.arraycopy(iValues, i, newValues, i + 1, newValues.length - i - 1); // use public constructor to ensure full validation // this isn't overly efficient, but is safe Partial newPartial = new Partial(newTypes, newValues, iChronology); iChronology.validate(newPartial, newValues); return newPartial; } if (value == getValue(index)) { return this; } int[] newValues = getValues(); newValues = getField(index).set(this, index, newValues, value); return new Partial(this, newValues); }
/** * Constructs a Partial with the specified fields and values. The fields must be specified in the * order largest to smallest. For year and weekyear fields with equal duration, year is defined as * being larger than weekyear. * * <p>The constructor uses the specified chronology. * * @param types the types to create the partial from, not null * @param values the values to store, not null * @param chronology the chronology, null means ISO * @throws IllegalArgumentException if the types or values are invalid */ public Partial(DateTimeFieldType[] types, int[] values, Chronology chronology) { super(); chronology = DateTimeUtils.getChronology(chronology).withUTC(); iChronology = chronology; if (types == null) { throw new IllegalArgumentException("Types array must not be null"); } if (values == null) { throw new IllegalArgumentException("Values array must not be null"); } if (values.length != types.length) { throw new IllegalArgumentException("Values array must be the same length as the types array"); } if (types.length == 0) { iTypes = types; iValues = values; return; } for (int i = 0; i < types.length; i++) { if (types[i] == null) { throw new IllegalArgumentException("Types array must not contain null: index " + i); } } DurationField lastUnitField = null; for (int i = 0; i < types.length; i++) { DateTimeFieldType loopType = types[i]; DurationField loopUnitField = loopType.getDurationType().getField(iChronology); if (i > 0) { if (loopUnitField.isSupported() == false) { if (lastUnitField.isSupported()) { throw new IllegalArgumentException( "Types array must be in order largest-smallest: " + types[i - 1].getName() + " < " + loopType.getName()); } else { throw new IllegalArgumentException( "Types array must not contain duplicate unsupported: " + types[i - 1].getName() + " and " + loopType.getName()); } } int compare = lastUnitField.compareTo(loopUnitField); if (compare < 0) { throw new IllegalArgumentException( "Types array must be in order largest-smallest: " + types[i - 1].getName() + " < " + loopType.getName()); } else if (compare == 0) { if (lastUnitField.equals(loopUnitField)) { DurationFieldType lastRangeType = types[i - 1].getRangeDurationType(); DurationFieldType loopRangeType = loopType.getRangeDurationType(); if (lastRangeType == null) { if (loopRangeType == null) { throw new IllegalArgumentException( "Types array must not contain duplicate: " + types[i - 1].getName() + " and " + loopType.getName()); } } else { if (loopRangeType == null) { throw new IllegalArgumentException( "Types array must be in order largest-smallest: " + types[i - 1].getName() + " < " + loopType.getName()); } DurationField lastRangeField = lastRangeType.getField(iChronology); DurationField loopRangeField = loopRangeType.getField(iChronology); if (lastRangeField.compareTo(loopRangeField) < 0) { throw new IllegalArgumentException( "Types array must be in order largest-smallest: " + types[i - 1].getName() + " < " + loopType.getName()); } if (lastRangeField.compareTo(loopRangeField) == 0) { throw new IllegalArgumentException( "Types array must not contain duplicate: " + types[i - 1].getName() + " and " + loopType.getName()); } } } else { if (lastUnitField.isSupported() && lastUnitField.getType() != DurationFieldType.YEARS_TYPE) { throw new IllegalArgumentException( "Types array must be in order largest-smallest," + " for year-based fields, years is defined as being largest: " + types[i - 1].getName() + " < " + loopType.getName()); } } } } lastUnitField = loopUnitField; } iTypes = (DateTimeFieldType[]) types.clone(); chronology.validate(this, values); iValues = (int[]) values.clone(); }