001    /*
002     *  Copyright 2001-2010 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.io.IOException;
019    import java.io.ObjectInputStream;
020    import java.io.ObjectOutputStream;
021    import java.io.Serializable;
022    import java.util.Locale;
023    
024    import org.joda.convert.FromString;
025    import org.joda.convert.ToString;
026    import org.joda.time.base.BaseDateTime;
027    import org.joda.time.chrono.ISOChronology;
028    import org.joda.time.field.AbstractReadableInstantFieldProperty;
029    import org.joda.time.field.FieldUtils;
030    import org.joda.time.format.DateTimeFormatter;
031    import org.joda.time.format.ISODateTimeFormat;
032    
033    /**
034     * MutableDateTime is the standard implementation of a modifiable datetime class.
035     * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
036     * <p>
037     * This class uses a Chronology internally. The Chronology determines how the
038     * millisecond instant value is converted into the date time fields.
039     * The default Chronology is <code>ISOChronology</code> which is the agreed
040     * international standard and compatible with the modern Gregorian calendar.
041     * <p>
042     * Each individual field can be accessed in two ways:
043     * <ul>
044     * <li><code>getHourOfDay()</code>
045     * <li><code>hourOfDay().get()</code>
046     * </ul>
047     * The second technique also provides access to other useful methods on the
048     * field:
049     * <ul>
050     * <li>get numeric value
051     * <li>set numeric value
052     * <li>add to numeric value
053     * <li>add to numeric value wrapping with the field
054     * <li>get text value
055     * <li>get short text value
056     * <li>set text value
057     * <li>field maximum value
058     * <li>field minimum value
059     * </ul>
060     *
061     * <p>
062     * MutableDateTime is mutable and not thread-safe, unless concurrent threads
063     * are not invoking mutator methods.
064     *
065     * @author Guy Allard
066     * @author Brian S O'Neill
067     * @author Stephen Colebourne
068     * @author Mike Schrag
069     * @since 1.0
070     * @see DateTime
071     */
072    public class MutableDateTime
073            extends BaseDateTime
074            implements ReadWritableDateTime, Cloneable, Serializable {
075    
076        /** Serialization version */
077        private static final long serialVersionUID = 2852608688135209575L;
078    
079        /** Rounding is disabled */
080        public static final int ROUND_NONE = 0;
081        /** Rounding mode as described by {@link DateTimeField#roundFloor} */
082        public static final int ROUND_FLOOR = 1;
083        /** Rounding mode as described by {@link DateTimeField#roundCeiling} */
084        public static final int ROUND_CEILING = 2;
085        /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */
086        public static final int ROUND_HALF_FLOOR = 3;
087        /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */
088        public static final int ROUND_HALF_CEILING = 4;
089        /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */
090        public static final int ROUND_HALF_EVEN = 5;
091    
092        /** The field to round on */
093        private DateTimeField iRoundingField;
094        /** The mode of rounding */
095        private int iRoundingMode;
096    
097        //-----------------------------------------------------------------------
098        /**
099         * Obtains a {@code MutableDateTime} set to the current system millisecond time
100         * using <code>ISOChronology</code> in the default time zone.
101         * 
102         * @return the current date-time, not null
103         * @since 2.0
104         */
105        public static MutableDateTime now() {
106            return new MutableDateTime();
107        }
108    
109        /**
110         * Obtains a {@code MutableDateTime} set to the current system millisecond time
111         * using <code>ISOChronology</code> in the specified time zone.
112         *
113         * @param zone  the time zone, not null
114         * @return the current date-time, not null
115         * @since 2.0
116         */
117        public static MutableDateTime now(DateTimeZone zone) {
118            if (zone == null) {
119                throw new NullPointerException("Zone must not be null");
120            }
121            return new MutableDateTime(zone);
122        }
123    
124        /**
125         * Obtains a {@code MutableDateTime} set to the current system millisecond time
126         * using the specified chronology.
127         *
128         * @param chronology  the chronology, not null
129         * @return the current date-time, not null
130         * @since 2.0
131         */
132        public static MutableDateTime now(Chronology chronology) {
133            if (chronology == null) {
134                throw new NullPointerException("Chronology must not be null");
135            }
136            return new MutableDateTime(chronology);
137        }
138    
139        //-----------------------------------------------------------------------
140        /**
141         * Parses a {@code MutableDateTime} from the specified string.
142         * <p>
143         * This uses {@link ISODateTimeFormat#dateTimeParser()}.
144         * 
145         * @param str  the string to parse, not null
146         * @since 2.0
147         */
148        @FromString
149        public static MutableDateTime parse(String str) {
150            return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed());
151        }
152    
153        /**
154         * Parses a {@code MutableDateTime} from the specified string using a formatter.
155         * 
156         * @param str  the string to parse, not null
157         * @param formatter  the formatter to use, not null
158         * @since 2.0
159         */
160        public static MutableDateTime parse(String str, DateTimeFormatter formatter) {
161            return formatter.parseDateTime(str).toMutableDateTime();
162        }
163    
164        //-----------------------------------------------------------------------
165        /**
166         * Constructs an instance set to the current system millisecond time
167         * using <code>ISOChronology</code> in the default time zone.
168         * 
169         * @see #now()
170         */
171        public MutableDateTime() {
172            super();
173        }
174    
175        /**
176         * Constructs an instance set to the current system millisecond time
177         * using <code>ISOChronology</code> in the specified time zone.
178         * <p>
179         * If the specified time zone is null, the default zone is used.
180         *
181         * @param zone  the time zone, null means default zone
182         * @see #now(DateTimeZone)
183         */
184        public MutableDateTime(DateTimeZone zone) {
185            super(zone);
186        }
187    
188        /**
189         * Constructs an instance set to the current system millisecond time
190         * using the specified chronology.
191         * <p>
192         * If the chronology is null, <code>ISOChronology</code>
193         * in the default time zone is used.
194         *
195         * @param chronology  the chronology, null means ISOChronology in default zone
196         * @see #now(Chronology)
197         */
198        public MutableDateTime(Chronology chronology) {
199            super(chronology);
200        }
201    
202        //-----------------------------------------------------------------------
203        /**
204         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
205         * using <code>ISOChronology</code> in the default time zone.
206         *
207         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
208         */
209        public MutableDateTime(long instant) {
210            super(instant);
211        }
212    
213        /**
214         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
215         * using <code>ISOChronology</code> in the specified time zone.
216         * <p>
217         * If the specified time zone is null, the default zone is used.
218         *
219         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
220         * @param zone  the time zone, null means default zone
221         */
222        public MutableDateTime(long instant, DateTimeZone zone) {
223            super(instant, zone);
224        }
225    
226        /**
227         * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
228         * using the specified chronology.
229         * <p>
230         * If the chronology is null, <code>ISOChronology</code>
231         * in the default time zone is used.
232         *
233         * @param instant  the milliseconds from 1970-01-01T00:00:00Z
234         * @param chronology  the chronology, null means ISOChronology in default zone
235         */
236        public MutableDateTime(long instant, Chronology chronology) {
237            super(instant, chronology);
238        }
239    
240        //-----------------------------------------------------------------------
241        /**
242         * Constructs an instance from an Object that represents a datetime.
243         * <p>
244         * If the object implies a chronology (such as GregorianCalendar does),
245         * then that chronology will be used. Otherwise, ISO default is used.
246         * Thus if a GregorianCalendar is passed in, the chronology used will
247         * be GJ, but if a Date is passed in the chronology will be ISO.
248         * <p>
249         * The recognised object types are defined in
250         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
251         * include ReadableInstant, String, Calendar and Date.
252         *
253         * @param instant  the datetime object, null means now
254         * @throws IllegalArgumentException if the instant is invalid
255         */
256        public MutableDateTime(Object instant) {
257            super(instant, (Chronology) null);
258        }
259    
260        /**
261         * Constructs an instance from an Object that represents a datetime,
262         * forcing the time zone to that specified.
263         * <p>
264         * If the object implies a chronology (such as GregorianCalendar does),
265         * then that chronology will be used, but with the time zone adjusted.
266         * Otherwise, ISO is used in the specified time zone.
267         * If the specified time zone is null, the default zone is used.
268         * Thus if a GregorianCalendar is passed in, the chronology used will
269         * be GJ, but if a Date is passed in the chronology will be ISO.
270         * <p>
271         * The recognised object types are defined in
272         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
273         * include ReadableInstant, String, Calendar and Date.
274         *
275         * @param instant  the datetime object, null means now
276         * @param zone  the time zone, null means default time zone
277         * @throws IllegalArgumentException if the instant is invalid
278         */
279        public MutableDateTime(Object instant, DateTimeZone zone) {
280            super(instant, zone);
281        }
282    
283        /**
284         * Constructs an instance from an Object that represents a datetime,
285         * using the specified chronology.
286         * <p>
287         * If the chronology is null, ISO in the default time zone is used.
288         * Any chronology implied by the object (such as GregorianCalendar does)
289         * is ignored.
290         * <p>
291         * The recognised object types are defined in
292         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
293         * include ReadableInstant, String, Calendar and Date.
294         *
295         * @param instant  the datetime object, null means now
296         * @param chronology  the chronology, null means ISOChronology in default zone
297         * @throws IllegalArgumentException if the instant is invalid
298         */
299        public MutableDateTime(Object instant, Chronology chronology) {
300            super(instant, DateTimeUtils.getChronology(chronology));
301        }
302    
303        //-----------------------------------------------------------------------
304        /**
305         * Constructs an instance from datetime field values
306         * using <code>ISOChronology</code> in the default time zone.
307         *
308         * @param year  the year
309         * @param monthOfYear  the month of the year
310         * @param dayOfMonth  the day of the month
311         * @param hourOfDay  the hour of the day
312         * @param minuteOfHour  the minute of the hour
313         * @param secondOfMinute  the second of the minute
314         * @param millisOfSecond  the millisecond of the second
315         */
316        public MutableDateTime(
317                int year,
318                int monthOfYear,
319                int dayOfMonth,
320                int hourOfDay,
321                int minuteOfHour,
322                int secondOfMinute,
323                int millisOfSecond) {
324            super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
325        }
326    
327        /**
328         * Constructs an instance from datetime field values
329         * using <code>ISOChronology</code> in the specified time zone.
330         * <p>
331         * If the specified time zone is null, the default zone is used.
332         *
333         * @param year  the year
334         * @param monthOfYear  the month of the year
335         * @param dayOfMonth  the day of the month
336         * @param hourOfDay  the hour of the day
337         * @param minuteOfHour  the minute of the hour
338         * @param secondOfMinute  the second of the minute
339         * @param millisOfSecond  the millisecond of the second
340         * @param zone  the time zone, null means default time zone
341         */
342        public MutableDateTime(
343                int year,
344                int monthOfYear,
345                int dayOfMonth,
346                int hourOfDay,
347                int minuteOfHour,
348                int secondOfMinute,
349                int millisOfSecond,
350                DateTimeZone zone) {
351            super(year, monthOfYear, dayOfMonth,
352                  hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
353        }
354    
355        /**
356         * Constructs an instance from datetime field values
357         * using the specified chronology.
358         * <p>
359         * If the chronology is null, <code>ISOChronology</code>
360         * in the default time zone is used.
361         *
362         * @param year  the year
363         * @param monthOfYear  the month of the year
364         * @param dayOfMonth  the day of the month
365         * @param hourOfDay  the hour of the day
366         * @param minuteOfHour  the minute of the hour
367         * @param secondOfMinute  the second of the minute
368         * @param millisOfSecond  the millisecond of the second
369         * @param chronology  the chronology, null means ISOChronology in default zone
370         */
371        public MutableDateTime(
372                int year,
373                int monthOfYear,
374                int dayOfMonth,
375                int hourOfDay,
376                int minuteOfHour,
377                int secondOfMinute,
378                int millisOfSecond,
379                Chronology chronology) {
380            super(year, monthOfYear, dayOfMonth,
381                  hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, chronology);
382        }
383    
384        //-----------------------------------------------------------------------
385        /**
386         * Gets the field used for rounding this instant, returning null if rounding
387         * is not enabled.
388         * 
389         * @return the rounding field
390         */
391        public DateTimeField getRoundingField() {
392            return iRoundingField;
393        }
394    
395        /**
396         * Gets the rounding mode for this instant, returning ROUND_NONE if rounding
397         * is not enabled.
398         * 
399         * @return the rounding mode constant
400         */
401        public int getRoundingMode() {
402            return iRoundingMode;
403        }
404    
405        /**
406         * Sets the status of rounding to use the specified field and ROUND_FLOOR mode.
407         * A null field will disable rounding.
408         * Once set, the instant is then rounded using the new field and mode.
409         * <p>
410         * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
411         * to be rounded. This can be used to control the precision of the instant,
412         * for example by setting a rounding field of minuteOfDay, the seconds and
413         * milliseconds will always be zero.
414         *
415         * @param field rounding field or null to disable
416         */
417        public void setRounding(DateTimeField field) {
418            setRounding(field, MutableDateTime.ROUND_FLOOR);
419        }
420    
421        /**
422         * Sets the status of rounding to use the specified field and mode.
423         * A null field or mode of ROUND_NONE will disable rounding.
424         * Once set, the instant is then rounded using the new field and mode.
425         * <p>
426         * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
427         * to be rounded. This can be used to control the precision of the instant,
428         * for example by setting a rounding field of minuteOfDay, the seconds and
429         * milliseconds will always be zero.
430         *
431         * @param field  rounding field or null to disable
432         * @param mode  rounding mode or ROUND_NONE to disable
433         * @throws IllegalArgumentException if mode is unknown, no exception if field is null
434         */
435        public void setRounding(DateTimeField field, int mode) {
436            if (field != null && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) {
437                throw new IllegalArgumentException("Illegal rounding mode: " + mode);
438            }
439            iRoundingField = (mode == ROUND_NONE ? null : field);
440            iRoundingMode = (field == null ? ROUND_NONE : mode);
441            setMillis(getMillis());
442        }
443    
444        //-----------------------------------------------------------------------
445        /**
446         * Set the milliseconds of the datetime.
447         * <p>
448         * All changes to the millisecond field occurs via this method.
449         *
450         * @param instant  the milliseconds since 1970-01-01T00:00:00Z to set the
451         * datetime to
452         */
453        public void setMillis(long instant) {
454            switch (iRoundingMode) {
455                case ROUND_NONE:
456                    break;
457                case ROUND_FLOOR:
458                    instant = iRoundingField.roundFloor(instant);
459                    break;
460                case ROUND_CEILING:
461                    instant = iRoundingField.roundCeiling(instant);
462                    break;
463                case ROUND_HALF_FLOOR:
464                    instant = iRoundingField.roundHalfFloor(instant);
465                    break;
466                case ROUND_HALF_CEILING:
467                    instant = iRoundingField.roundHalfCeiling(instant);
468                    break;
469                case ROUND_HALF_EVEN:
470                    instant = iRoundingField.roundHalfEven(instant);
471                    break;
472            }
473    
474            super.setMillis(instant);
475        }
476    
477        /**
478         * Sets the millisecond instant of this instant from another.
479         * <p>
480         * This method does not change the chronology of this instant, just the
481         * millisecond instant.
482         * 
483         * @param instant  the instant to use, null means now
484         */
485        public void setMillis(ReadableInstant instant) {
486            long instantMillis = DateTimeUtils.getInstantMillis(instant);
487            setMillis(instantMillis);  // set via this class not super
488        }
489    
490        //-----------------------------------------------------------------------
491        /**
492         * Add an amount of time to the datetime.
493         * 
494         * @param duration  the millis to add
495         * @throws ArithmeticException if the result exceeds the capacity of the instant
496         */
497        public void add(long duration) {
498            setMillis(FieldUtils.safeAdd(getMillis(), duration));  // set via this class not super
499        }
500    
501        /**
502         * Adds a duration to this instant.
503         * <p>
504         * This will typically change the value of most fields.
505         *
506         * @param duration  the duration to add, null means add zero
507         * @throws ArithmeticException if the result exceeds the capacity of the instant
508         */
509        public void add(ReadableDuration duration) {
510            add(duration, 1);
511        }
512    
513        /**
514         * Adds a duration to this instant specifying how many times to add.
515         * <p>
516         * This will typically change the value of most fields.
517         *
518         * @param duration  the duration to add, null means add zero
519         * @param scalar  direction and amount to add, which may be negative
520         * @throws ArithmeticException if the result exceeds the capacity of the instant
521         */
522        public void add(ReadableDuration duration, int scalar) {
523            if (duration != null) {
524                add(FieldUtils.safeMultiply(duration.getMillis(), scalar));
525            }
526        }
527    
528        /**
529         * Adds a period to this instant.
530         * <p>
531         * This will typically change the value of most fields.
532         *
533         * @param period  the period to add, null means add zero
534         * @throws ArithmeticException if the result exceeds the capacity of the instant
535         */
536        public void add(ReadablePeriod period) {
537            add(period, 1);
538        }
539    
540        /**
541         * Adds a period to this instant specifying how many times to add.
542         * <p>
543         * This will typically change the value of most fields.
544         *
545         * @param period  the period to add, null means add zero
546         * @param scalar  direction and amount to add, which may be negative
547         * @throws ArithmeticException if the result exceeds the capacity of the instant
548         */
549        public void add(ReadablePeriod period, int scalar) {
550            if (period != null) {
551                setMillis(getChronology().add(period, getMillis(), scalar));  // set via this class not super
552            }
553        }
554    
555        //-----------------------------------------------------------------------
556        /**
557         * Set the chronology of the datetime.
558         * <p>
559         * All changes to the chronology occur via this method.
560         * 
561         * @param chronology  the chronology to use, null means ISOChronology in default zone
562         */
563        public void setChronology(Chronology chronology) {
564            super.setChronology(chronology);
565        }
566    
567        //-----------------------------------------------------------------------
568        /**
569         * Sets the time zone of the datetime, changing the chronology and field values.
570         * <p>
571         * Changing the zone using this method retains the millisecond instant.
572         * The millisecond instant is adjusted in the new zone to compensate.
573         * 
574         * chronology. Setting the time zone does not affect the millisecond value
575         * of this instant.
576         * <p>
577         * If the chronology already has this time zone, no change occurs.
578         *
579         * @param newZone  the time zone to use, null means default zone
580         * @see #setZoneRetainFields
581         */
582        public void setZone(DateTimeZone newZone) {
583            newZone = DateTimeUtils.getZone(newZone);
584            Chronology chrono = getChronology();
585            if (chrono.getZone() != newZone) {
586                setChronology(chrono.withZone(newZone));  // set via this class not super
587            }
588        }
589    
590        /**
591         * Sets the time zone of the datetime, changing the chronology and millisecond.
592         * <p>
593         * Changing the zone using this method retains the field values.
594         * The millisecond instant is adjusted in the new zone to compensate.
595         * <p>
596         * If the chronology already has this time zone, no change occurs.
597         *
598         * @param newZone  the time zone to use, null means default zone
599         * @see #setZone
600         */
601        public void setZoneRetainFields(DateTimeZone newZone) {
602            newZone = DateTimeUtils.getZone(newZone);
603            DateTimeZone originalZone = DateTimeUtils.getZone(getZone());
604            if (newZone == originalZone) {
605                return;
606            }
607            
608            long millis = originalZone.getMillisKeepLocal(newZone, getMillis());
609            setChronology(getChronology().withZone(newZone));  // set via this class not super
610            setMillis(millis);
611        }
612    
613        //-----------------------------------------------------------------------
614        /**
615         * Sets the value of one of the fields of the instant, such as hourOfDay.
616         *
617         * @param type  a field type, usually obtained from DateTimeFieldType, not null
618         * @param value  the value to set the field to
619         * @throws IllegalArgumentException if the value is null or invalid
620         */
621        public void set(DateTimeFieldType type, int value) {
622            if (type == null) {
623                throw new IllegalArgumentException("Field must not be null");
624            }
625            setMillis(type.getField(getChronology()).set(getMillis(), value));
626        }
627    
628        /**
629         * Adds to the instant specifying the duration and multiple to add.
630         *
631         * @param type  a field type, usually obtained from DateTimeFieldType, not null
632         * @param amount  the amount to add of this duration
633         * @throws IllegalArgumentException if the value is null or invalid
634         * @throws ArithmeticException if the result exceeds the capacity of the instant
635         */
636        public void add(DurationFieldType type, int amount) {
637            if (type == null) {
638                throw new IllegalArgumentException("Field must not be null");
639            }
640            setMillis(type.getField(getChronology()).add(getMillis(), amount));
641        }
642    
643        //-----------------------------------------------------------------------
644        /**
645         * Set the year to the specified value.
646         *
647         * @param year  the year
648         * @throws IllegalArgumentException if the value is invalid
649         */
650        public void setYear(final int year) {
651            setMillis(getChronology().year().set(getMillis(), year));
652        }
653    
654        /**
655         * Add a number of years to the date.
656         *
657         * @param years  the years to add
658         * @throws IllegalArgumentException if the value is invalid
659         */
660        public void addYears(final int years) {
661            setMillis(getChronology().years().add(getMillis(), years));
662        }
663    
664        //-----------------------------------------------------------------------
665        /**
666         * Set the weekyear to the specified value.
667         *
668         * @param weekyear  the weekyear
669         * @throws IllegalArgumentException if the value is invalid
670         */
671        public void setWeekyear(final int weekyear) {
672            setMillis(getChronology().weekyear().set(getMillis(), weekyear));
673        }
674    
675        /**
676         * Add a number of weekyears to the date.
677         *
678         * @param weekyears  the weekyears to add
679         * @throws IllegalArgumentException if the value is invalid
680         */
681        public void addWeekyears(final int weekyears) {
682            setMillis(getChronology().weekyears().add(getMillis(), weekyears));
683        }
684    
685        //-----------------------------------------------------------------------
686        /**
687         * Set the month of the year to the specified value.
688         *
689         * @param monthOfYear  the month of the year
690         * @throws IllegalArgumentException if the value is invalid
691         */
692        public void setMonthOfYear(final int monthOfYear) {
693            setMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear));
694        }
695    
696        /**
697         * Add a number of months to the date.
698         *
699         * @param months  the months to add
700         * @throws IllegalArgumentException if the value is invalid
701         */
702        public void addMonths(final int months) {
703            setMillis(getChronology().months().add(getMillis(), months));
704        }
705    
706        //-----------------------------------------------------------------------
707        /**
708         * Set the week of weekyear to the specified value.
709         *
710         * @param weekOfWeekyear the week of the weekyear
711         * @throws IllegalArgumentException if the value is invalid
712         */
713        public void setWeekOfWeekyear(final int weekOfWeekyear) {
714            setMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear));
715        }
716    
717        /**
718         * Add a number of weeks to the date.
719         *
720         * @param weeks  the weeks to add
721         * @throws IllegalArgumentException if the value is invalid
722         */
723        public void addWeeks(final int weeks) {
724            setMillis(getChronology().weeks().add(getMillis(), weeks));
725        }
726    
727        //-----------------------------------------------------------------------
728        /**
729         * Set the day of year to the specified value.
730         *
731         * @param dayOfYear the day of the year
732         * @throws IllegalArgumentException if the value is invalid
733         */
734        public void setDayOfYear(final int dayOfYear) {
735            setMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear));
736        }
737    
738        /**
739         * Set the day of the month to the specified value.
740         *
741         * @param dayOfMonth  the day of the month
742         * @throws IllegalArgumentException if the value is invalid
743         */
744        public void setDayOfMonth(final int dayOfMonth) {
745            setMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth));
746        }
747    
748        /**
749         * Set the day of week to the specified value.
750         *
751         * @param dayOfWeek  the day of the week
752         * @throws IllegalArgumentException if the value is invalid
753         */
754        public void setDayOfWeek(final int dayOfWeek) {
755            setMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek));
756        }
757    
758        /**
759         * Add a number of days to the date.
760         *
761         * @param days  the days to add
762         * @throws IllegalArgumentException if the value is invalid
763         */
764        public void addDays(final int days) {
765            setMillis(getChronology().days().add(getMillis(), days));
766        }
767    
768        //-----------------------------------------------------------------------
769        /**
770         * Set the hour of the day to the specified value.
771         *
772         * @param hourOfDay  the hour of day
773         * @throws IllegalArgumentException if the value is invalid
774         */
775        public void setHourOfDay(final int hourOfDay) {
776            setMillis(getChronology().hourOfDay().set(getMillis(), hourOfDay));
777        }
778    
779        /**
780         * Add a number of hours to the date.
781         *
782         * @param hours  the hours to add
783         * @throws IllegalArgumentException if the value is invalid
784         */
785        public void addHours(final int hours) {
786            setMillis(getChronology().hours().add(getMillis(), hours));
787        }
788        
789        //-----------------------------------------------------------------------
790        /**
791         * Set the minute of the day to the specified value.
792         *
793         * @param minuteOfDay  the minute of day
794         * @throws IllegalArgumentException if the value is invalid
795         */
796        public void setMinuteOfDay(final int minuteOfDay) {
797            setMillis(getChronology().minuteOfDay().set(getMillis(), minuteOfDay));
798        }
799    
800        /**
801         * Set the minute of the hour to the specified value.
802         *
803         * @param minuteOfHour  the minute of hour
804         * @throws IllegalArgumentException if the value is invalid
805         */
806        public void setMinuteOfHour(final int minuteOfHour) {
807            setMillis(getChronology().minuteOfHour().set(getMillis(), minuteOfHour));
808        }
809    
810        /**
811         * Add a number of minutes to the date.
812         *
813         * @param minutes  the minutes to add
814         * @throws IllegalArgumentException if the value is invalid
815         */
816        public void addMinutes(final int minutes) {
817            setMillis(getChronology().minutes().add(getMillis(), minutes));
818        }
819    
820        //-----------------------------------------------------------------------
821        /**
822         * Set the second of the day to the specified value.
823         *
824         * @param secondOfDay  the second of day
825         * @throws IllegalArgumentException if the value is invalid
826         */
827        public void setSecondOfDay(final int secondOfDay) {
828            setMillis(getChronology().secondOfDay().set(getMillis(), secondOfDay));
829        }
830    
831        /**
832         * Set the second of the minute to the specified value.
833         *
834         * @param secondOfMinute  the second of minute
835         * @throws IllegalArgumentException if the value is invalid
836         */
837        public void setSecondOfMinute(final int secondOfMinute) {
838            setMillis(getChronology().secondOfMinute().set(getMillis(), secondOfMinute));
839        }
840    
841        /**
842         * Add a number of seconds to the date.
843         *
844         * @param seconds  the seconds to add
845         * @throws IllegalArgumentException if the value is invalid
846         */
847        public void addSeconds(final int seconds) {
848            setMillis(getChronology().seconds().add(getMillis(), seconds));
849        }
850    
851        //-----------------------------------------------------------------------
852        /**
853         * Set the millis of the day to the specified value.
854         *
855         * @param millisOfDay  the millis of day
856         * @throws IllegalArgumentException if the value is invalid
857         */
858        public void setMillisOfDay(final int millisOfDay) {
859            setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
860        }
861    
862        /**
863         * Set the millis of the second to the specified value.
864         *
865         * @param millisOfSecond  the millis of second
866         * @throws IllegalArgumentException if the value is invalid
867         */
868        public void setMillisOfSecond(final int millisOfSecond) {
869            setMillis(getChronology().millisOfSecond().set(getMillis(), millisOfSecond));
870        }
871    
872        /**
873         * Add a number of milliseconds to the date. The implementation of this
874         * method differs from the {@link #add(long)} method in that a
875         * DateTimeField performs the addition.
876         *
877         * @param millis  the milliseconds to add
878         * @throws IllegalArgumentException if the value is invalid
879         */
880        public void addMillis(final int millis) {
881            setMillis(getChronology().millis().add(getMillis(), millis));
882        }
883    
884        //-----------------------------------------------------------------------
885        /**
886         * Set the date from milliseconds.
887         * The time part of this object will be unaffected.
888         *
889         * @param instant  an instant to copy the date from, time part ignored
890         * @throws IllegalArgumentException if the value is invalid
891         */
892        public void setDate(final long instant) {
893            setMillis(getChronology().millisOfDay().set(instant, getMillisOfDay()));
894        }
895    
896        /**
897         * Set the date from another instant.
898         * The time part of this object will be unaffected.
899         *
900         * @param instant  an instant to copy the date from, time part ignored
901         * @throws IllegalArgumentException if the object is invalid
902         */
903        public void setDate(final ReadableInstant instant) {
904            long instantMillis = DateTimeUtils.getInstantMillis(instant);
905            Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
906            DateTimeZone zone = instantChrono.getZone();
907            if (zone != null) {
908                instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
909            }
910            setDate(instantMillis);
911        }
912    
913        /**
914         * Set the date from fields.
915         * The time part of this object will be unaffected.
916         *
917         * @param year  the year
918         * @param monthOfYear  the month of the year
919         * @param dayOfMonth  the day of the month
920         * @throws IllegalArgumentException if the value is invalid
921         */
922        public void setDate(
923                final int year,
924                final int monthOfYear,
925                final int dayOfMonth) {
926            Chronology c = getChronology();
927            long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0);
928            setDate(instantMidnight);
929        }
930    
931        //-----------------------------------------------------------------------
932        /**
933         * Set the time from milliseconds.
934         * The date part of this object will be unaffected.
935         *
936         * @param millis  an instant to copy the time from, date part ignored
937         * @throws IllegalArgumentException if the value is invalid
938         */
939        public void setTime(final long millis) {
940            int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis);
941            setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
942        }
943    
944        /**
945         * Set the time from another instant.
946         * The date part of this object will be unaffected.
947         *
948         * @param instant  an instant to copy the time from, date part ignored
949         * @throws IllegalArgumentException if the object is invalid
950         */
951        public void setTime(final ReadableInstant instant) {
952            long instantMillis = DateTimeUtils.getInstantMillis(instant);
953            Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
954            DateTimeZone zone = instantChrono.getZone();
955            if (zone != null) {
956                instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
957            }
958            setTime(instantMillis);
959        }
960    
961        /**
962         * Set the time from fields.
963         * The date part of this object will be unaffected.
964         *
965         * @param hour  the hour
966         * @param minuteOfHour  the minute of the hour
967         * @param secondOfMinute  the second of the minute
968         * @param millisOfSecond  the millisecond of the second
969         * @throws IllegalArgumentException if the value is invalid
970         */
971        public void setTime(
972                final int hour,
973                final int minuteOfHour,
974                final int secondOfMinute,
975                final int millisOfSecond) {
976            long instant = getChronology().getDateTimeMillis(
977                getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond);
978            setMillis(instant);
979        }
980    
981        /**
982         * Set the date and time from fields.
983         *
984         * @param year  the year
985         * @param monthOfYear  the month of the year
986         * @param dayOfMonth  the day of the month
987         * @param hourOfDay  the hour of the day
988         * @param minuteOfHour  the minute of the hour
989         * @param secondOfMinute  the second of the minute
990         * @param millisOfSecond  the millisecond of the second
991         * @throws IllegalArgumentException if the value is invalid
992         */
993        public void setDateTime(
994                final int year,
995                final int monthOfYear,
996                final int dayOfMonth,
997                final int hourOfDay,
998                final int minuteOfHour,
999                final int secondOfMinute,
1000                final int millisOfSecond) {
1001            long instant = getChronology().getDateTimeMillis(
1002                year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
1003            setMillis(instant);
1004        }
1005    
1006        //-----------------------------------------------------------------------
1007        /**
1008         * Gets the property object for the specified type, which contains many useful methods.
1009         *
1010         * @param type  the field type to get the chronology for
1011         * @return the property object
1012         * @throws IllegalArgumentException if the field is null or unsupported
1013         * @since 1.2
1014         */
1015        public Property property(DateTimeFieldType type) {
1016            if (type == null) {
1017                throw new IllegalArgumentException("The DateTimeFieldType must not be null");
1018            }
1019            DateTimeField field = type.getField(getChronology());
1020            if (field.isSupported() == false) {
1021                throw new IllegalArgumentException("Field '" + type + "' is not supported");
1022            }
1023            return new Property(this, field);
1024        }
1025    
1026        /**
1027         * Get the era property.
1028         * 
1029         * @return the era property
1030         */
1031        public Property era() {
1032            return new Property(this, getChronology().era());
1033        }
1034    
1035        /**
1036         * Get the century of era property.
1037         * 
1038         * @return the year of era property
1039         */
1040        public Property centuryOfEra() {
1041            return new Property(this, getChronology().centuryOfEra());
1042        }
1043    
1044        /**
1045         * Get the year of century property.
1046         * 
1047         * @return the year of era property
1048         */
1049        public Property yearOfCentury() {
1050            return new Property(this, getChronology().yearOfCentury());
1051        }
1052    
1053        /**
1054         * Get the year of era property.
1055         * 
1056         * @return the year of era property
1057         */
1058        public Property yearOfEra() {
1059            return new Property(this, getChronology().yearOfEra());
1060        }
1061    
1062        /**
1063         * Get the year property.
1064         * 
1065         * @return the year property
1066         */
1067        public Property year() {
1068            return new Property(this, getChronology().year());
1069        }
1070    
1071        /**
1072         * Get the year of a week based year property.
1073         * 
1074         * @return the year of a week based year property
1075         */
1076        public Property weekyear() {
1077            return new Property(this, getChronology().weekyear());
1078        }
1079    
1080        /**
1081         * Get the month of year property.
1082         * 
1083         * @return the month of year property
1084         */
1085        public Property monthOfYear() {
1086            return new Property(this, getChronology().monthOfYear());
1087        }
1088    
1089        /**
1090         * Get the week of a week based year property.
1091         * 
1092         * @return the week of a week based year property
1093         */
1094        public Property weekOfWeekyear() {
1095            return new Property(this, getChronology().weekOfWeekyear());
1096        }
1097    
1098        /**
1099         * Get the day of year property.
1100         * 
1101         * @return the day of year property
1102         */
1103        public Property dayOfYear() {
1104            return new Property(this, getChronology().dayOfYear());
1105        }
1106    
1107        /**
1108         * Get the day of month property.
1109         * <p>
1110         * The values for day of month are defined in {@link DateTimeConstants}.
1111         * 
1112         * @return the day of month property
1113         */
1114        public Property dayOfMonth() {
1115            return new Property(this, getChronology().dayOfMonth());
1116        }
1117    
1118        /**
1119         * Get the day of week property.
1120         * <p>
1121         * The values for day of week are defined in {@link DateTimeConstants}.
1122         * 
1123         * @return the day of week property
1124         */
1125        public Property dayOfWeek() {
1126            return new Property(this, getChronology().dayOfWeek());
1127        }
1128    
1129        //-----------------------------------------------------------------------
1130        /**
1131         * Get the hour of day field property
1132         * 
1133         * @return the hour of day property
1134         */
1135        public Property hourOfDay() {
1136            return new Property(this, getChronology().hourOfDay());
1137        }
1138    
1139        /**
1140         * Get the minute of day property
1141         * 
1142         * @return the minute of day property
1143         */
1144        public Property minuteOfDay() {
1145            return new Property(this, getChronology().minuteOfDay());
1146        }
1147    
1148        /**
1149         * Get the minute of hour field property
1150         * 
1151         * @return the minute of hour property
1152         */
1153        public Property minuteOfHour() {
1154            return new Property(this, getChronology().minuteOfHour());
1155        }
1156    
1157        /**
1158         * Get the second of day property
1159         * 
1160         * @return the second of day property
1161         */
1162        public Property secondOfDay() {
1163            return new Property(this, getChronology().secondOfDay());
1164        }
1165    
1166        /**
1167         * Get the second of minute field property
1168         * 
1169         * @return the second of minute property
1170         */
1171        public Property secondOfMinute() {
1172            return new Property(this, getChronology().secondOfMinute());
1173        }
1174    
1175        /**
1176         * Get the millis of day property
1177         * 
1178         * @return the millis of day property
1179         */
1180        public Property millisOfDay() {
1181            return new Property(this, getChronology().millisOfDay());
1182        }
1183    
1184        /**
1185         * Get the millis of second property
1186         * 
1187         * @return the millis of second property
1188         */
1189        public Property millisOfSecond() {
1190            return new Property(this, getChronology().millisOfSecond());
1191        }
1192    
1193        //-----------------------------------------------------------------------
1194        /**
1195         * Clone this object without having to cast the returned object.
1196         *
1197         * @return a clone of the this object.
1198         */
1199        public MutableDateTime copy() {
1200            return (MutableDateTime) clone();
1201        }
1202    
1203        //-----------------------------------------------------------------------
1204        /**
1205         * Clone this object.
1206         *
1207         * @return a clone of this object.
1208         */
1209        public Object clone() {
1210            try {
1211                return super.clone();
1212            } catch (CloneNotSupportedException ex) {
1213                throw new InternalError("Clone error");
1214            }
1215        }
1216    
1217        /**
1218         * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
1219         * 
1220         * @return ISO8601 time formatted string.
1221         */
1222        @ToString
1223        public String toString() {
1224            return ISODateTimeFormat.dateTime().print(this);
1225        }
1226    
1227        /**
1228         * MutableDateTime.Property binds a MutableDateTime to a
1229         * DateTimeField allowing powerful datetime functionality to be easily
1230         * accessed.
1231         * <p>
1232         * The example below shows how to use the property to change the value of a
1233         * MutableDateTime object.
1234         * <pre>
1235         * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123);
1236         * dt.year().add(20);
1237         * dt.second().roundFloor().minute().set(10);
1238         * </pre>
1239         * <p>
1240         * MutableDateTime.Propery itself is thread-safe and immutable, but the
1241         * MutableDateTime being operated on is not.
1242         *
1243         * @author Stephen Colebourne
1244         * @author Brian S O'Neill
1245         * @since 1.0
1246         */
1247        public static final class Property extends AbstractReadableInstantFieldProperty {
1248            
1249            /** Serialization version */
1250            private static final long serialVersionUID = -4481126543819298617L;
1251            
1252            /** The instant this property is working against */
1253            private MutableDateTime iInstant;
1254            /** The field this property is working against */
1255            private DateTimeField iField;
1256            
1257            /**
1258             * Constructor.
1259             * 
1260             * @param instant  the instant to set
1261             * @param field  the field to use
1262             */
1263            Property(MutableDateTime instant, DateTimeField field) {
1264                super();
1265                iInstant = instant;
1266                iField = field;
1267            }
1268            
1269            /**
1270             * Writes the property in a safe serialization format.
1271             */
1272            private void writeObject(ObjectOutputStream oos) throws IOException {
1273                oos.writeObject(iInstant);
1274                oos.writeObject(iField.getType());
1275            }
1276    
1277            /**
1278             * Reads the property from a safe serialization format.
1279             */
1280            private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
1281                iInstant = (MutableDateTime) oos.readObject();
1282                DateTimeFieldType type = (DateTimeFieldType) oos.readObject();
1283                iField = type.getField(iInstant.getChronology());
1284            }
1285    
1286            //-----------------------------------------------------------------------
1287            /**
1288             * Gets the field being used.
1289             * 
1290             * @return the field
1291             */
1292            public DateTimeField getField() {
1293                return iField;
1294            }
1295            
1296            /**
1297             * Gets the milliseconds of the datetime that this property is linked to.
1298             * 
1299             * @return the milliseconds
1300             */
1301            protected long getMillis() {
1302                return iInstant.getMillis();
1303            }
1304            
1305            /**
1306             * Gets the chronology of the datetime that this property is linked to.
1307             * 
1308             * @return the chronology
1309             * @since 1.4
1310             */
1311            protected Chronology getChronology() {
1312                return iInstant.getChronology();
1313            }
1314            
1315            /**
1316             * Gets the mutable datetime being used.
1317             * 
1318             * @return the mutable datetime
1319             */
1320            public MutableDateTime getMutableDateTime() {
1321                return iInstant;
1322            }
1323            
1324            //-----------------------------------------------------------------------
1325            /**
1326             * Adds a value to the millis value.
1327             * 
1328             * @param value  the value to add
1329             * @return the mutable datetime being used, so calls can be chained
1330             * @see DateTimeField#add(long,int)
1331             */
1332            public MutableDateTime add(int value) {
1333                iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1334                return iInstant;
1335            }
1336            
1337            /**
1338             * Adds a value to the millis value.
1339             * 
1340             * @param value  the value to add
1341             * @return the mutable datetime being used, so calls can be chained
1342             * @see DateTimeField#add(long,long)
1343             */
1344            public MutableDateTime add(long value) {
1345                iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1346                return iInstant;
1347            }
1348            
1349            /**
1350             * Adds a value, possibly wrapped, to the millis value.
1351             * 
1352             * @param value  the value to add
1353             * @return the mutable datetime being used, so calls can be chained
1354             * @see DateTimeField#addWrapField
1355             */
1356            public MutableDateTime addWrapField(int value) {
1357                iInstant.setMillis(getField().addWrapField(iInstant.getMillis(), value));
1358                return iInstant;
1359            }
1360            
1361            //-----------------------------------------------------------------------
1362            /**
1363             * Sets a value.
1364             * 
1365             * @param value  the value to set.
1366             * @return the mutable datetime being used, so calls can be chained
1367             * @see DateTimeField#set(long,int)
1368             */
1369            public MutableDateTime set(int value) {
1370                iInstant.setMillis(getField().set(iInstant.getMillis(), value));
1371                return iInstant;
1372            }
1373            
1374            /**
1375             * Sets a text value.
1376             * 
1377             * @param text  the text value to set
1378             * @param locale  optional locale to use for selecting a text symbol
1379             * @return the mutable datetime being used, so calls can be chained
1380             * @throws IllegalArgumentException if the text value isn't valid
1381             * @see DateTimeField#set(long,java.lang.String,java.util.Locale)
1382             */
1383            public MutableDateTime set(String text, Locale locale) {
1384                iInstant.setMillis(getField().set(iInstant.getMillis(), text, locale));
1385                return iInstant;
1386            }
1387            
1388            /**
1389             * Sets a text value.
1390             * 
1391             * @param text  the text value to set
1392             * @return the mutable datetime being used, so calls can be chained
1393             * @throws IllegalArgumentException if the text value isn't valid
1394             * @see DateTimeField#set(long,java.lang.String)
1395             */
1396            public MutableDateTime set(String text) {
1397                set(text, null);
1398                return iInstant;
1399            }
1400            
1401            //-----------------------------------------------------------------------
1402            /**
1403             * Round to the lowest whole unit of this field.
1404             *
1405             * @return the mutable datetime being used, so calls can be chained
1406             * @see DateTimeField#roundFloor
1407             */
1408            public MutableDateTime roundFloor() {
1409                iInstant.setMillis(getField().roundFloor(iInstant.getMillis()));
1410                return iInstant;
1411            }
1412    
1413            /**
1414             * Round to the highest whole unit of this field.
1415             *
1416             * @return the mutable datetime being used, so calls can be chained
1417             * @see DateTimeField#roundCeiling
1418             */
1419            public MutableDateTime roundCeiling() {
1420                iInstant.setMillis(getField().roundCeiling(iInstant.getMillis()));
1421                return iInstant;
1422            }
1423            
1424            /**
1425             * Round to the nearest whole unit of this field, favoring the floor if
1426             * halfway.
1427             *
1428             * @return the mutable datetime being used, so calls can be chained
1429             * @see DateTimeField#roundHalfFloor
1430             */
1431            public MutableDateTime roundHalfFloor() {
1432                iInstant.setMillis(getField().roundHalfFloor(iInstant.getMillis()));
1433                return iInstant;
1434            }
1435            
1436            /**
1437             * Round to the nearest whole unit of this field, favoring the ceiling if
1438             * halfway.
1439             *
1440             * @return the mutable datetime being used, so calls can be chained
1441             * @see DateTimeField#roundHalfCeiling
1442             */
1443            public MutableDateTime roundHalfCeiling() {
1444                iInstant.setMillis(getField().roundHalfCeiling(iInstant.getMillis()));
1445                return iInstant;
1446            }
1447    
1448            /**
1449             * Round to the nearest whole unit of this field. If halfway, the ceiling
1450             * is favored over the floor only if it makes this field's value even.
1451             *
1452             * @return the mutable datetime being used, so calls can be chained
1453             * @see DateTimeField#roundHalfEven
1454             */
1455            public MutableDateTime roundHalfEven() {
1456                iInstant.setMillis(getField().roundHalfEven(iInstant.getMillis()));
1457                return iInstant;
1458            }
1459        }
1460    
1461    }