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 }