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     */
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    @Deprecated
065    public 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    }