001/*
002 *  Copyright 2001-2010 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time;
017
018import java.io.Serializable;
019import java.util.Calendar;
020import java.util.Date;
021import java.util.Locale;
022
023import org.joda.convert.FromString;
024import org.joda.convert.ToString;
025import org.joda.time.base.BasePartial;
026import org.joda.time.chrono.ISOChronology;
027import org.joda.time.field.AbstractPartialFieldProperty;
028import org.joda.time.field.FieldUtils;
029import org.joda.time.format.DateTimeFormat;
030import org.joda.time.format.DateTimeFormatter;
031import org.joda.time.format.ISODateTimeFormat;
032
033/**
034 * YearMonth is an immutable partial supporting the year and monthOfYear fields.
035 * <p>
036 * NOTE: This class only supports the two fields listed above.
037 * It is impossible to query any other fields, such as dayOfWeek or centuryOfEra.
038 * <p>
039 * Calculations on YearMonth are performed using a {@link Chronology}.
040 * This chronology is set to be in the UTC time zone for all calculations.
041 * <p>
042 * One use case for this class is to store a credit card expiry date, as that only
043 * references the year and month.
044 * This class can be used as the gYearMonth type in XML Schema.
045 * <p>
046 * Each individual field can be queried in two ways:
047 * <ul>
048 * <li><code>getMonthOfYear()</code>
049 * <li><code>monthOfYear().get()</code>
050 * </ul>
051 * The second technique also provides access to other useful methods on the
052 * field:
053 * <ul>
054 * <li>numeric value - <code>monthOfYear().get()</code>
055 * <li>text value - <code>monthOfYear().getAsText()</code>
056 * <li>short text value - <code>monthOfYear().getAsShortText()</code>
057 * <li>maximum/minimum values - <code>monthOfYear().getMaximumValue()</code>
058 * <li>add/subtract - <code>monthOfYear().addToCopy()</code>
059 * <li>set - <code>monthOfYear().setCopy()</code>
060 * </ul>
061 * <p>
062 * YearMonth is thread-safe and immutable, provided that the Chronology is as well.
063 * All standard Chronology classes supplied are thread-safe and immutable.
064 *
065 * @author Stephen Colebourne
066 * @since 2.0
067 */
068public final class YearMonth
069        extends BasePartial
070        implements ReadablePartial, Serializable {
071
072    /** Serialization version */
073    private static final long serialVersionUID = 797544782896179L;
074    /** The singleton set of field types */
075    private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
076        DateTimeFieldType.year(),
077        DateTimeFieldType.monthOfYear(),
078    };
079
080    /** The index of the year field in the field array */
081    public static final int YEAR = 0;
082    /** The index of the monthOfYear field in the field array */
083    public static final int MONTH_OF_YEAR = 1;
084
085    //-----------------------------------------------------------------------
086    /**
087     * Obtains a {@code YearMonth} set to the current system millisecond time
088     * using <code>ISOChronology</code> in the default time zone.
089     * The resulting object does not use the zone.
090     * 
091     * @return the current year-month, not null
092     * @since 2.0
093     */
094    public static YearMonth now() {
095        return new YearMonth();
096    }
097
098    /**
099     * Obtains a {@code YearMonth} set to the current system millisecond time
100     * using <code>ISOChronology</code> in the specified time zone.
101     * The resulting object does not use the zone.
102     *
103     * @param zone  the time zone, not null
104     * @return the current year-month, not null
105     * @since 2.0
106     */
107    public static YearMonth now(DateTimeZone zone) {
108        if (zone == null) {
109            throw new NullPointerException("Zone must not be null");
110        }
111        return new YearMonth(zone);
112    }
113
114    /**
115     * Obtains a {@code YearMonth} set to the current system millisecond time
116     * using the specified chronology.
117     * The resulting object does not use the zone.
118     *
119     * @param chronology  the chronology, not null
120     * @return the current year-month, not null
121     * @since 2.0
122     */
123    public static YearMonth now(Chronology chronology) {
124        if (chronology == null) {
125            throw new NullPointerException("Chronology must not be null");
126        }
127        return new YearMonth(chronology);
128    }
129
130    //-----------------------------------------------------------------------
131    /**
132     * Parses a {@code YearMonth} from the specified string.
133     * <p>
134     * This uses {@link ISODateTimeFormat#localDateParser()}.
135     * 
136     * @param str  the string to parse, not null
137     * @since 2.0
138     */
139    @FromString
140    public static YearMonth parse(String str) {
141        return parse(str, ISODateTimeFormat.localDateParser());
142    }
143
144    /**
145     * Parses a {@code YearMonth} from the specified string using a formatter.
146     * 
147     * @param str  the string to parse, not null
148     * @param formatter  the formatter to use, not null
149     * @since 2.0
150     */
151    public static YearMonth parse(String str, DateTimeFormatter formatter) {
152        LocalDate date = formatter.parseLocalDate(str);
153        return new YearMonth(date.getYear(), date.getMonthOfYear());
154    }
155
156    //-----------------------------------------------------------------------
157    /**
158     * Constructs a YearMonth from a <code>java.util.Calendar</code>
159     * using exactly the same field values avoiding any time zone effects.
160     * <p>
161     * Each field is queried from the Calendar and assigned to the YearMonth.
162     * <p>
163     * This factory method ignores the type of the calendar and always
164     * creates a YearMonth with ISO chronology. It is expected that you
165     * will only pass in instances of <code>GregorianCalendar</code> however
166     * this is not validated.
167     *
168     * @param calendar  the Calendar to extract fields from
169     * @return the created YearMonth, never null
170     * @throws IllegalArgumentException if the calendar is null
171     * @throws IllegalArgumentException if the year or month is invalid for the ISO chronology
172     */
173    public static YearMonth fromCalendarFields(Calendar calendar) {
174        if (calendar == null) {
175            throw new IllegalArgumentException("The calendar must not be null");
176        }
177        return new YearMonth(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1);
178    }
179
180    /**
181     * Constructs a YearMonth from a <code>java.util.Date</code>
182     * using exactly the same field values avoiding any time zone effects.
183     * <p>
184     * Each field is queried from the Date and assigned to the YearMonth.
185     * <p>
186     * This factory method always creates a YearMonth with ISO chronology.
187     *
188     * @param date  the Date to extract fields from
189     * @return the created YearMonth, never null
190     * @throws IllegalArgumentException if the calendar is null
191     * @throws IllegalArgumentException if the year or month is invalid for the ISO chronology
192     */
193    @SuppressWarnings("deprecation")
194    public static YearMonth fromDateFields(Date date) {
195        if (date == null) {
196            throw new IllegalArgumentException("The date must not be null");
197        }
198        return new YearMonth(date.getYear() + 1900, date.getMonth() + 1);
199    }
200
201    //-----------------------------------------------------------------------
202    /**
203     * Constructs a YearMonth with the current year-month, using ISOChronology in
204     * the default zone to extract the fields.
205     * <p>
206     * The constructor uses the default time zone, resulting in the local time
207     * being initialised. Once the constructor is complete, all further calculations
208     * are performed without reference to a time-zone (by switching to UTC).
209     * 
210     * @see #now()
211     */
212    public YearMonth() {
213        super();
214    }
215
216    /**
217     * Constructs a YearMonth with the current year-month, using ISOChronology in
218     * the specified zone to extract the fields.
219     * <p>
220     * The constructor uses the specified time zone to obtain the current year-month.
221     * Once the constructor is complete, all further calculations
222     * are performed without reference to a time-zone (by switching to UTC).
223     * 
224     * @param zone  the zone to use, null means default zone
225     * @see #now(DateTimeZone)
226     */
227    public YearMonth(DateTimeZone zone) {
228        super(ISOChronology.getInstance(zone));
229    }
230
231    /**
232     * Constructs a YearMonth with the current year-month, using the specified chronology
233     * and zone to extract the fields.
234     * <p>
235     * The constructor uses the time zone of the chronology specified.
236     * Once the constructor is complete, all further calculations are performed
237     * without reference to a time-zone (by switching to UTC).
238     *
239     * @param chronology  the chronology, null means ISOChronology in the default zone
240     * @see #now(Chronology)
241     */
242    public YearMonth(Chronology chronology) {
243        super(chronology);
244    }
245
246    /**
247     * Constructs a YearMonth extracting the partial fields from the specified
248     * milliseconds using the ISOChronology in the default zone.
249     * <p>
250     * The constructor uses the default time zone, resulting in the local time
251     * being initialised. Once the constructor is complete, all further calculations
252     * are performed without reference to a time-zone (by switching to UTC).
253     *
254     * @param instant  the milliseconds from 1970-01-01T00:00:00Z
255     */
256    public YearMonth(long instant) {
257        super(instant);
258    }
259
260    /**
261     * Constructs a YearMonth extracting the partial fields from the specified
262     * milliseconds using the chronology provided.
263     * <p>
264     * The constructor uses the time zone of the chronology specified.
265     * Once the constructor is complete, all further calculations are performed
266     * without reference to a time-zone (by switching to UTC).
267     *
268     * @param instant  the milliseconds from 1970-01-01T00:00:00Z
269     * @param chronology  the chronology, null means ISOChronology in the default zone
270     */
271    public YearMonth(long instant, Chronology chronology) {
272        super(instant, chronology);
273    }
274
275    /**
276     * Constructs a YearMonth from an Object that represents some form of time.
277     * <p>
278     * The recognised object types are defined in
279     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
280     * include ReadableInstant, String, Calendar and Date.
281     * The String formats are described by {@link ISODateTimeFormat#localDateParser()}.
282     * <p>
283     * The chronology used will be derived from the object, defaulting to ISO.
284     *
285     * @param instant  the date-time object, null means now
286     * @throws IllegalArgumentException if the instant is invalid
287     */
288    public YearMonth(Object instant) {
289        super(instant, null, ISODateTimeFormat.localDateParser());
290    }
291
292    /**
293     * Constructs a YearMonth from an Object that represents some form of time,
294     * using the specified chronology.
295     * <p>
296     * The recognised object types are defined in
297     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
298     * include ReadableInstant, String, Calendar and Date.
299     * The String formats are described by {@link ISODateTimeFormat#localDateParser()}.
300     * <p>
301     * The constructor uses the time zone of the chronology specified.
302     * Once the constructor is complete, all further calculations are performed
303     * without reference to a time-zone (by switching to UTC).
304     * The specified chronology overrides that of the object.
305     *
306     * @param instant  the date-time object, null means now
307     * @param chronology  the chronology, null means ISO default
308     * @throws IllegalArgumentException if the instant is invalid
309     */
310    public YearMonth(Object instant, Chronology chronology) {
311        super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.localDateParser());
312    }
313
314    /**
315     * Constructs a YearMonth with specified year and month
316     * using <code>ISOChronology</code>.
317     * <p>
318     * The constructor uses the no time zone initialising the fields as provided.
319     * Once the constructor is complete, all further calculations
320     * are performed without reference to a time-zone (by switching to UTC).
321     *
322     * @param year  the year
323     * @param monthOfYear  the month of the year
324     */
325    public YearMonth(int year, int monthOfYear) {
326        this(year, monthOfYear, null);
327    }
328
329    /**
330     * Constructs an instance set to the specified year and month
331     * using the specified chronology, whose zone is ignored.
332     * <p>
333     * If the chronology is null, <code>ISOChronology</code> is used.
334     * <p>
335     * The constructor uses the time zone of the chronology specified.
336     * Once the constructor is complete, all further calculations are performed
337     * without reference to a time-zone (by switching to UTC).
338     *
339     * @param year  the year
340     * @param monthOfYear  the month of the year
341     * @param chronology  the chronology, null means ISOChronology in the default zone
342     */
343    public YearMonth(int year, int monthOfYear, Chronology chronology) {
344        super(new int[] {year, monthOfYear}, chronology);
345    }
346
347    /**
348     * Constructs a YearMonth with chronology from this instance and new values.
349     *
350     * @param partial  the partial to base this new instance on
351     * @param values  the new set of values
352     */
353    YearMonth(YearMonth partial, int[] values) {
354        super(partial, values);
355    }
356
357    /**
358     * Constructs a YearMonth with values from this instance and a new chronology.
359     *
360     * @param partial  the partial to base this new instance on
361     * @param chrono  the new chronology
362     */
363    YearMonth(YearMonth partial, Chronology chrono) {
364        super(partial, chrono);
365    }
366
367    /**
368     * Handle broken serialization from other tools.
369     * @return the resolved object, not null
370     */
371    private Object readResolve() {
372        if (DateTimeZone.UTC.equals(getChronology().getZone()) == false) {
373            return new YearMonth(this, getChronology().withUTC());
374        }
375        return this;
376    }
377
378    //-----------------------------------------------------------------------
379    /**
380     * Gets the number of fields in this partial, which is two.
381     * The supported fields are Year and MonthOfYear.
382     * Note that only these fields may be queried.
383     *
384     * @return the field count, two
385     */
386    public int size() {
387        return 2;
388    }
389
390    /**
391     * Gets the field for a specific index in the chronology specified.
392     * <p>
393     * This method must not use any instance variables.
394     * 
395     * @param index  the index to retrieve
396     * @param chrono  the chronology to use
397     * @return the field, never null
398     */
399    protected DateTimeField getField(int index, Chronology chrono) {
400        switch (index) {
401            case YEAR:
402                return chrono.year();
403            case MONTH_OF_YEAR:
404                return chrono.monthOfYear();
405            default:
406                throw new IndexOutOfBoundsException("Invalid index: " + index);
407        }
408    }
409
410    /**
411     * Gets the field type at the specified index.
412     *
413     * @param index  the index to retrieve
414     * @return the field at the specified index, never null
415     * @throws IndexOutOfBoundsException if the index is invalid
416     */
417    public DateTimeFieldType getFieldType(int index) {
418        return FIELD_TYPES[index];
419    }
420
421    /**
422     * Gets an array of the field type of each of the fields that this partial supports.
423     * <p>
424     * The fields are returned largest to smallest, Year, Month.
425     *
426     * @return the array of field types (cloned), largest to smallest, never null
427     */
428    public DateTimeFieldType[] getFieldTypes() {
429        return (DateTimeFieldType[]) FIELD_TYPES.clone();
430    }
431
432    //-----------------------------------------------------------------------
433    /**
434     * Returns a copy of this year-month with the specified chronology.
435     * This instance is immutable and unaffected by this method call.
436     * <p>
437     * This method retains the values of the fields, thus the result will
438     * typically refer to a different instant.
439     * <p>
440     * The time zone of the specified chronology is ignored, as YearMonth
441     * operates without a time zone.
442     *
443     * @param newChronology  the new chronology, null means ISO
444     * @return a copy of this year-month with a different chronology, never null
445     * @throws IllegalArgumentException if the values are invalid for the new chronology
446     */
447    public YearMonth withChronologyRetainFields(Chronology newChronology) {
448        newChronology = DateTimeUtils.getChronology(newChronology);
449        newChronology = newChronology.withUTC();
450        if (newChronology == getChronology()) {
451            return this;
452        } else {
453            YearMonth newYearMonth = new YearMonth(this, newChronology);
454            newChronology.validate(newYearMonth, getValues());
455            return newYearMonth;
456        }
457    }
458
459    /**
460     * Returns a copy of this year-month with the specified field set to a new value.
461     * <p>
462     * For example, if the field type is <code>monthOfYear</code> then the month
463     * would be changed in the returned instance.
464     * <p>
465     * These three lines are equivalent:
466     * <pre>
467     * YearMonth updated = ym.withField(DateTimeFieldType.monthOfYear(), 6);
468     * YearMonth updated = ym.monthOfYear().setCopy(6);
469     * YearMonth updated = ym.property(DateTimeFieldType.monthOfYear()).setCopy(6);
470     * </pre>
471     *
472     * @param fieldType  the field type to set, not null
473     * @param value  the value to set
474     * @return a copy of this instance with the field set, never null
475     * @throws IllegalArgumentException if the value is null or invalid
476     */
477    public YearMonth withField(DateTimeFieldType fieldType, int value) {
478        int index = indexOfSupported(fieldType);
479        if (value == getValue(index)) {
480            return this;
481        }
482        int[] newValues = getValues();
483        newValues = getField(index).set(this, index, newValues, value);
484        return new YearMonth(this, newValues);
485    }
486
487    /**
488     * Returns a copy of this year-month with the value of the specified field increased.
489     * <p>
490     * If the addition is zero, then <code>this</code> is returned.
491     * <p>
492     * These three lines are equivalent:
493     * <pre>
494     * YearMonth added = ym.withFieldAdded(DurationFieldType.months(), 6);
495     * YearMonth added = ym.plusMonths(6);
496     * YearMonth added = ym.monthOfYear().addToCopy(6);
497     * </pre>
498     * 
499     * @param fieldType  the field type to add to, not null
500     * @param amount  the amount to add
501     * @return a copy of this instance with the field updated, never null
502     * @throws IllegalArgumentException if the value is null or invalid
503     * @throws ArithmeticException if the new date-time exceeds the capacity
504     */
505    public YearMonth withFieldAdded(DurationFieldType fieldType, int amount) {
506        int index = indexOfSupported(fieldType);
507        if (amount == 0) {
508            return this;
509        }
510        int[] newValues = getValues();
511        newValues = getField(index).add(this, index, newValues, amount);
512        return new YearMonth(this, newValues);
513    }
514
515    /**
516     * Returns a copy of this year-month with the specified period added.
517     * <p>
518     * If the addition is zero, then <code>this</code> is returned.
519     * Fields in the period that aren't present in the partial are ignored.
520     * <p>
521     * This method is typically used to add multiple copies of complex
522     * period instances. Adding one field is best achieved using methods
523     * like {@link #withFieldAdded(DurationFieldType, int)}
524     * or {@link #plusYears(int)}.
525     * 
526     * @param period  the period to add to this one, null means zero
527     * @param scalar  the amount of times to add, such as -1 to subtract once
528     * @return a copy of this instance with the period added, never null
529     * @throws ArithmeticException if the new date-time exceeds the capacity
530     */
531    public YearMonth withPeriodAdded(ReadablePeriod period, int scalar) {
532        if (period == null || scalar == 0) {
533            return this;
534        }
535        int[] newValues = getValues();
536        for (int i = 0; i < period.size(); i++) {
537            DurationFieldType fieldType = period.getFieldType(i);
538            int index = indexOf(fieldType);
539            if (index >= 0) {
540                newValues = getField(index).add(this, index, newValues,
541                        FieldUtils.safeMultiply(period.getValue(i), scalar));
542            }
543        }
544        return new YearMonth(this, newValues);
545    }
546
547    //-----------------------------------------------------------------------
548    /**
549     * Returns a copy of this year-month with the specified period added.
550     * <p>
551     * If the amount is zero or null, then <code>this</code> is returned.
552     * <p>
553     * This method is typically used to add complex period instances.
554     * Adding one field is best achieved using methods
555     * like {@link #plusYears(int)}.
556     * 
557     * @param period  the duration to add to this one, null means zero
558     * @return a copy of this instance with the period added, never null
559     * @throws ArithmeticException if the new year-month exceeds the capacity
560     */
561    public YearMonth plus(ReadablePeriod period) {
562        return withPeriodAdded(period, 1);
563    }
564
565    //-----------------------------------------------------------------------
566    /**
567     * Returns a copy of this year-month plus the specified number of years.
568     * <p>
569     * This year-month instance is immutable and unaffected by this method call.
570     * <p>
571     * The following three lines are identical in effect:
572     * <pre>
573     * YearMonth added = ym.plusYears(6);
574     * YearMonth added = ym.plus(Period.years(6));
575     * YearMonth added = ym.withFieldAdded(DurationFieldType.years(), 6);
576     * </pre>
577     *
578     * @param years  the amount of years to add, may be negative
579     * @return the new year-month plus the increased years, never null
580     */
581    public YearMonth plusYears(int years) {
582        return withFieldAdded(DurationFieldType.years(), years);
583    }
584
585    /**
586     * Returns a copy of this year-month plus the specified number of months.
587     * <p>
588     * This year-month instance is immutable and unaffected by this method call.
589     * <p>
590     * The following three lines are identical in effect:
591     * <pre>
592     * YearMonth added = ym.plusMonths(6);
593     * YearMonth added = ym.plus(Period.months(6));
594     * YearMonth added = ym.withFieldAdded(DurationFieldType.months(), 6);
595     * </pre>
596     *
597     * @param months  the amount of months to add, may be negative
598     * @return the new year-month plus the increased months, never null
599     */
600    public YearMonth plusMonths(int months) {
601        return withFieldAdded(DurationFieldType.months(), months);
602    }
603
604    //-----------------------------------------------------------------------
605    /**
606     * Returns a copy of this year-month with the specified period taken away.
607     * <p>
608     * If the amount is zero or null, then <code>this</code> is returned.
609     * <p>
610     * This method is typically used to subtract complex period instances.
611     * Subtracting one field is best achieved using methods
612     * like {@link #minusYears(int)}.
613     * 
614     * @param period  the period to reduce this instant by
615     * @return a copy of this instance with the period taken away, never null
616     * @throws ArithmeticException if the new year-month exceeds the capacity
617     */
618    public YearMonth minus(ReadablePeriod period) {
619        return withPeriodAdded(period, -1);
620    }
621
622    //-----------------------------------------------------------------------
623    /**
624     * Returns a copy of this year-month minus the specified number of years.
625     * <p>
626     * This year-month instance is immutable and unaffected by this method call.
627     * <p>
628     * The following three lines are identical in effect:
629     * <pre>
630     * YearMonth subtracted = ym.minusYears(6);
631     * YearMonth subtracted = ym.minus(Period.years(6));
632     * YearMonth subtracted = ym.withFieldAdded(DurationFieldType.years(), -6);
633     * </pre>
634     *
635     * @param years  the amount of years to subtract, may be negative
636     * @return the new year-month minus the increased years, never null
637     */
638    public YearMonth minusYears(int years) {
639        return withFieldAdded(DurationFieldType.years(), FieldUtils.safeNegate(years));
640    }
641
642    /**
643     * Returns a copy of this year-month minus the specified number of months.
644     * <p>
645     * This year-month instance is immutable and unaffected by this method call.
646     * <p>
647     * The following three lines are identical in effect:
648     * <pre>
649     * YearMonth subtracted = ym.minusMonths(6);
650     * YearMonth subtracted = ym.minus(Period.months(6));
651     * YearMonth subtracted = ym.withFieldAdded(DurationFieldType.months(), -6);
652     * </pre>
653     *
654     * @param months  the amount of months to subtract, may be negative
655     * @return the new year-month minus the increased months, never null
656     */
657    public YearMonth minusMonths(int months) {
658        return withFieldAdded(DurationFieldType.months(), FieldUtils.safeNegate(months));
659    }
660
661    //-----------------------------------------------------------------------
662    /**
663     * Converts this object to a LocalDate with the same year-month and chronology.
664     *
665     * @param dayOfMonth the day of month to use, valid for chronology, such as 1-31 for ISO
666     * @return a LocalDate with the same year-month and chronology, never null
667     */
668    public LocalDate toLocalDate(int dayOfMonth) {
669        return new LocalDate(getYear(), getMonthOfYear(), dayOfMonth, getChronology());
670    }
671
672    //-----------------------------------------------------------------------
673    /**
674     * Converts this object to an Interval representing the whole month.
675     * <p>
676     * The interval will use the chronology of the year-month in the default zone.
677     * <p>
678     * This instance is immutable and unaffected by this method call.
679     *
680     * @return an interval over the month, never null
681     */
682    public Interval toInterval() {
683        return toInterval(null);
684    }
685
686    /**
687     * Converts this object to an Interval representing the whole month.
688     * <p>
689     * The interval will use the chronology of the year-month in the specified zone.
690     * <p>
691     * This instance is immutable and unaffected by this method call.
692     *
693     * @param zone  the zone to get the Interval in, null means default
694     * @return an interval over the month, never null
695     */
696    public Interval toInterval(DateTimeZone zone) {
697        zone = DateTimeUtils.getZone(zone);
698        DateTime start = toLocalDate(1).toDateTimeAtStartOfDay(zone);
699        DateTime end = plusMonths(1).toLocalDate(1).toDateTimeAtStartOfDay(zone);
700        return new Interval(start, end);
701    }
702
703    //-----------------------------------------------------------------------
704    /**
705     * Get the year field value.
706     *
707     * @return the year
708     */
709    public int getYear() {
710        return getValue(YEAR);
711    }
712
713    /**
714     * Get the month of year field value.
715     *
716     * @return the month of year
717     */
718    public int getMonthOfYear() {
719        return getValue(MONTH_OF_YEAR);
720    }
721
722    //-----------------------------------------------------------------------
723    /**
724     * Returns a copy of this year-month with the year field updated.
725     * <p>
726     * YearMonth is immutable, so there are no set methods.
727     * Instead, this method returns a new instance with the value of
728     * year changed.
729     *
730     * @param year  the year to set
731     * @return a copy of this object with the field set, never null
732     * @throws IllegalArgumentException if the value is invalid
733     */
734    public YearMonth withYear(int year) {
735        int[] newValues = getValues();
736        newValues = getChronology().year().set(this, YEAR, newValues, year);
737        return new YearMonth(this, newValues);
738    }
739
740    /**
741     * Returns a copy of this year-month with the month of year field updated.
742     * <p>
743     * YearMonth is immutable, so there are no set methods.
744     * Instead, this method returns a new instance with the value of
745     * month of year changed.
746     *
747     * @param monthOfYear  the month of year to set
748     * @return a copy of this object with the field set, never null
749     * @throws IllegalArgumentException if the value is invalid
750     */
751    public YearMonth withMonthOfYear(int monthOfYear) {
752        int[] newValues = getValues();
753        newValues = getChronology().monthOfYear().set(this, MONTH_OF_YEAR, newValues, monthOfYear);
754        return new YearMonth(this, newValues);
755    }
756
757    //-----------------------------------------------------------------------
758    /**
759     * Gets the property object for the specified type, which contains
760     * many useful methods.
761     *
762     * @param type  the field type to get the property for
763     * @return the property object
764     * @throws IllegalArgumentException if the field is null or unsupported
765     */
766    public Property property(DateTimeFieldType type) {
767        return new Property(this, indexOfSupported(type));
768    }
769
770    //-----------------------------------------------------------------------
771    /**
772     * Get the year field property which provides access to advanced functionality.
773     * 
774     * @return the year property
775     */
776    public Property year() {
777        return new Property(this, YEAR);
778    }
779
780    /**
781     * Get the month of year field property which provides access to advanced functionality.
782     * 
783     * @return the month of year property
784     */
785    public Property monthOfYear() {
786        return new Property(this, MONTH_OF_YEAR);
787    }
788
789    //-----------------------------------------------------------------------
790    /**
791     * Output the year-month in ISO8601 format (yyyy-MM).
792     *
793     * @return ISO8601 time formatted string.
794     */
795    @ToString
796    public String toString() {
797        return ISODateTimeFormat.yearMonth().print(this);
798    }
799
800    /**
801     * Output the year-month using the specified format pattern.
802     *
803     * @param pattern  the pattern specification, null means use <code>toString</code>
804     * @see org.joda.time.format.DateTimeFormat
805     */
806    public String toString(String pattern) {
807        if (pattern == null) {
808            return toString();
809        }
810        return DateTimeFormat.forPattern(pattern).print(this);
811    }
812
813    /**
814     * Output the year-month using the specified format pattern.
815     *
816     * @param pattern  the pattern specification, null means use <code>toString</code>
817     * @param locale  Locale to use, null means default
818     * @see org.joda.time.format.DateTimeFormat
819     */
820    public String toString(String pattern, Locale locale) throws IllegalArgumentException {
821        if (pattern == null) {
822            return toString();
823        }
824        return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this);
825    }
826
827    //-----------------------------------------------------------------------
828    /**
829     * The property class for <code>YearMonth</code>.
830     * <p>
831     * This class binds a <code>YearMonth</code> to a <code>DateTimeField</code>.
832     * 
833     * @author Stephen Colebourne
834     * @since 2.0
835     */
836    public static class Property extends AbstractPartialFieldProperty implements Serializable {
837
838        /** Serialization version */
839        private static final long serialVersionUID = 5727734012190224363L;
840
841        /** The partial */
842        private final YearMonth iBase;
843        /** The field index */
844        private final int iFieldIndex;
845
846        /**
847         * Constructs a property.
848         * 
849         * @param partial  the partial instance
850         * @param fieldIndex  the index in the partial
851         */
852        Property(YearMonth partial, int fieldIndex) {
853            super();
854            iBase = partial;
855            iFieldIndex = fieldIndex;
856        }
857
858        /**
859         * Gets the field that this property uses.
860         * 
861         * @return the field
862         */
863        public DateTimeField getField() {
864            return iBase.getField(iFieldIndex);
865        }
866
867        /**
868         * Gets the partial that this property belongs to.
869         * 
870         * @return the partial
871         */
872        protected ReadablePartial getReadablePartial() {
873            return iBase;
874        }
875
876        /**
877         * Gets the partial that this property belongs to.
878         * 
879         * @return the partial
880         */
881        public YearMonth getYearMonth() {
882            return iBase;
883        }
884
885        /**
886         * Gets the value of this field.
887         * 
888         * @return the field value
889         */
890        public int get() {
891            return iBase.getValue(iFieldIndex);
892        }
893
894        //-----------------------------------------------------------------------
895        /**
896         * Adds to the value of this field in a copy of this YearMonth.
897         * <p>
898         * The value will be added to this field. If the value is too large to be
899         * added solely to this field then it will affect larger fields.
900         * Smaller fields are unaffected.
901         * <p>
902         * If the result would be too large, beyond the maximum year, then an
903         * IllegalArgumentException is thrown.
904         * <p>
905         * The YearMonth attached to this property is unchanged by this call.
906         * Instead, a new instance is returned.
907         * 
908         * @param valueToAdd  the value to add to the field in the copy
909         * @return a copy of the YearMonth with the field value changed
910         * @throws IllegalArgumentException if the value isn't valid
911         */
912        public YearMonth addToCopy(int valueToAdd) {
913            int[] newValues = iBase.getValues();
914            newValues = getField().add(iBase, iFieldIndex, newValues, valueToAdd);
915            return new YearMonth(iBase, newValues);
916        }
917
918        /**
919         * Adds to the value of this field in a copy of this YearMonth wrapping
920         * within this field if the maximum value is reached.
921         * <p>
922         * The value will be added to this field. If the value is too large to be
923         * added solely to this field then it wraps within this field.
924         * Other fields are unaffected.
925         * <p>
926         * For example,
927         * <code>2004-12</code> addWrapField one month returns <code>2004-01</code>.
928         * <p>
929         * The YearMonth attached to this property is unchanged by this call.
930         * Instead, a new instance is returned.
931         * 
932         * @param valueToAdd  the value to add to the field in the copy
933         * @return a copy of the YearMonth with the field value changed
934         * @throws IllegalArgumentException if the value isn't valid
935         */
936        public YearMonth addWrapFieldToCopy(int valueToAdd) {
937            int[] newValues = iBase.getValues();
938            newValues = getField().addWrapField(iBase, iFieldIndex, newValues, valueToAdd);
939            return new YearMonth(iBase, newValues);
940        }
941
942        //-----------------------------------------------------------------------
943        /**
944         * Sets this field in a copy of the YearMonth.
945         * <p>
946         * The YearMonth attached to this property is unchanged by this call.
947         * Instead, a new instance is returned.
948         * 
949         * @param value  the value to set the field in the copy to
950         * @return a copy of the YearMonth with the field value changed
951         * @throws IllegalArgumentException if the value isn't valid
952         */
953        public YearMonth setCopy(int value) {
954            int[] newValues = iBase.getValues();
955            newValues = getField().set(iBase, iFieldIndex, newValues, value);
956            return new YearMonth(iBase, newValues);
957        }
958
959        /**
960         * Sets this field in a copy of the YearMonth to a parsed text value.
961         * <p>
962         * The YearMonth attached to this property is unchanged by this call.
963         * Instead, a new instance is returned.
964         * 
965         * @param text  the text value to set
966         * @param locale  optional locale to use for selecting a text symbol
967         * @return a copy of the YearMonth with the field value changed
968         * @throws IllegalArgumentException if the text value isn't valid
969         */
970        public YearMonth setCopy(String text, Locale locale) {
971            int[] newValues = iBase.getValues();
972            newValues = getField().set(iBase, iFieldIndex, newValues, text, locale);
973            return new YearMonth(iBase, newValues);
974        }
975
976        /**
977         * Sets this field in a copy of the YearMonth to a parsed text value.
978         * <p>
979         * The YearMonth attached to this property is unchanged by this call.
980         * Instead, a new instance is returned.
981         * 
982         * @param text  the text value to set
983         * @return a copy of the YearMonth with the field value changed
984         * @throws IllegalArgumentException if the text value isn't valid
985         */
986        public YearMonth setCopy(String text) {
987            return setCopy(text, null);
988        }
989    }
990
991}