View Javadoc

1   /*
2    *  Copyright 2001-2010 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   */
16  package org.joda.time;
17  
18  import java.io.Serializable;
19  import java.util.Calendar;
20  import java.util.Date;
21  import java.util.Locale;
22  
23  import org.joda.convert.FromString;
24  import org.joda.convert.ToString;
25  import org.joda.time.base.BasePartial;
26  import org.joda.time.chrono.ISOChronology;
27  import org.joda.time.field.AbstractPartialFieldProperty;
28  import org.joda.time.field.FieldUtils;
29  import org.joda.time.format.DateTimeFormat;
30  import org.joda.time.format.DateTimeFormatter;
31  import org.joda.time.format.ISODateTimeFormat;
32  
33  /**
34   * YearMonth is an immutable partial supporting the year and monthOfYear fields.
35   * <p>
36   * NOTE: This class only supports the two fields listed above.
37   * It is impossible to query any other fields, such as dayOfWeek or centuryOfEra.
38   * <p>
39   * Calculations on YearMonth are performed using a {@link Chronology}.
40   * This chronology is set to be in the UTC time zone for all calculations.
41   * <p>
42   * One use case for this class is to store a credit card expiry date, as that only
43   * references the year and month.
44   * This class can be used as the gYearMonth type in XML Schema.
45   * <p>
46   * Each individual field can be queried in two ways:
47   * <ul>
48   * <li><code>getMonthOfYear()</code>
49   * <li><code>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   * YearMonth 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 2.0
67   */
68  public final class YearMonth
69          extends BasePartial
70          implements ReadablePartial, Serializable {
71  
72      /** Serialization version */
73      private static final long serialVersionUID = 797544782896179L;
74      /** The singleton set of field types */
75      private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
76          DateTimeFieldType.year(),
77          DateTimeFieldType.monthOfYear(),
78      };
79  
80      /** The index of the year field in the field array */
81      public static final int YEAR = 0;
82      /** The index of the monthOfYear field in the field array */
83      public static final int MONTH_OF_YEAR = 1;
84  
85      //-----------------------------------------------------------------------
86      /**
87       * Obtains a {@code YearMonth} set to the current system millisecond time
88       * using <code>ISOChronology</code> in the default time zone.
89       * The resulting object does not use the zone.
90       * 
91       * @return the current year-month, not null
92       * @since 2.0
93       */
94      public static YearMonth now() {
95          return new YearMonth();
96      }
97  
98      /**
99       * 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 }