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