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     */
016    package org.joda.time;
017    
018    import java.io.Serializable;
019    import java.util.Calendar;
020    import java.util.Date;
021    import java.util.Locale;
022    
023    import org.joda.convert.FromString;
024    import org.joda.convert.ToString;
025    import org.joda.time.base.BasePartial;
026    import org.joda.time.chrono.ISOChronology;
027    import org.joda.time.field.AbstractPartialFieldProperty;
028    import org.joda.time.field.FieldUtils;
029    import org.joda.time.format.DateTimeFormat;
030    import org.joda.time.format.DateTimeFormatter;
031    import 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     */
068    public 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    }