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