View Javadoc

1   /*
2    *  Copyright 2001-2010 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time;
17  
18  import java.io.IOException;
19  import java.io.ObjectInputStream;
20  import java.io.ObjectOutputStream;
21  import java.io.Serializable;
22  import java.util.Locale;
23  
24  import org.joda.convert.FromString;
25  import org.joda.convert.ToString;
26  import org.joda.time.base.BaseDateTime;
27  import org.joda.time.chrono.ISOChronology;
28  import org.joda.time.field.AbstractReadableInstantFieldProperty;
29  import org.joda.time.field.FieldUtils;
30  import org.joda.time.format.DateTimeFormatter;
31  import org.joda.time.format.ISODateTimeFormat;
32  
33  /**
34   * MutableDateTime is the standard implementation of a modifiable datetime class.
35   * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
36   * <p>
37   * This class uses a Chronology internally. The Chronology determines how the
38   * millisecond instant value is converted into the date time fields.
39   * The default Chronology is <code>ISOChronology</code> which is the agreed
40   * international standard and compatible with the modern Gregorian calendar.
41   * <p>
42   * Each individual field can be accessed in two ways:
43   * <ul>
44   * <li><code>getHourOfDay()</code>
45   * <li><code>hourOfDay().get()</code>
46   * </ul>
47   * The second technique also provides access to other useful methods on the
48   * field:
49   * <ul>
50   * <li>get numeric value
51   * <li>set numeric value
52   * <li>add to numeric value
53   * <li>add to numeric value wrapping with the field
54   * <li>get text value
55   * <li>get short text value
56   * <li>set text value
57   * <li>field maximum value
58   * <li>field minimum value
59   * </ul>
60   *
61   * <p>
62   * MutableDateTime is mutable and not thread-safe, unless concurrent threads
63   * are not invoking mutator methods.
64   *
65   * @author Guy Allard
66   * @author Brian S O'Neill
67   * @author Stephen Colebourne
68   * @author Mike Schrag
69   * @since 1.0
70   * @see DateTime
71   */
72  public class MutableDateTime
73          extends BaseDateTime
74          implements ReadWritableDateTime, Cloneable, Serializable {
75  
76      /** Serialization version */
77      private static final long serialVersionUID = 2852608688135209575L;
78  
79      /** Rounding is disabled */
80      public static final int ROUND_NONE = 0;
81      /** Rounding mode as described by {@link DateTimeField#roundFloor} */
82      public static final int ROUND_FLOOR = 1;
83      /** Rounding mode as described by {@link DateTimeField#roundCeiling} */
84      public static final int ROUND_CEILING = 2;
85      /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */
86      public static final int ROUND_HALF_FLOOR = 3;
87      /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */
88      public static final int ROUND_HALF_CEILING = 4;
89      /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */
90      public static final int ROUND_HALF_EVEN = 5;
91  
92      /** The field to round on */
93      private DateTimeField iRoundingField;
94      /** The mode of rounding */
95      private int iRoundingMode;
96  
97      //-----------------------------------------------------------------------
98      /**
99       * 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      * <p>
900      * If the input is a {@code ReadableDateTime} then it is converted to the
901      * same time-zone as this object before using the instant millis.
902      *
903      * @param instant  an instant to copy the date from, time part ignored
904      * @throws IllegalArgumentException if the object is invalid
905      */
906     public void setDate(final ReadableInstant instant) {
907         long instantMillis = DateTimeUtils.getInstantMillis(instant);
908         if (instant instanceof ReadableDateTime) {
909             ReadableDateTime rdt = (ReadableDateTime) instant;
910             Chronology instantChrono = DateTimeUtils.getChronology(rdt.getChronology());
911             DateTimeZone zone = instantChrono.getZone();
912             if (zone != null) {
913                 instantMillis = zone.getMillisKeepLocal(getZone(), instantMillis);
914             }
915         }
916         setDate(instantMillis);
917     }
918 
919     /**
920      * Set the date from fields.
921      * The time part of this object will be unaffected.
922      *
923      * @param year  the year
924      * @param monthOfYear  the month of the year
925      * @param dayOfMonth  the day of the month
926      * @throws IllegalArgumentException if the value is invalid
927      */
928     public void setDate(
929             final int year,
930             final int monthOfYear,
931             final int dayOfMonth) {
932         Chronology c = getChronology();
933         long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0);
934         setDate(instantMidnight);
935     }
936 
937     //-----------------------------------------------------------------------
938     /**
939      * Set the time from milliseconds.
940      * The date part of this object will be unaffected.
941      *
942      * @param millis  an instant to copy the time from, date part ignored
943      * @throws IllegalArgumentException if the value is invalid
944      */
945     public void setTime(final long millis) {
946         int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis);
947         setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
948     }
949 
950     /**
951      * Set the time from another instant.
952      * The date part of this object will be unaffected.
953      *
954      * @param instant  an instant to copy the time from, date part ignored
955      * @throws IllegalArgumentException if the object is invalid
956      */
957     public void setTime(final ReadableInstant instant) {
958         long instantMillis = DateTimeUtils.getInstantMillis(instant);
959         Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
960         DateTimeZone zone = instantChrono.getZone();
961         if (zone != null) {
962             instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
963         }
964         setTime(instantMillis);
965     }
966 
967     /**
968      * Set the time from fields.
969      * The date part of this object will be unaffected.
970      *
971      * @param hour  the hour
972      * @param minuteOfHour  the minute of the hour
973      * @param secondOfMinute  the second of the minute
974      * @param millisOfSecond  the millisecond of the second
975      * @throws IllegalArgumentException if the value is invalid
976      */
977     public void setTime(
978             final int hour,
979             final int minuteOfHour,
980             final int secondOfMinute,
981             final int millisOfSecond) {
982         long instant = getChronology().getDateTimeMillis(
983             getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond);
984         setMillis(instant);
985     }
986 
987     /**
988      * Set the date and time from fields.
989      *
990      * @param year  the year
991      * @param monthOfYear  the month of the year
992      * @param dayOfMonth  the day of the month
993      * @param hourOfDay  the hour of the day
994      * @param minuteOfHour  the minute of the hour
995      * @param secondOfMinute  the second of the minute
996      * @param millisOfSecond  the millisecond of the second
997      * @throws IllegalArgumentException if the value is invalid
998      */
999     public void setDateTime(
1000             final int year,
1001             final int monthOfYear,
1002             final int dayOfMonth,
1003             final int hourOfDay,
1004             final int minuteOfHour,
1005             final int secondOfMinute,
1006             final int millisOfSecond) {
1007         long instant = getChronology().getDateTimeMillis(
1008             year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
1009         setMillis(instant);
1010     }
1011 
1012     //-----------------------------------------------------------------------
1013     /**
1014      * Gets the property object for the specified type, which contains many useful methods.
1015      *
1016      * @param type  the field type to get the chronology for
1017      * @return the property object
1018      * @throws IllegalArgumentException if the field is null or unsupported
1019      * @since 1.2
1020      */
1021     public Property property(DateTimeFieldType type) {
1022         if (type == null) {
1023             throw new IllegalArgumentException("The DateTimeFieldType must not be null");
1024         }
1025         DateTimeField field = type.getField(getChronology());
1026         if (field.isSupported() == false) {
1027             throw new IllegalArgumentException("Field '" + type + "' is not supported");
1028         }
1029         return new Property(this, field);
1030     }
1031 
1032     /**
1033      * Get the era property.
1034      * 
1035      * @return the era property
1036      */
1037     public Property era() {
1038         return new Property(this, getChronology().era());
1039     }
1040 
1041     /**
1042      * Get the century of era property.
1043      * 
1044      * @return the year of era property
1045      */
1046     public Property centuryOfEra() {
1047         return new Property(this, getChronology().centuryOfEra());
1048     }
1049 
1050     /**
1051      * Get the year of century property.
1052      * 
1053      * @return the year of era property
1054      */
1055     public Property yearOfCentury() {
1056         return new Property(this, getChronology().yearOfCentury());
1057     }
1058 
1059     /**
1060      * Get the year of era property.
1061      * 
1062      * @return the year of era property
1063      */
1064     public Property yearOfEra() {
1065         return new Property(this, getChronology().yearOfEra());
1066     }
1067 
1068     /**
1069      * Get the year property.
1070      * 
1071      * @return the year property
1072      */
1073     public Property year() {
1074         return new Property(this, getChronology().year());
1075     }
1076 
1077     /**
1078      * Get the year of a week based year property.
1079      * 
1080      * @return the year of a week based year property
1081      */
1082     public Property weekyear() {
1083         return new Property(this, getChronology().weekyear());
1084     }
1085 
1086     /**
1087      * Get the month of year property.
1088      * 
1089      * @return the month of year property
1090      */
1091     public Property monthOfYear() {
1092         return new Property(this, getChronology().monthOfYear());
1093     }
1094 
1095     /**
1096      * Get the week of a week based year property.
1097      * 
1098      * @return the week of a week based year property
1099      */
1100     public Property weekOfWeekyear() {
1101         return new Property(this, getChronology().weekOfWeekyear());
1102     }
1103 
1104     /**
1105      * Get the day of year property.
1106      * 
1107      * @return the day of year property
1108      */
1109     public Property dayOfYear() {
1110         return new Property(this, getChronology().dayOfYear());
1111     }
1112 
1113     /**
1114      * Get the day of month property.
1115      * <p>
1116      * The values for day of month are defined in {@link DateTimeConstants}.
1117      * 
1118      * @return the day of month property
1119      */
1120     public Property dayOfMonth() {
1121         return new Property(this, getChronology().dayOfMonth());
1122     }
1123 
1124     /**
1125      * Get the day of week property.
1126      * <p>
1127      * The values for day of week are defined in {@link DateTimeConstants}.
1128      * 
1129      * @return the day of week property
1130      */
1131     public Property dayOfWeek() {
1132         return new Property(this, getChronology().dayOfWeek());
1133     }
1134 
1135     //-----------------------------------------------------------------------
1136     /**
1137      * Get the hour of day field property
1138      * 
1139      * @return the hour of day property
1140      */
1141     public Property hourOfDay() {
1142         return new Property(this, getChronology().hourOfDay());
1143     }
1144 
1145     /**
1146      * Get the minute of day property
1147      * 
1148      * @return the minute of day property
1149      */
1150     public Property minuteOfDay() {
1151         return new Property(this, getChronology().minuteOfDay());
1152     }
1153 
1154     /**
1155      * Get the minute of hour field property
1156      * 
1157      * @return the minute of hour property
1158      */
1159     public Property minuteOfHour() {
1160         return new Property(this, getChronology().minuteOfHour());
1161     }
1162 
1163     /**
1164      * Get the second of day property
1165      * 
1166      * @return the second of day property
1167      */
1168     public Property secondOfDay() {
1169         return new Property(this, getChronology().secondOfDay());
1170     }
1171 
1172     /**
1173      * Get the second of minute field property
1174      * 
1175      * @return the second of minute property
1176      */
1177     public Property secondOfMinute() {
1178         return new Property(this, getChronology().secondOfMinute());
1179     }
1180 
1181     /**
1182      * Get the millis of day property
1183      * 
1184      * @return the millis of day property
1185      */
1186     public Property millisOfDay() {
1187         return new Property(this, getChronology().millisOfDay());
1188     }
1189 
1190     /**
1191      * Get the millis of second property
1192      * 
1193      * @return the millis of second property
1194      */
1195     public Property millisOfSecond() {
1196         return new Property(this, getChronology().millisOfSecond());
1197     }
1198 
1199     //-----------------------------------------------------------------------
1200     /**
1201      * Clone this object without having to cast the returned object.
1202      *
1203      * @return a clone of the this object.
1204      */
1205     public MutableDateTime copy() {
1206         return (MutableDateTime) clone();
1207     }
1208 
1209     //-----------------------------------------------------------------------
1210     /**
1211      * Clone this object.
1212      *
1213      * @return a clone of this object.
1214      */
1215     public Object clone() {
1216         try {
1217             return super.clone();
1218         } catch (CloneNotSupportedException ex) {
1219             throw new InternalError("Clone error");
1220         }
1221     }
1222 
1223     /**
1224      * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ).
1225      * 
1226      * @return ISO8601 time formatted string.
1227      */
1228     @ToString
1229     public String toString() {
1230         return ISODateTimeFormat.dateTime().print(this);
1231     }
1232 
1233     /**
1234      * MutableDateTime.Property binds a MutableDateTime to a
1235      * DateTimeField allowing powerful datetime functionality to be easily
1236      * accessed.
1237      * <p>
1238      * The example below shows how to use the property to change the value of a
1239      * MutableDateTime object.
1240      * <pre>
1241      * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123);
1242      * dt.year().add(20);
1243      * dt.second().roundFloor().minute().set(10);
1244      * </pre>
1245      * <p>
1246      * MutableDateTime.Propery itself is thread-safe and immutable, but the
1247      * MutableDateTime being operated on is not.
1248      *
1249      * @author Stephen Colebourne
1250      * @author Brian S O'Neill
1251      * @since 1.0
1252      */
1253     public static final class Property extends AbstractReadableInstantFieldProperty {
1254         
1255         /** Serialization version */
1256         private static final long serialVersionUID = -4481126543819298617L;
1257         
1258         /** The instant this property is working against */
1259         private MutableDateTime iInstant;
1260         /** The field this property is working against */
1261         private DateTimeField iField;
1262         
1263         /**
1264          * Constructor.
1265          * 
1266          * @param instant  the instant to set
1267          * @param field  the field to use
1268          */
1269         Property(MutableDateTime instant, DateTimeField field) {
1270             super();
1271             iInstant = instant;
1272             iField = field;
1273         }
1274         
1275         /**
1276          * Writes the property in a safe serialization format.
1277          */
1278         private void writeObject(ObjectOutputStream oos) throws IOException {
1279             oos.writeObject(iInstant);
1280             oos.writeObject(iField.getType());
1281         }
1282 
1283         /**
1284          * Reads the property from a safe serialization format.
1285          */
1286         private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
1287             iInstant = (MutableDateTime) oos.readObject();
1288             DateTimeFieldType type = (DateTimeFieldType) oos.readObject();
1289             iField = type.getField(iInstant.getChronology());
1290         }
1291 
1292         //-----------------------------------------------------------------------
1293         /**
1294          * Gets the field being used.
1295          * 
1296          * @return the field
1297          */
1298         public DateTimeField getField() {
1299             return iField;
1300         }
1301         
1302         /**
1303          * Gets the milliseconds of the datetime that this property is linked to.
1304          * 
1305          * @return the milliseconds
1306          */
1307         protected long getMillis() {
1308             return iInstant.getMillis();
1309         }
1310         
1311         /**
1312          * Gets the chronology of the datetime that this property is linked to.
1313          * 
1314          * @return the chronology
1315          * @since 1.4
1316          */
1317         protected Chronology getChronology() {
1318             return iInstant.getChronology();
1319         }
1320         
1321         /**
1322          * Gets the mutable datetime being used.
1323          * 
1324          * @return the mutable datetime
1325          */
1326         public MutableDateTime getMutableDateTime() {
1327             return iInstant;
1328         }
1329         
1330         //-----------------------------------------------------------------------
1331         /**
1332          * Adds a value to the millis value.
1333          * 
1334          * @param value  the value to add
1335          * @return the mutable datetime being used, so calls can be chained
1336          * @see DateTimeField#add(long,int)
1337          */
1338         public MutableDateTime add(int value) {
1339             iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1340             return iInstant;
1341         }
1342         
1343         /**
1344          * Adds a value to the millis value.
1345          * 
1346          * @param value  the value to add
1347          * @return the mutable datetime being used, so calls can be chained
1348          * @see DateTimeField#add(long,long)
1349          */
1350         public MutableDateTime add(long value) {
1351             iInstant.setMillis(getField().add(iInstant.getMillis(), value));
1352             return iInstant;
1353         }
1354         
1355         /**
1356          * Adds a value, possibly wrapped, to the millis value.
1357          * 
1358          * @param value  the value to add
1359          * @return the mutable datetime being used, so calls can be chained
1360          * @see DateTimeField#addWrapField
1361          */
1362         public MutableDateTime addWrapField(int value) {
1363             iInstant.setMillis(getField().addWrapField(iInstant.getMillis(), value));
1364             return iInstant;
1365         }
1366         
1367         //-----------------------------------------------------------------------
1368         /**
1369          * Sets a value.
1370          * 
1371          * @param value  the value to set.
1372          * @return the mutable datetime being used, so calls can be chained
1373          * @see DateTimeField#set(long,int)
1374          */
1375         public MutableDateTime set(int value) {
1376             iInstant.setMillis(getField().set(iInstant.getMillis(), value));
1377             return iInstant;
1378         }
1379         
1380         /**
1381          * Sets a text value.
1382          * 
1383          * @param text  the text value to set
1384          * @param locale  optional locale to use for selecting a text symbol
1385          * @return the mutable datetime being used, so calls can be chained
1386          * @throws IllegalArgumentException if the text value isn't valid
1387          * @see DateTimeField#set(long,java.lang.String,java.util.Locale)
1388          */
1389         public MutableDateTime set(String text, Locale locale) {
1390             iInstant.setMillis(getField().set(iInstant.getMillis(), text, locale));
1391             return iInstant;
1392         }
1393         
1394         /**
1395          * Sets a text value.
1396          * 
1397          * @param text  the text value to set
1398          * @return the mutable datetime being used, so calls can be chained
1399          * @throws IllegalArgumentException if the text value isn't valid
1400          * @see DateTimeField#set(long,java.lang.String)
1401          */
1402         public MutableDateTime set(String text) {
1403             set(text, null);
1404             return iInstant;
1405         }
1406         
1407         //-----------------------------------------------------------------------
1408         /**
1409          * Round to the lowest whole unit of this field.
1410          *
1411          * @return the mutable datetime being used, so calls can be chained
1412          * @see DateTimeField#roundFloor
1413          */
1414         public MutableDateTime roundFloor() {
1415             iInstant.setMillis(getField().roundFloor(iInstant.getMillis()));
1416             return iInstant;
1417         }
1418 
1419         /**
1420          * Round to the highest whole unit of this field.
1421          *
1422          * @return the mutable datetime being used, so calls can be chained
1423          * @see DateTimeField#roundCeiling
1424          */
1425         public MutableDateTime roundCeiling() {
1426             iInstant.setMillis(getField().roundCeiling(iInstant.getMillis()));
1427             return iInstant;
1428         }
1429         
1430         /**
1431          * Round to the nearest whole unit of this field, favoring the floor if
1432          * halfway.
1433          *
1434          * @return the mutable datetime being used, so calls can be chained
1435          * @see DateTimeField#roundHalfFloor
1436          */
1437         public MutableDateTime roundHalfFloor() {
1438             iInstant.setMillis(getField().roundHalfFloor(iInstant.getMillis()));
1439             return iInstant;
1440         }
1441         
1442         /**
1443          * Round to the nearest whole unit of this field, favoring the ceiling if
1444          * halfway.
1445          *
1446          * @return the mutable datetime being used, so calls can be chained
1447          * @see DateTimeField#roundHalfCeiling
1448          */
1449         public MutableDateTime roundHalfCeiling() {
1450             iInstant.setMillis(getField().roundHalfCeiling(iInstant.getMillis()));
1451             return iInstant;
1452         }
1453 
1454         /**
1455          * Round to the nearest whole unit of this field. If halfway, the ceiling
1456          * is favored over the floor only if it makes this field's value even.
1457          *
1458          * @return the mutable datetime being used, so calls can be chained
1459          * @see DateTimeField#roundHalfEven
1460          */
1461         public MutableDateTime roundHalfEven() {
1462             iInstant.setMillis(getField().roundHalfEven(iInstant.getMillis()));
1463             return iInstant;
1464         }
1465     }
1466 
1467 }