EMMA Coverage Report (generated Tue Oct 28 00:01:11 GMT 2008)
[all classes][org.joda.time]

COVERAGE SUMMARY FOR SOURCE FILE [Partial.java]

nameclass, %method, %block, %line, %
Partial.java100% (2/2)100% (45/45)100% (1187/1192)100% (248/249)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Partial100% (1/1)100% (33/33)100% (1060/1065)100% (225/226)
isMatch (ReadablePartial): boolean 100% (1/1)85%  (28/33)86%  (6/7)
Partial (): void 100% (1/1)100% (5/5)100% (2/2)
Partial (Chronology): void 100% (1/1)100% (16/16)100% (5/5)
Partial (Chronology, DateTimeFieldType [], int []): void 100% (1/1)100% (12/12)100% (5/5)
Partial (DateTimeFieldType [], int []): void 100% (1/1)100% (6/6)100% (2/2)
Partial (DateTimeFieldType [], int [], Chronology): void 100% (1/1)100% (248/248)100% (41/41)
Partial (DateTimeFieldType, int): void 100% (1/1)100% (6/6)100% (2/2)
Partial (DateTimeFieldType, int, Chronology): void 100% (1/1)100% (38/38)100% (9/9)
Partial (Partial, int []): void 100% (1/1)100% (14/14)100% (5/5)
Partial (ReadablePartial): void 100% (1/1)100% (48/48)100% (10/10)
getChronology (): Chronology 100% (1/1)100% (3/3)100% (1/1)
getField (int, Chronology): DateTimeField 100% (1/1)100% (7/7)100% (1/1)
getFieldType (int): DateTimeFieldType 100% (1/1)100% (5/5)100% (1/1)
getFieldTypes (): DateTimeFieldType [] 100% (1/1)100% (5/5)100% (1/1)
getFormatter (): DateTimeFormatter 100% (1/1)100% (45/45)100% (13/13)
getValue (int): int 100% (1/1)100% (5/5)100% (1/1)
getValues (): int [] 100% (1/1)100% (5/5)100% (1/1)
isMatch (ReadableInstant): boolean 100% (1/1)100% (34/34)100% (7/7)
minus (ReadablePeriod): Partial 100% (1/1)100% (5/5)100% (1/1)
plus (ReadablePeriod): Partial 100% (1/1)100% (5/5)100% (1/1)
property (DateTimeFieldType): Partial$Property 100% (1/1)100% (8/8)100% (1/1)
size (): int 100% (1/1)100% (4/4)100% (1/1)
toString (): String 100% (1/1)100% (29/29)100% (10/10)
toString (String): String 100% (1/1)100% (10/10)100% (3/3)
toString (String, Locale): String 100% (1/1)100% (12/12)100% (3/3)
toStringList (): String 100% (1/1)100% (55/55)100% (11/11)
with (DateTimeFieldType, int): Partial 100% (1/1)100% (173/173)100% (35/35)
withChronologyRetainFields (Chronology): Partial 100% (1/1)100% (28/28)100% (7/7)
withField (DateTimeFieldType, int): Partial 100% (1/1)100% (29/29)100% (6/6)
withFieldAddWrapped (DurationFieldType, int): Partial 100% (1/1)100% (26/26)100% (6/6)
withFieldAdded (DurationFieldType, int): Partial 100% (1/1)100% (26/26)100% (6/6)
withPeriodAdded (ReadablePeriod, int): Partial 100% (1/1)100% (46/46)100% (9/9)
without (DateTimeFieldType): Partial 100% (1/1)100% (74/74)100% (12/12)
     
class Partial$Property100% (1/1)100% (12/12)100% (127/127)100% (23/23)
Partial$Property (Partial, int): void 100% (1/1)100% (9/9)100% (4/4)
addToCopy (int): Partial 100% (1/1)100% (21/21)100% (3/3)
addWrapFieldToCopy (int): Partial 100% (1/1)100% (21/21)100% (3/3)
get (): int 100% (1/1)100% (6/6)100% (1/1)
getField (): DateTimeField 100% (1/1)100% (6/6)100% (1/1)
getPartial (): Partial 100% (1/1)100% (3/3)100% (1/1)
getReadablePartial (): ReadablePartial 100% (1/1)100% (3/3)100% (1/1)
setCopy (String): Partial 100% (1/1)100% (5/5)100% (1/1)
setCopy (String, Locale): Partial 100% (1/1)100% (22/22)100% (3/3)
setCopy (int): Partial 100% (1/1)100% (21/21)100% (3/3)
withMaximumValue (): Partial 100% (1/1)100% (5/5)100% (1/1)
withMinimumValue (): Partial 100% (1/1)100% (5/5)100% (1/1)

1/*
2 *  Copyright 2001-2006 Stephen Colebourne
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16package org.joda.time;
17 
18import java.io.Serializable;
19import java.util.ArrayList;
20import java.util.Arrays;
21import java.util.List;
22import java.util.Locale;
23 
24import org.joda.time.base.AbstractPartial;
25import org.joda.time.field.AbstractPartialFieldProperty;
26import org.joda.time.field.FieldUtils;
27import org.joda.time.format.DateTimeFormat;
28import org.joda.time.format.DateTimeFormatter;
29import org.joda.time.format.ISODateTimeFormat;
30 
31/**
32 * Partial is an immutable partial datetime supporting any set of datetime fields.
33 * <p>
34 * A Partial instance can be used to hold any combination of fields.
35 * The instance does not contain a time zone, so any datetime is local.
36 * <p>
37 * A Partial can be matched against an instant using {@link #isMatch(ReadableInstant)}.
38 * This method compares each field on this partial with those of the instant
39 * and determines if the partial matches the instant.
40 * Given this definition, an empty Partial instance represents any datetime
41 * and always matches.
42 * <p>
43 * Calculations on Partial are performed using a {@link Chronology}.
44 * This chronology is set to be in the UTC time zone for all calculations.
45 * <p>
46 * Each individual field can be queried in two ways:
47 * <ul>
48 * <li><code>get(DateTimeFieldType.monthOfYear())</code>
49 * <li><code>property(DateTimeFieldType.monthOfYear()).get()</code>
50 * </ul>
51 * The second technique also provides access to other useful methods on the
52 * field:
53 * <ul>
54 * <li>numeric value - <code>monthOfYear().get()</code>
55 * <li>text value - <code>monthOfYear().getAsText()</code>
56 * <li>short text value - <code>monthOfYear().getAsShortText()</code>
57 * <li>maximum/minimum values - <code>monthOfYear().getMaximumValue()</code>
58 * <li>add/subtract - <code>monthOfYear().addToCopy()</code>
59 * <li>set - <code>monthOfYear().setCopy()</code>
60 * </ul>
61 * <p>
62 * Partial is thread-safe and immutable, provided that the Chronology is as well.
63 * All standard Chronology classes supplied are thread-safe and immutable.
64 *
65 * @author Stephen Colebourne
66 * @since 1.1
67 */
68public final class Partial
69        extends AbstractPartial
70        implements ReadablePartial, Serializable {
71 
72    /** Serialization version */
73    private static final long serialVersionUID = 12324121189002L;
74 
75    /** The chronology in use. */
76    private final Chronology iChronology;
77    /** The set of field types. */
78    private final DateTimeFieldType[] iTypes;
79    /** The values of each field in this partial. */
80    private final int[] iValues;
81    /** The formatter to use, [0] may miss some fields, [1] doesn't miss any fields. */
82    private transient DateTimeFormatter[] iFormatter;
83 
84    // Constructors
85    //-----------------------------------------------------------------------
86    /**
87     * Constructs a Partial with no fields or values, which can be considered
88     * to represent any date.
89     * <p>
90     * This is most useful when constructing partials, for example:
91     * <pre>
92     * Partial p = new Partial()
93     *     .with(DateTimeFieldType.dayOfWeek(), 5)
94     *     .with(DateTimeFieldType.hourOfDay(), 12)
95     *     .with(DateTimeFieldType.minuteOfHour(), 20);
96     * </pre>
97     * Note that, although this is a clean way to write code, it is fairly
98     * inefficient internally.
99     * <p>
100     * The constructor uses the default ISO chronology.
101     */
102    public Partial() {
103        this((Chronology) null);
104    }
105 
106    /**
107     * Constructs a Partial with no fields or values, which can be considered
108     * to represent any date.
109     * <p>
110     * This is most useful when constructing partials, for example:
111     * <pre>
112     * Partial p = new Partial(chrono)
113     *     .with(DateTimeFieldType.dayOfWeek(), 5)
114     *     .with(DateTimeFieldType.hourOfDay(), 12)
115     *     .with(DateTimeFieldType.minuteOfHour(), 20);
116     * </pre>
117     * Note that, although this is a clean way to write code, it is fairly
118     * inefficient internally.
119     *
120     * @param chrono  the chronology, null means ISO
121     */
122    public Partial(Chronology chrono) {
123        super();
124        iChronology = DateTimeUtils.getChronology(chrono).withUTC();
125        iTypes = new DateTimeFieldType[0];
126        iValues = new int[0];
127    }
128 
129    /**
130     * Constructs a Partial with the specified field and value.
131     * <p>
132     * The constructor uses the default ISO chronology.
133     * 
134     * @param type  the single type to create the partial from, not null
135     * @param value  the value to store
136     * @throws IllegalArgumentException if the type or value is invalid
137     */
138    public Partial(DateTimeFieldType type, int value) {
139        this(type, value, null);
140    }
141 
142    /**
143     * Constructs a Partial with the specified field and value.
144     * <p>
145     * The constructor uses the specified chronology.
146     * 
147     * @param type  the single type to create the partial from, not null
148     * @param value  the value to store
149     * @param chronology  the chronology, null means ISO
150     * @throws IllegalArgumentException if the type or value is invalid
151     */
152    public Partial(DateTimeFieldType type, int value, Chronology chronology) {
153        super();
154        chronology = DateTimeUtils.getChronology(chronology).withUTC();
155        iChronology = chronology;
156        if (type == null) {
157            throw new IllegalArgumentException("The field type must not be null");
158        }
159        iTypes = new DateTimeFieldType[] {type};
160        iValues = new int[] {value};
161        chronology.validate(this, iValues);
162    }
163 
164    /**
165     * Constructs a Partial with the specified fields and values.
166     * The fields must be specified in the order largest to smallest.
167     * <p>
168     * The constructor uses the specified chronology.
169     * 
170     * @param types  the types to create the partial from, not null
171     * @param values  the values to store, not null
172     * @throws IllegalArgumentException if the types or values are invalid
173     */
174    public Partial(DateTimeFieldType[] types, int[] values) {
175        this(types, values, null);
176    }
177 
178    /**
179     * Constructs a Partial with the specified fields and values.
180     * The fields must be specified in the order largest to smallest.
181     * <p>
182     * The constructor uses the specified chronology.
183     * 
184     * @param types  the types to create the partial from, not null
185     * @param values  the values to store, not null
186     * @param chronology  the chronology, null means ISO
187     * @throws IllegalArgumentException if the types or values are invalid
188     */
189    public Partial(DateTimeFieldType[] types, int[] values, Chronology chronology) {
190        super();
191        chronology = DateTimeUtils.getChronology(chronology).withUTC();
192        iChronology = chronology;
193        if (types == null) {
194            throw new IllegalArgumentException("Types array must not be null");
195        }
196        if (values == null) {
197            throw new IllegalArgumentException("Values array must not be null");
198        }
199        if (values.length != types.length) {
200            throw new IllegalArgumentException("Values array must be the same length as the types array");
201        }
202        if (types.length == 0) {
203            iTypes = types;
204            iValues = values;
205            return;
206        }
207        for (int i = 0; i < types.length; i++) {
208            if (types[i] == null) {
209                throw new IllegalArgumentException("Types array must not contain null: index " + i);
210            }
211        }
212        DurationField lastUnitField = null;
213        for (int i = 0; i < types.length; i++) {
214            DateTimeFieldType loopType = types[i];
215            DurationField loopUnitField = loopType.getDurationType().getField(iChronology);
216            if (i > 0) {
217                int compare = lastUnitField.compareTo(loopUnitField);
218                if (compare < 0 || (compare != 0 && loopUnitField.isSupported() == false)) {
219                    throw new IllegalArgumentException("Types array must be in order largest-smallest: " +
220                            types[i - 1].getName() + " < " + loopType.getName());
221                } else if (compare == 0) {
222                    if (types[i - 1].getRangeDurationType() == null) {
223                        if (loopType.getRangeDurationType() == null) {
224                            throw new IllegalArgumentException("Types array must not contain duplicate: " + loopType.getName());
225                        }
226                    } else {
227                        if (loopType.getRangeDurationType() == null) {
228                            throw new IllegalArgumentException("Types array must be in order largest-smallest: " +
229                                    types[i - 1].getName() + " < " + loopType.getName());
230                        }
231                        DurationField lastRangeField = types[i - 1].getRangeDurationType().getField(iChronology);
232                        DurationField loopRangeField = loopType.getRangeDurationType().getField(iChronology);
233                        if (lastRangeField.compareTo(loopRangeField) < 0) {
234                            throw new IllegalArgumentException("Types array must be in order largest-smallest: " +
235                                    types[i - 1].getName() + " < " + loopType.getName());
236                        }
237                        if (lastRangeField.compareTo(loopRangeField) == 0) {
238                            throw new IllegalArgumentException("Types array must not contain duplicate: " + loopType.getName());
239                        }
240                    }
241                }
242            }
243            lastUnitField = loopUnitField;
244        }
245        
246        iTypes = (DateTimeFieldType[]) types.clone();
247        chronology.validate(this, values);
248        iValues = (int[]) values.clone();
249    }
250 
251    /**
252     * Constructs a Partial by copying all the fields and types from
253     * another partial.
254     * <p>
255     * This is most useful when copying from a YearMonthDay or TimeOfDay.
256     */
257    public Partial(ReadablePartial partial) {
258        super();
259        if (partial == null) {
260            throw new IllegalArgumentException("The partial must not be null");
261        }
262        iChronology = DateTimeUtils.getChronology(partial.getChronology()).withUTC();
263        iTypes = new DateTimeFieldType[partial.size()];
264        iValues = new int[partial.size()];
265        for (int i = 0; i < partial.size(); i++) {
266            iTypes[i] = partial.getFieldType(i);
267            iValues[i] = partial.getValue(i);
268        }
269    }
270 
271    /**
272     * Constructs a Partial with the specified values.
273     * This constructor assigns and performs no validation.
274     * 
275     * @param partial  the partial to copy
276     * @param values  the values to store
277     * @throws IllegalArgumentException if the types or values are invalid
278     */
279    Partial(Partial partial, int[] values) {
280        super();
281        iChronology = partial.iChronology;
282        iTypes = partial.iTypes;
283        iValues = values;
284    }
285 
286    /**
287     * Constructs a Partial with the specified chronology, fields and values.
288     * This constructor assigns and performs no validation.
289     * 
290     * @param chronology  the chronology
291     * @param types  the types to create the partial from
292     * @param values  the values to store
293     * @throws IllegalArgumentException if the types or values are invalid
294     */
295    Partial(Chronology chronology, DateTimeFieldType[] types, int[] values) {
296        super();
297        iChronology = chronology;
298        iTypes = types;
299        iValues = values;
300    }
301 
302    //-----------------------------------------------------------------------
303    /**
304     * Gets the number of fields in this partial.
305     * 
306     * @return the field count
307     */
308    public int size() {
309        return iTypes.length;
310    }
311 
312    /**
313     * Gets the chronology of the partial which is never null.
314     * <p>
315     * The {@link Chronology} is the calculation engine behind the partial and
316     * provides conversion and validation of the fields in a particular calendar system.
317     * 
318     * @return the chronology, never null
319     */
320    public Chronology getChronology() {
321        return iChronology;
322    }
323 
324    /**
325     * Gets the field for a specific index in the chronology specified.
326     * 
327     * @param index  the index to retrieve
328     * @param chrono  the chronology to use
329     * @return the field
330     * @throws IndexOutOfBoundsException if the index is invalid
331     */
332    protected DateTimeField getField(int index, Chronology chrono) {
333        return iTypes[index].getField(chrono);
334    }
335 
336    /**
337     * Gets the field type at the specified index.
338     *
339     * @param index  the index to retrieve
340     * @return the field at the specified index
341     * @throws IndexOutOfBoundsException if the index is invalid
342     */
343    public DateTimeFieldType getFieldType(int index) {
344        return iTypes[index];
345    }
346 
347    /**
348     * Gets an array of the field type of each of the fields that
349     * this partial supports.
350     * <p>
351     * The fields are returned largest to smallest.
352     *
353     * @return the array of field types (cloned), largest to smallest
354     */
355    public DateTimeFieldType[] getFieldTypes() {
356        return (DateTimeFieldType[]) iTypes.clone();
357    }
358 
359    //-----------------------------------------------------------------------
360    /**
361     * Gets the value of the field at the specifed index.
362     * 
363     * @param index  the index
364     * @return the value
365     * @throws IndexOutOfBoundsException if the index is invalid
366     */
367    public int getValue(int index) {
368        return iValues[index];
369    }
370 
371    /**
372     * Gets an array of the value of each of the fields that
373     * this partial supports.
374     * <p>
375     * The fields are returned largest to smallest.
376     * Each value corresponds to the same array index as <code>getFieldTypes()</code>
377     *
378     * @return the current values of each field (cloned), largest to smallest
379     */
380    public int[] getValues() {
381        return (int[]) iValues.clone();
382    }
383 
384    //-----------------------------------------------------------------------
385    /**
386     * Creates a new Partial instance with the specified chronology.
387     * This instance is immutable and unaffected by this method call.
388     * <p>
389     * This method retains the values of the fields, thus the result will
390     * typically refer to a different instant.
391     * <p>
392     * The time zone of the specified chronology is ignored, as Partial
393     * operates without a time zone.
394     *
395     * @param newChronology  the new chronology, null means ISO
396     * @return a copy of this datetime with a different chronology
397     * @throws IllegalArgumentException if the values are invalid for the new chronology
398     */
399    public Partial withChronologyRetainFields(Chronology newChronology) {
400        newChronology = DateTimeUtils.getChronology(newChronology);
401        newChronology = newChronology.withUTC();
402        if (newChronology == getChronology()) {
403            return this;
404        } else {
405            Partial newPartial = new Partial(newChronology, iTypes, iValues);
406            newChronology.validate(newPartial, iValues);
407            return newPartial;
408        }
409    }
410 
411    //-----------------------------------------------------------------------
412    /**
413     * Gets a copy of this date with the specified field set to a new value.
414     * <p>
415     * If this partial did not previously support the field, the new one will.
416     * Contrast this behaviour with {@link #withField(DateTimeFieldType, int)}.
417     * <p>
418     * For example, if the field type is <code>dayOfMonth</code> then the day
419     * would be changed/added in the returned instance.
420     *
421     * @param fieldType  the field type to set, not null
422     * @param value  the value to set
423     * @return a copy of this instance with the field set
424     * @throws IllegalArgumentException if the value is null or invalid
425     */
426    public Partial with(DateTimeFieldType fieldType, int value) {
427        if (fieldType == null) {
428            throw new IllegalArgumentException("The field type must not be null");
429        }
430        int index = indexOf(fieldType);
431        if (index == -1) {
432            DateTimeFieldType[] newTypes = new DateTimeFieldType[iTypes.length + 1];
433            int[] newValues = new int[newTypes.length];
434            
435            // find correct insertion point to keep largest-smallest order
436            int i = 0;
437            DurationField unitField = fieldType.getDurationType().getField(iChronology);
438            if (unitField.isSupported()) {
439                for (; i < iTypes.length; i++) {
440                    DateTimeFieldType loopType = iTypes[i];
441                    DurationField loopUnitField = loopType.getDurationType().getField(iChronology);
442                    if (loopUnitField.isSupported()) {
443                        int compare = unitField.compareTo(loopUnitField);
444                        if (compare > 0) {
445                            break;
446                        } else if (compare == 0) {
447                            DurationField rangeField = fieldType.getRangeDurationType().getField(iChronology);
448                            DurationField loopRangeField = loopType.getRangeDurationType().getField(iChronology);
449                            if (rangeField.compareTo(loopRangeField) > 0) {
450                                break;
451                            }
452                        }
453                    }
454                }
455            }
456            System.arraycopy(iTypes, 0, newTypes, 0, i);
457            System.arraycopy(iValues, 0, newValues, 0, i);
458            newTypes[i] = fieldType;
459            newValues[i] = value;
460            System.arraycopy(iTypes, i, newTypes, i + 1, newTypes.length - i - 1);
461            System.arraycopy(iValues, i, newValues, i + 1, newValues.length - i - 1);
462            
463            Partial newPartial = new Partial(iChronology, newTypes, newValues);
464            iChronology.validate(newPartial, newValues);
465            return newPartial;
466        }
467        if (value == getValue(index)) {
468            return this;
469        }
470        int[] newValues = getValues();
471        newValues = getField(index).set(this, index, newValues, value);
472        return new Partial(this, newValues);
473    }
474 
475    /**
476     * Gets a copy of this date with the specified field removed.
477     * <p>
478     * If this partial did not previously support the field, no error occurs.
479     *
480     * @param fieldType  the field type to remove, may be null
481     * @return a copy of this instance with the field removed
482     */
483    public Partial without(DateTimeFieldType fieldType) {
484        int index = indexOf(fieldType);
485        if (index != -1) {
486            DateTimeFieldType[] newTypes = new DateTimeFieldType[size() - 1];
487            int[] newValues = new int[size() - 1];
488            System.arraycopy(iTypes, 0, newTypes, 0, index);
489            System.arraycopy(iTypes, index + 1, newTypes, index, newTypes.length - index);
490            System.arraycopy(iValues, 0, newValues, 0, index);
491            System.arraycopy(iValues, index + 1, newValues, index, newValues.length - index);
492            Partial newPartial = new Partial(iChronology, newTypes, newValues);
493            iChronology.validate(newPartial, newValues);
494            return newPartial;
495        }
496        return this;
497    }
498 
499    //-----------------------------------------------------------------------
500    /**
501     * Gets a copy of this Partial with the specified field set to a new value.
502     * <p>
503     * If this partial does not support the field, an exception is thrown.
504     * Contrast this behaviour with {@link #with(DateTimeFieldType, int)}.
505     * <p>
506     * For example, if the field type is <code>dayOfMonth</code> then the day
507     * would be changed in the returned instance if supported.
508     *
509     * @param fieldType  the field type to set, not null
510     * @param value  the value to set
511     * @return a copy of this instance with the field set
512     * @throws IllegalArgumentException if the value is null or invalid
513     */
514    public Partial withField(DateTimeFieldType fieldType, int value) {
515        int index = indexOfSupported(fieldType);
516        if (value == getValue(index)) {
517            return this;
518        }
519        int[] newValues = getValues();
520        newValues = getField(index).set(this, index, newValues, value);
521        return new Partial(this, newValues);
522    }
523 
524    /**
525     * Gets a copy of this Partial with the value of the specified field increased.
526     * If this partial does not support the field, an exception is thrown.
527     * <p>
528     * If the addition is zero, then <code>this</code> is returned.
529     * The addition will overflow into larger fields (eg. minute to hour).
530     * However, it will not wrap around if the top maximum is reached.
531     *
532     * @param fieldType  the field type to add to, not null
533     * @param amount  the amount to add
534     * @return a copy of this instance with the field updated
535     * @throws IllegalArgumentException if the value is null or invalid
536     * @throws ArithmeticException if the new datetime exceeds the capacity
537     */
538    public Partial withFieldAdded(DurationFieldType fieldType, int amount) {
539        int index = indexOfSupported(fieldType);
540        if (amount == 0) {
541            return this;
542        }
543        int[] newValues = getValues();
544        newValues = getField(index).add(this, index, newValues, amount);
545        return new Partial(this, newValues);
546    }
547 
548    /**
549     * Gets a copy of this Partial with the value of the specified field increased.
550     * If this partial does not support the field, an exception is thrown.
551     * <p>
552     * If the addition is zero, then <code>this</code> is returned.
553     * The addition will overflow into larger fields (eg. minute to hour).
554     * If the maximum is reached, the addition will wra.
555     *
556     * @param fieldType  the field type to add to, not null
557     * @param amount  the amount to add
558     * @return a copy of this instance with the field updated
559     * @throws IllegalArgumentException if the value is null or invalid
560     * @throws ArithmeticException if the new datetime exceeds the capacity
561     */
562    public Partial withFieldAddWrapped(DurationFieldType fieldType, int amount) {
563        int index = indexOfSupported(fieldType);
564        if (amount == 0) {
565            return this;
566        }
567        int[] newValues = getValues();
568        newValues = getField(index).addWrapPartial(this, index, newValues, amount);
569        return new Partial(this, newValues);
570    }
571 
572    /**
573     * Gets a copy of this Partial with the specified period added.
574     * <p>
575     * If the addition is zero, then <code>this</code> is returned.
576     * Fields in the period that aren't present in the partial are ignored.
577     * <p>
578     * This method is typically used to add multiple copies of complex
579     * period instances. Adding one field is best achieved using the method
580     * {@link #withFieldAdded(DurationFieldType, int)}.
581     * 
582     * @param period  the period to add to this one, null means zero
583     * @param scalar  the amount of times to add, such as -1 to subtract once
584     * @return a copy of this instance with the period added
585     * @throws ArithmeticException if the new datetime exceeds the capacity
586     */
587    public Partial withPeriodAdded(ReadablePeriod period, int scalar) {
588        if (period == null || scalar == 0) {
589            return this;
590        }
591        int[] newValues = getValues();
592        for (int i = 0; i < period.size(); i++) {
593            DurationFieldType fieldType = period.getFieldType(i);
594            int index = indexOf(fieldType);
595            if (index >= 0) {
596                newValues = getField(index).add(this, index, newValues,
597                        FieldUtils.safeMultiply(period.getValue(i), scalar));
598            }
599        }
600        return new Partial(this, newValues);
601    }
602 
603    /**
604     * Gets a copy of this instance with the specified period added.
605     * <p>
606     * If the amount is zero or null, then <code>this</code> is returned.
607     *
608     * @param period  the duration to add to this one, null means zero
609     * @return a copy of this instance with the period added
610     * @throws ArithmeticException if the new datetime exceeds the capacity of a long
611     */
612    public Partial plus(ReadablePeriod period) {
613        return withPeriodAdded(period, 1);
614    }
615 
616    /**
617     * Gets a copy of this instance with the specified period take away.
618     * <p>
619     * If the amount is zero or null, then <code>this</code> is returned.
620     *
621     * @param period  the period to reduce this instant by
622     * @return a copy of this instance with the period taken away
623     * @throws ArithmeticException if the new datetime exceeds the capacity of a long
624     */
625    public Partial minus(ReadablePeriod period) {
626        return withPeriodAdded(period, -1);
627    }
628 
629    //-----------------------------------------------------------------------
630    /**
631     * Gets the property object for the specified type, which contains
632     * many useful methods for getting and manipulating the partial.
633     * <p>
634     * See also {@link ReadablePartial#get(DateTimeFieldType)}.
635     *
636     * @param type  the field type to get the property for, not null
637     * @return the property object
638     * @throws IllegalArgumentException if the field is null or unsupported
639     */
640    public Property property(DateTimeFieldType type) {
641        return new Property(this, indexOfSupported(type));
642    }
643 
644    //-----------------------------------------------------------------------
645    /**
646     * Does this partial match the specified instant.
647     * <p>
648     * A match occurs when all the fields of this partial are the same as the
649     * corresponding fields on the specified instant.
650     *
651     * @param instant  an instant to check against, null means now in default zone
652     * @return true if this partial matches the specified instant
653     */
654    public boolean isMatch(ReadableInstant instant) {
655        long millis = DateTimeUtils.getInstantMillis(instant);
656        Chronology chrono = DateTimeUtils.getInstantChronology(instant);
657        for (int i = 0; i < iTypes.length; i++) {
658            int value = iTypes[i].getField(chrono).get(millis);
659            if (value != iValues[i]) {
660                return false;
661            }
662        }
663        return true;
664    }
665 
666    /**
667     * Does this partial match the specified partial.
668     * <p>
669     * A match occurs when all the fields of this partial are the same as the
670     * corresponding fields on the specified partial.
671     *
672     * @param partial  a partial to check against, must not be null
673     * @return true if this partial matches the specified partial
674     * @throws IllegalArgumentException if the partial is null
675     * @throws IllegalArgumentException if the fields of the two partials do not match
676     * @since 1.5
677     */
678    public boolean isMatch(ReadablePartial partial) {
679        if (partial == null) {
680            throw new IllegalArgumentException("The partial must not be null");
681        }
682        for (int i = 0; i < iTypes.length; i++) {
683            int value = partial.get(iTypes[i]);
684            if (value != iValues[i]) {
685                return false;
686            }
687        }
688        return true;
689    }
690 
691    //-----------------------------------------------------------------------
692    /**
693     * Gets a formatter suitable for the fields in this partial.
694     * <p>
695     * If there is no appropriate ISO format, null is returned.
696     * This method may return a formatter that does not display all the
697     * fields of the partial. This might occur when you have overlapping
698     * fields, such as dayOfWeek and dayOfMonth.
699     *
700     * @return a formatter suitable for the fields in this partial, null
701     *  if none is suitable
702     */
703    public DateTimeFormatter getFormatter() {
704        DateTimeFormatter[] f = iFormatter;
705        if (f == null) {
706            if (size() == 0) {
707                return null;
708            }
709            f = new DateTimeFormatter[2];
710            try {
711                List list = new ArrayList(Arrays.asList(iTypes));
712                f[0] = ISODateTimeFormat.forFields(list, true, false);
713                if (list.size() == 0) {
714                    f[1] = f[0];
715                }
716            } catch (IllegalArgumentException ex) {
717                // ignore
718            }
719            iFormatter = f;
720        }
721        return f[0];
722    }
723 
724    //-----------------------------------------------------------------------
725    /**
726     * Output the date in an appropriate ISO8601 format.
727     * <p>
728     * This method will output the partial in one of two ways.
729     * If {@link #getFormatter()}
730     * <p>
731     * If there is no appropriate ISO format a dump of the fields is output
732     * via {@link #toStringList()}.
733     * 
734     * @return ISO8601 formatted string
735     */
736    public String toString() {
737        DateTimeFormatter[] f = iFormatter;
738        if (f == null) {
739            getFormatter();
740            f = iFormatter;
741            if (f == null) {
742                return toStringList();
743            }
744        }
745        DateTimeFormatter f1 = f[1];
746        if (f1 == null) {
747            return toStringList();
748        }
749        return f1.print(this);
750    }
751 
752    /**
753     * Gets a string version of the partial that lists all the fields.
754     * <p>
755     * This method exists to provide a better debugging toString than
756     * the standard toString. This method lists all the fields and their
757     * values in a style similar to the collections framework.
758     *
759     * @return a toString format that lists all the fields
760     */
761    public String toStringList() {
762        int size = size();
763        StringBuffer buf = new StringBuffer(20 * size);
764        buf.append('[');
765        for (int i = 0; i < size; i++) {
766            if (i > 0) {
767                buf.append(',').append(' ');
768            }
769            buf.append(iTypes[i].getName());
770            buf.append('=');
771            buf.append(iValues[i]);
772        }
773        buf.append(']');
774        return buf.toString();
775    }
776 
777    /**
778     * Output the date using the specified format pattern.
779     * Unsupported fields will appear as special unicode characters.
780     *
781     * @param pattern  the pattern specification, null means use <code>toString</code>
782     * @see org.joda.time.format.DateTimeFormat
783     */
784    public String toString(String pattern) {
785        if (pattern == null) {
786            return toString();
787        }
788        return DateTimeFormat.forPattern(pattern).print(this);
789    }
790 
791    /**
792     * Output the date using the specified format pattern.
793     * Unsupported fields will appear as special unicode characters.
794     *
795     * @param pattern  the pattern specification, null means use <code>toString</code>
796     * @param locale  Locale to use, null means default
797     * @see org.joda.time.format.DateTimeFormat
798     */
799    public String toString(String pattern, Locale locale) {
800        if (pattern == null) {
801            return toString();
802        }
803        return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this);
804    }
805 
806    //-----------------------------------------------------------------------
807    /**
808     * The property class for <code>Partial</code>.
809     * <p>
810     * This class binds a <code>Partial</code> to a <code>DateTimeField</code>.
811     * 
812     * @author Stephen Colebourne
813     * @since 1.1
814     */
815    public static class Property extends AbstractPartialFieldProperty implements Serializable {
816 
817        /** Serialization version */
818        private static final long serialVersionUID = 53278362873888L;
819 
820        /** The partial */
821        private final Partial iPartial;
822        /** The field index */
823        private final int iFieldIndex;
824 
825        /**
826         * Constructs a property.
827         * 
828         * @param partial  the partial instance
829         * @param fieldIndex  the index in the partial
830         */
831        Property(Partial partial, int fieldIndex) {
832            super();
833            iPartial = partial;
834            iFieldIndex = fieldIndex;
835        }
836 
837        /**
838         * Gets the field that this property uses.
839         * 
840         * @return the field
841         */
842        public DateTimeField getField() {
843            return iPartial.getField(iFieldIndex);
844        }
845 
846        /**
847         * Gets the partial that this property belongs to.
848         * 
849         * @return the partial
850         */
851        protected ReadablePartial getReadablePartial() {
852            return iPartial;
853        }
854 
855        /**
856         * Gets the partial that this property belongs to.
857         * 
858         * @return the partial
859         */
860        public Partial getPartial() {
861            return iPartial;
862        }
863 
864        /**
865         * Gets the value of this field.
866         * 
867         * @return the field value
868         */
869        public int get() {
870            return iPartial.getValue(iFieldIndex);
871        }
872 
873        //-----------------------------------------------------------------------
874        /**
875         * Adds to the value of this field in a copy of this Partial.
876         * <p>
877         * The value will be added to this field. If the value is too large to be
878         * added solely to this field then it will affect larger fields.
879         * Smaller fields are unaffected.
880         * <p>
881         * If the result would be too large, beyond the maximum year, then an
882         * IllegalArgumentException is thrown.
883         * <p>
884         * The Partial attached to this property is unchanged by this call.
885         * Instead, a new instance is returned.
886         * 
887         * @param valueToAdd  the value to add to the field in the copy
888         * @return a copy of the Partial with the field value changed
889         * @throws IllegalArgumentException if the value isn't valid
890         */
891        public Partial addToCopy(int valueToAdd) {
892            int[] newValues = iPartial.getValues();
893            newValues = getField().add(iPartial, iFieldIndex, newValues, valueToAdd);
894            return new Partial(iPartial, newValues);
895        }
896 
897        /**
898         * Adds to the value of this field in a copy of this Partial wrapping
899         * within this field if the maximum value is reached.
900         * <p>
901         * The value will be added to this field. If the value is too large to be
902         * added solely to this field then it wraps within this field.
903         * Other fields are unaffected.
904         * <p>
905         * For example,
906         * <code>2004-12-20</code> addWrapField one month returns <code>2004-01-20</code>.
907         * <p>
908         * The Partial attached to this property is unchanged by this call.
909         * Instead, a new instance is returned.
910         * 
911         * @param valueToAdd  the value to add to the field in the copy
912         * @return a copy of the Partial with the field value changed
913         * @throws IllegalArgumentException if the value isn't valid
914         */
915        public Partial addWrapFieldToCopy(int valueToAdd) {
916            int[] newValues = iPartial.getValues();
917            newValues = getField().addWrapField(iPartial, iFieldIndex, newValues, valueToAdd);
918            return new Partial(iPartial, newValues);
919        }
920 
921        //-----------------------------------------------------------------------
922        /**
923         * Sets this field in a copy of the Partial.
924         * <p>
925         * The Partial attached to this property is unchanged by this call.
926         * Instead, a new instance is returned.
927         * 
928         * @param value  the value to set the field in the copy to
929         * @return a copy of the Partial with the field value changed
930         * @throws IllegalArgumentException if the value isn't valid
931         */
932        public Partial setCopy(int value) {
933            int[] newValues = iPartial.getValues();
934            newValues = getField().set(iPartial, iFieldIndex, newValues, value);
935            return new Partial(iPartial, newValues);
936        }
937 
938        /**
939         * Sets this field in a copy of the Partial to a parsed text value.
940         * <p>
941         * The Partial attached to this property is unchanged by this call.
942         * Instead, a new instance is returned.
943         * 
944         * @param text  the text value to set
945         * @param locale  optional locale to use for selecting a text symbol
946         * @return a copy of the Partial with the field value changed
947         * @throws IllegalArgumentException if the text value isn't valid
948         */
949        public Partial setCopy(String text, Locale locale) {
950            int[] newValues = iPartial.getValues();
951            newValues = getField().set(iPartial, iFieldIndex, newValues, text, locale);
952            return new Partial(iPartial, newValues);
953        }
954 
955        /**
956         * Sets this field in a copy of the Partial to a parsed text value.
957         * <p>
958         * The Partial attached to this property is unchanged by this call.
959         * Instead, a new instance is returned.
960         * 
961         * @param text  the text value to set
962         * @return a copy of the Partial with the field value changed
963         * @throws IllegalArgumentException if the text value isn't valid
964         */
965        public Partial setCopy(String text) {
966            return setCopy(text, null);
967        }
968 
969        //-----------------------------------------------------------------------
970        /**
971         * Returns a new Partial with this field set to the maximum value
972         * for this field.
973         * <p>
974         * The Partial attached to this property is unchanged by this call.
975         *
976         * @return a copy of the Partial with this field set to its maximum
977         * @since 1.2
978         */
979        public Partial withMaximumValue() {
980            return setCopy(getMaximumValue());
981        }
982 
983        /**
984         * Returns a new Partial with this field set to the minimum value
985         * for this field.
986         * <p>
987         * The Partial attached to this property is unchanged by this call.
988         *
989         * @return a copy of the Partial with this field set to its minimum
990         * @since 1.2
991         */
992        public Partial withMinimumValue() {
993            return setCopy(getMinimumValue());
994        }
995    }
996 
997}

[all classes][org.joda.time]
EMMA 2.0.5312 (C) Vladimir Roubtsov