gt:         return new Property(this, getChronology().dayOfWeek());
context: /*
   *  Copyright 2001-2013 Stephen Colebourne
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  package org.joda.time;
  
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serializable;
  import java.util.Locale;
  
  import org.joda.convert.FromString;
  import org.joda.convert.ToString;
  import org.joda.time.base.BaseDateTime;
  import org.joda.time.chrono.ISOChronology;
  import org.joda.time.field.AbstractReadableInstantFieldProperty;
  import org.joda.time.field.FieldUtils;
  import org.joda.time.format.DateTimeFormatter;
  import org.joda.time.format.ISODateTimeFormat;
  
  /**
   * MutableDateTime is the standard implementation of a modifiable datetime class.
   * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
   * <p>
   * This class uses a Chronology internally. The Chronology determines how the
   * millisecond instant value is converted into the date time fields.
   * The default Chronology is <code>ISOChronology</code> which is the agreed
   * international standard and compatible with the modern Gregorian calendar.
   * <p>
   * Each individual field can be accessed in two ways:
   * <ul>
   * <li><code>getHourOfDay()</code>
   * <li><code>hourOfDay().get()</code>
   * </ul>
   * The second technique also provides access to other useful methods on the
   * field:
   * <ul>
   * <li>get numeric value
   * <li>set numeric value
   * <li>add to numeric value
   * <li>add to numeric value wrapping with the field
   * <li>get text value
   * <li>get short text value
   * <li>set text value
   * <li>field maximum value
   * <li>field minimum value
   * </ul>
   *
   * <p>
   * MutableDateTime is mutable and not thread-safe, unless concurrent threads
   * are not invoking mutator methods.
   *
   * @author Guy Allard
   * @author Brian S O'Neill
   * @author Stephen Colebourne
   * @author Mike Schrag
   * @since 1.0
   * @see DateTime
   */
  public class MutableDateTime
          extends BaseDateTime
          implements ReadWritableDateTime, Cloneable, Serializable {
  
      /** Serialization version */
      private static final long serialVersionUID = 2852608688135209575L;
  
      /** Rounding is disabled */
      public static final int ROUND_NONE = 0;
      /** Rounding mode as described by {@link DateTimeField#roundFloor} */
      public static final int ROUND_FLOOR = 1;
      /** Rounding mode as described by {@link DateTimeField#roundCeiling} */
      public static final int ROUND_CEILING = 2;
      /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */
      public static final int ROUND_HALF_FLOOR = 3;
      /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */
      public static final int ROUND_HALF_CEILING = 4;
      /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */
      public static final int ROUND_HALF_EVEN = 5;
  
      /** The field to round on */
      private DateTimeField iRoundingField;
      /** The mode of rounding */
      private int iRoundingMode;
  
      //-----------------------------------------------------------------------
      /**
       * Obtains a {@code MutableDateTime} set to the current system millisecond time
       * using <code>ISOChronology</code> in the default time zone.
       * 
       * @return the current date-time, not null
       * @since 2.0
       */
      public static MutableDateTime now() {
          return new MutableDateTime();
      }
  
      /**
       * Obtains a {@code MutableDateTime} set to the current system millisecond time
       * using <code>ISOChronology</code> in the specified time zone.
       *
       * @param zone  the time zone, not null
       * @return the current date-time, not null
       * @since 2.0
       */
      public static MutableDateTime now(DateTimeZone zone) {
          if (zone == null) {
              throw new NullPointerException("Zone must not be null");
          }
          return new MutableDateTime(zone);
      }
  
      /**
       * Obtains a {@code MutableDateTime} set to the current system millisecond time
       * using the specified chronology.
       *
       * @param chronology  the chronology, not null
       * @return the current date-time, not null
       * @since 2.0
       */
      public static MutableDateTime now(Chronology chronology) {
          if (chronology == null) {
              throw new NullPointerException("Chronology must not be null");
          }
          return new MutableDateTime(chronology);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Parses a {@code MutableDateTime} from the specified string.
       * <p>
       * This uses {@link ISODateTimeFormat#dateTimeParser()}.
       * 
       * @param str  the string to parse, not null
       * @since 2.0
       */
      @FromString
      public static MutableDateTime parse(String str) {
          return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed());
      }
  
      /**
       * Parses a {@code MutableDateTime} from the specified string using a formatter.
       * 
       * @param str  the string to parse, not null
       * @param formatter  the formatter to use, not null
       * @since 2.0
       */
      public static MutableDateTime parse(String str, DateTimeFormatter formatter) {
          return formatter.parseDateTime(str).toMutableDateTime();
      }
  
      //-----------------------------------------------------------------------
      /**
       * Constructs an instance set to the current system millisecond time
       * using <code>ISOChronology</code> in the default time zone.
       * 
       * @see #now()
       */
      public MutableDateTime() {
          super();
      }
  
      /**
       * Constructs an instance set to the current system millisecond time
       * using <code>ISOChronology</code> in the specified time zone.
       * <p>
       * If the specified time zone is null, the default zone is used.
       *
       * @param zone  the time zone, null means default zone
       * @see #now(DateTimeZone)
       */
      public MutableDateTime(DateTimeZone zone) {
          super(zone);
      }
  
      /**
       * Constructs an instance set to the current system millisecond time
       * using the specified chronology.
       * <p>
       * If the chronology is null, <code>ISOChronology</code>
       * in the default time zone is used.
       *
       * @param chronology  the chronology, null means ISOChronology in default zone
       * @see #now(Chronology)
       */
      public MutableDateTime(Chronology chronology) {
          super(chronology);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
       * using <code>ISOChronology</code> in the default time zone.
       *
       * @param instant  the milliseconds from 1970-01-01T00:00:00Z
       */
      public MutableDateTime(long instant) {
          super(instant);
      }
  
      /**
       * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
       * using <code>ISOChronology</code> in the specified time zone.
       * <p>
       * If the specified time zone is null, the default zone is used.
       *
       * @param instant  the milliseconds from 1970-01-01T00:00:00Z
       * @param zone  the time zone, null means default zone
       */
      public MutableDateTime(long instant, DateTimeZone zone) {
          super(instant, zone);
      }
  
      /**
       * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
       * using the specified chronology.
       * <p>
       * If the chronology is null, <code>ISOChronology</code>
       * in the default time zone is used.
       *
       * @param instant  the milliseconds from 1970-01-01T00:00:00Z
       * @param chronology  the chronology, null means ISOChronology in default zone
       */
      public MutableDateTime(long instant, Chronology chronology) {
          super(instant, chronology);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Constructs an instance from an Object that represents a datetime.
       * <p>
       * If the object implies a chronology (such as GregorianCalendar does),
       * then that chronology will be used. Otherwise, ISO default is used.
       * Thus if a GregorianCalendar is passed in, the chronology used will
       * be GJ, but if a Date is passed in the chronology will be ISO.
       * <p>
       * The recognised object types are defined in
       * {@link org.joda.time.convert.ConverterManager ConverterManager} and
       * include ReadableInstant, String, Calendar and Date.
       *
       * @param instant  the datetime object, null means now
       * @throws IllegalArgumentException if the instant is invalid
       */
      public MutableDateTime(Object instant) {
          super(instant, (Chronology) null);
      }
  
      /**
       * Constructs an instance from an Object that represents a datetime,
       * forcing the time zone to that specified.
       * <p>
       * If the object implies a chronology (such as GregorianCalendar does),
       * then that chronology will be used, but with the time zone adjusted.
       * Otherwise, ISO is used in the specified time zone.
       * If the specified time zone is null, the default zone is used.
       * Thus if a GregorianCalendar is passed in, the chronology used will
       * be GJ, but if a Date is passed in the chronology will be ISO.
       * <p>
       * The recognised object types are defined in
       * {@link org.joda.time.convert.ConverterManager ConverterManager} and
       * include ReadableInstant, String, Calendar and Date.
       *
       * @param instant  the datetime object, null means now
       * @param zone  the time zone, null means default time zone
       * @throws IllegalArgumentException if the instant is invalid
       */
      public MutableDateTime(Object instant, DateTimeZone zone) {
          super(instant, zone);
      }
  
      /**
       * Constructs an instance from an Object that represents a datetime,
       * using the specified chronology.
       * <p>
       * If the chronology is null, ISO in the default time zone is used.
       * Any chronology implied by the object (such as GregorianCalendar does)
       * is ignored.
       * <p>
       * The recognised object types are defined in
       * {@link org.joda.time.convert.ConverterManager ConverterManager} and
       * include ReadableInstant, String, Calendar and Date.
       *
       * @param instant  the datetime object, null means now
       * @param chronology  the chronology, null means ISOChronology in default zone
       * @throws IllegalArgumentException if the instant is invalid
       */
      public MutableDateTime(Object instant, Chronology chronology) {
          super(instant, DateTimeUtils.getChronology(chronology));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Constructs an instance from datetime field values
       * using <code>ISOChronology</code> in the default time zone.
       *
       * @param year  the year
       * @param monthOfYear  the month of the year
       * @param dayOfMonth  the day of the month
       * @param hourOfDay  the hour of the day
       * @param minuteOfHour  the minute of the hour
       * @param secondOfMinute  the second of the minute
       * @param millisOfSecond  the millisecond of the second
       */
      public MutableDateTime(
              int year,
              int monthOfYear,
              int dayOfMonth,
              int hourOfDay,
              int minuteOfHour,
              int secondOfMinute,
              int millisOfSecond) {
          super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
      }
  
      /**
       * Constructs an instance from datetime field values
       * using <code>ISOChronology</code> in the specified time zone.
       * <p>
       * If the specified time zone is null, the default zone is used.
       *
       * @param year  the year
       * @param monthOfYear  the month of the year
       * @param dayOfMonth  the day of the month
       * @param hourOfDay  the hour of the day
       * @param minuteOfHour  the minute of the hour
       * @param secondOfMinute  the second of the minute
       * @param millisOfSecond  the millisecond of the second
       * @param zone  the time zone, null means default time zone
       */
      public MutableDateTime(
              int year,
              int monthOfYear,
              int dayOfMonth,
              int hourOfDay,
              int minuteOfHour,
              int secondOfMinute,
              int millisOfSecond,
              DateTimeZone zone) {
          super(year, monthOfYear, dayOfMonth,
                hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
      }
  
      /**
       * Constructs an instance from datetime field values
       * using the specified chronology.
       * <p>
       * If the chronology is null, <code>ISOChronology</code>
       * in the default time zone is used.
       *
       * @param year  the year
       * @param monthOfYear  the month of the year
       * @param dayOfMonth  the day of the month
       * @param hourOfDay  the hour of the day
       * @param minuteOfHour  the minute of the hour
       * @param secondOfMinute  the second of the minute
       * @param millisOfSecond  the millisecond of the second
       * @param chronology  the chronology, null means ISOChronology in default zone
       */
      public MutableDateTime(
              int year,
              int monthOfYear,
              int dayOfMonth,
              int hourOfDay,
              int minuteOfHour,
              int secondOfMinute,
              int millisOfSecond,
              Chronology chronology) {
          super(year, monthOfYear, dayOfMonth,
                hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, chronology);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the field used for rounding this instant, returning null if rounding
       * is not enabled.
       * 
       * @return the rounding field
       */
      public DateTimeField getRoundingField() {
          return iRoundingField;
      }
  
      /**
       * Gets the rounding mode for this instant, returning ROUND_NONE if rounding
       * is not enabled.
       * 
       * @return the rounding mode constant
       */
      public int getRoundingMode() {
          return iRoundingMode;
      }
  
      /**
       * Sets the status of rounding to use the specified field and ROUND_FLOOR mode.
       * A null field will disable rounding.
       * Once set, the instant is then rounded using the new field and mode.
       * <p>
       * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
       * to be rounded. This can be used to control the precision of the instant,
       * for example by setting a rounding field of minuteOfDay, the seconds and
       * milliseconds will always be zero.
       *
       * @param field rounding field or null to disable
       */
      public void setRounding(DateTimeField field) {
          setRounding(field, MutableDateTime.ROUND_FLOOR);
      }
  
      /**
       * Sets the status of rounding to use the specified field and mode.
       * A null field or mode of ROUND_NONE will disable rounding.
       * Once set, the instant is then rounded using the new field and mode.
       * <p>
       * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
       * to be rounded. This can be used to control the precision of the instant,
       * for example by setting a rounding field of minuteOfDay, the seconds and
       * milliseconds will always be zero.
       *
       * @param field  rounding field or null to disable
       * @param mode  rounding mode or ROUND_NONE to disable
       * @throws IllegalArgumentException if mode is unknown, no exception if field is null
       */
      public void setRounding(DateTimeField field, int mode) {
          if (field != null && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) {
              throw new IllegalArgumentException("Illegal rounding mode: " + mode);
          }
          iRoundingField = (mode == ROUND_NONE ? null : field);
          iRoundingMode = (field == null ? ROUND_NONE : mode);
          setMillis(getMillis());
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the milliseconds of the datetime.
       * <p>
       * All changes to the millisecond field occurs via this method.
       *
       * @param instant  the milliseconds since 1970-01-01T00:00:00Z to set the
       * datetime to
       */
      public void setMillis(long instant) {
          switch (iRoundingMode) {
              case ROUND_NONE:
                  break;
              case ROUND_FLOOR:
                  instant = iRoundingField.roundFloor(instant);
                  break;
              case ROUND_CEILING:
                  instant = iRoundingField.roundCeiling(instant);
                  break;
              case ROUND_HALF_FLOOR:
                  instant = iRoundingField.roundHalfFloor(instant);
                  break;
              case ROUND_HALF_CEILING:
                  instant = iRoundingField.roundHalfCeiling(instant);
                  break;
              case ROUND_HALF_EVEN:
                  instant = iRoundingField.roundHalfEven(instant);
                  break;
          }
          super.setMillis(instant);
      }
  
      /**
       * Sets the millisecond instant of this instant from another.
       * <p>
       * This method does not change the chronology of this instant, just the
       * millisecond instant.
       * 
       * @param instant  the instant to use, null means now
       */
      public void setMillis(ReadableInstant instant) {
          long instantMillis = DateTimeUtils.getInstantMillis(instant);
          setMillis(instantMillis);  // set via this class not super
      }
  
      //-----------------------------------------------------------------------
      /**
       * Add an amount of time to the datetime.
       * 
       * @param duration  the millis to add
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(long duration) {
          setMillis(FieldUtils.safeAdd(getMillis(), duration));  // set via this class not super
      }
  
      /**
       * Adds a duration to this instant.
       * <p>
       * This will typically change the value of most fields.
       *
       * @param duration  the duration to add, null means add zero
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(ReadableDuration duration) {
          add(duration, 1);
      }
  
      /**
       * Adds a duration to this instant specifying how many times to add.
       * <p>
       * This will typically change the value of most fields.
       *
       * @param duration  the duration to add, null means add zero
       * @param scalar  direction and amount to add, which may be negative
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(ReadableDuration duration, int scalar) {
          if (duration != null) {
              add(FieldUtils.safeMultiply(duration.getMillis(), scalar));
          }
      }
  
      /**
       * Adds a period to this instant.
       * <p>
       * This will typically change the value of most fields.
       *
       * @param period  the period to add, null means add zero
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(ReadablePeriod period) {
          add(period, 1);
      }
  
      /**
       * Adds a period to this instant specifying how many times to add.
       * <p>
       * This will typically change the value of most fields.
       *
       * @param period  the period to add, null means add zero
       * @param scalar  direction and amount to add, which may be negative
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(ReadablePeriod period, int scalar) {
          if (period != null) {
              setMillis(getChronology().add(period, getMillis(), scalar));  // set via this class not super
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the chronology of the datetime.
       * <p>
       * All changes to the chronology occur via this method.
       * 
       * @param chronology  the chronology to use, null means ISOChronology in default zone
       */
      public void setChronology(Chronology chronology) {
          super.setChronology(chronology);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Sets the time zone of the datetime, changing the chronology and field values.
       * <p>
       * Changing the zone using this method retains the millisecond instant.
       * The millisecond instant is adjusted in the new zone to compensate.
       * 
       * chronology. Setting the time zone does not affect the millisecond value
       * of this instant.
       * <p>
       * If the chronology already has this time zone, no change occurs.
       *
       * @param newZone  the time zone to use, null means default zone
       * @see #setZoneRetainFields
       */
      public void setZone(DateTimeZone newZone) {
          newZone = DateTimeUtils.getZone(newZone);
          Chronology chrono = getChronology();
          if (chrono.getZone() != newZone) {
              setChronology(chrono.withZone(newZone));  // set via this class not super
          }
      }
  
      /**
       * Sets the time zone of the datetime, changing the chronology and millisecond.
       * <p>
       * Changing the zone using this method retains the field values.
       * The millisecond instant is adjusted in the new zone to compensate.
       * <p>
       * If the chronology already has this time zone, no change occurs.
       *
       * @param newZone  the time zone to use, null means default zone
       * @see #setZone
       */
      public void setZoneRetainFields(DateTimeZone newZone) {
          newZone = DateTimeUtils.getZone(newZone);
          DateTimeZone originalZone = DateTimeUtils.getZone(getZone());
          if (newZone == originalZone) {
              return;
          }
          
          long millis = originalZone.getMillisKeepLocal(newZone, getMillis());
          setChronology(getChronology().withZone(newZone));  // set via this class not super
          setMillis(millis);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Sets the value of one of the fields of the instant, such as hourOfDay.
       *
       * @param type  a field type, usually obtained from DateTimeFieldType, not null
       * @param value  the value to set the field to
       * @throws IllegalArgumentException if the value is null or invalid
       */
      public void set(DateTimeFieldType type, int value) {
          if (type == null) {
              throw new IllegalArgumentException("Field must not be null");
          }
          setMillis(type.getField(getChronology()).set(getMillis(), value));
      }
  
      /**
       * Adds to the instant specifying the duration and multiple to add.
       *
       * @param type  a field type, usually obtained from DateTimeFieldType, not null
       * @param amount  the amount to add of this duration
       * @throws IllegalArgumentException if the value is null or invalid
       * @throws ArithmeticException if the result exceeds the capacity of the instant
       */
      public void add(DurationFieldType type, int amount) {
          if (type == null) {
              throw new IllegalArgumentException("Field must not be null");
          }
          if (amount != 0) {
              setMillis(type.getField(getChronology()).add(getMillis(), amount));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the year to the specified value.
       *
       * @param year  the year
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setYear(final int year) {
          setMillis(getChronology().year().set(getMillis(), year));
      }
  
      /**
       * Add a number of years to the date.
       *
       * @param years  the years to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addYears(final int years) {
          if (years != 0) {
              setMillis(getChronology().years().add(getMillis(), years));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the weekyear to the specified value.
       *
       * @param weekyear  the weekyear
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setWeekyear(final int weekyear) {
          setMillis(getChronology().weekyear().set(getMillis(), weekyear));
      }
  
      /**
       * Add a number of weekyears to the date.
       *
       * @param weekyears  the weekyears to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addWeekyears(final int weekyears) {
          if (weekyears != 0) {
              setMillis(getChronology().weekyears().add(getMillis(), weekyears));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the month of the year to the specified value.
       *
       * @param monthOfYear  the month of the year
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setMonthOfYear(final int monthOfYear) {
          setMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear));
      }
  
      /**
       * Add a number of months to the date.
       *
       * @param months  the months to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addMonths(final int months) {
          if (months != 0) {
              setMillis(getChronology().months().add(getMillis(), months));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the week of weekyear to the specified value.
       *
       * @param weekOfWeekyear the week of the weekyear
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setWeekOfWeekyear(final int weekOfWeekyear) {
          setMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear));
      }
  
      /**
       * Add a number of weeks to the date.
       *
       * @param weeks  the weeks to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addWeeks(final int weeks) {
          if (weeks != 0) {
              setMillis(getChronology().weeks().add(getMillis(), weeks));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the day of year to the specified value.
       *
       * @param dayOfYear the day of the year
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDayOfYear(final int dayOfYear) {
          setMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear));
      }
  
      /**
       * Set the day of the month to the specified value.
       *
       * @param dayOfMonth  the day of the month
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDayOfMonth(final int dayOfMonth) {
          setMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth));
      }
  
      /**
       * Set the day of week to the specified value.
       *
       * @param dayOfWeek  the day of the week
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDayOfWeek(final int dayOfWeek) {
          setMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek));
      }
  
      /**
       * Add a number of days to the date.
       *
       * @param days  the days to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addDays(final int days) {
          if (days != 0) {
              setMillis(getChronology().days().add(getMillis(), days));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the hour of the day to the specified value.
       *
       * @param hourOfDay  the hour of day
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setHourOfDay(final int hourOfDay) {
          setMillis(getChronology().hourOfDay().set(getMillis(), hourOfDay));
      }
  
      /**
       * Add a number of hours to the date.
       *
       * @param hours  the hours to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addHours(final int hours) {
          if (hours != 0) {
              setMillis(getChronology().hours().add(getMillis(), hours));
          }
      }
      
      //-----------------------------------------------------------------------
      /**
       * Set the minute of the day to the specified value.
       *
       * @param minuteOfDay  the minute of day
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setMinuteOfDay(final int minuteOfDay) {
          setMillis(getChronology().minuteOfDay().set(getMillis(), minuteOfDay));
      }
  
      /**
       * Set the minute of the hour to the specified value.
       *
       * @param minuteOfHour  the minute of hour
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setMinuteOfHour(final int minuteOfHour) {
          setMillis(getChronology().minuteOfHour().set(getMillis(), minuteOfHour));
      }
  
      /**
       * Add a number of minutes to the date.
       *
       * @param minutes  the minutes to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addMinutes(final int minutes) {
          if (minutes != 0) {
              setMillis(getChronology().minutes().add(getMillis(), minutes));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the second of the day to the specified value.
       *
       * @param secondOfDay  the second of day
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setSecondOfDay(final int secondOfDay) {
          setMillis(getChronology().secondOfDay().set(getMillis(), secondOfDay));
      }
  
      /**
       * Set the second of the minute to the specified value.
       *
       * @param secondOfMinute  the second of minute
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setSecondOfMinute(final int secondOfMinute) {
          setMillis(getChronology().secondOfMinute().set(getMillis(), secondOfMinute));
      }
  
      /**
       * Add a number of seconds to the date.
       *
       * @param seconds  the seconds to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addSeconds(final int seconds) {
          if (seconds != 0) {
              setMillis(getChronology().seconds().add(getMillis(), seconds));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the millis of the day to the specified value.
       *
       * @param millisOfDay  the millis of day
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setMillisOfDay(final int millisOfDay) {
          setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
      }
  
      /**
       * Set the millis of the second to the specified value.
       *
       * @param millisOfSecond  the millis of second
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setMillisOfSecond(final int millisOfSecond) {
          setMillis(getChronology().millisOfSecond().set(getMillis(), millisOfSecond));
      }
  
      /**
       * Add a number of milliseconds to the date. The implementation of this
       * method differs from the {@link #add(long)} method in that a
       * DateTimeField performs the addition.
       *
       * @param millis  the milliseconds to add
       * @throws IllegalArgumentException if the value is invalid
       */
      public void addMillis(final int millis) {
          if (millis != 0) {
              setMillis(getChronology().millis().add(getMillis(), millis));
          }
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the date from milliseconds.
       * The time part of this object will be unaffected.
       *
       * @param instant  an instant to copy the date from, time part ignored
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDate(final long instant) {
          setMillis(getChronology().millisOfDay().set(instant, getMillisOfDay()));
      }
  
      /**
       * Set the date from another instant.
       * The time part of this object will be unaffected.
       * <p>
       * If the input is a {@code ReadableDateTime} then it is converted to the
       * same time-zone as this object before using the instant millis.
       *
       * @param instant  an instant to copy the date from, time part ignored
       * @throws IllegalArgumentException if the object is invalid
       */
      public void setDate(final ReadableInstant instant) {
          long instantMillis = DateTimeUtils.getInstantMillis(instant);
          if (instant instanceof ReadableDateTime) {
              ReadableDateTime rdt = (ReadableDateTime) instant;
              Chronology instantChrono = DateTimeUtils.getChronology(rdt.getChronology());
              DateTimeZone zone = instantChrono.getZone();
              if (zone != null) {
                  instantMillis = zone.getMillisKeepLocal(getZone(), instantMillis);
              }
          }
          setDate(instantMillis);
      }
  
      /**
       * Set the date from fields.
       * The time part of this object will be unaffected.
       *
       * @param year  the year
       * @param monthOfYear  the month of the year
       * @param dayOfMonth  the day of the month
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDate(
              final int year,
              final int monthOfYear,
              final int dayOfMonth) {
          Chronology c = getChronology();
          long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0);
          setDate(instantMidnight);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Set the time from milliseconds.
       * The date part of this object will be unaffected.
       *
       * @param millis  an instant to copy the time from, date part ignored
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setTime(final long millis) {
          int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis);
          setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay));
      }
  
      /**
       * Set the time from another instant.
       * The date part of this object will be unaffected.
       *
       * @param instant  an instant to copy the time from, date part ignored
       * @throws IllegalArgumentException if the object is invalid
       */
      public void setTime(final ReadableInstant instant) {
          long instantMillis = DateTimeUtils.getInstantMillis(instant);
          Chronology instantChrono = DateTimeUtils.getInstantChronology(instant);
          DateTimeZone zone = instantChrono.getZone();
          if (zone != null) {
              instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis);
          }
          setTime(instantMillis);
      }
  
      /**
       * Set the time from fields.
       * The date part of this object will be unaffected.
       *
       * @param hour  the hour
       * @param minuteOfHour  the minute of the hour
       * @param secondOfMinute  the second of the minute
       * @param millisOfSecond  the millisecond of the second
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setTime(
              final int hour,
              final int minuteOfHour,
              final int secondOfMinute,
              final int millisOfSecond) {
          long instant = getChronology().getDateTimeMillis(
              getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond);
          setMillis(instant);
      }
  
      /**
       * Set the date and time from fields.
       *
       * @param year  the year
       * @param monthOfYear  the month of the year
       * @param dayOfMonth  the day of the month
       * @param hourOfDay  the hour of the day
       * @param minuteOfHour  the minute of the hour
       * @param secondOfMinute  the second of the minute
       * @param millisOfSecond  the millisecond of the second
       * @throws IllegalArgumentException if the value is invalid
       */
      public void setDateTime(
              final int year,
              final int monthOfYear,
              final int dayOfMonth,
              final int hourOfDay,
              final int minuteOfHour,
              final int secondOfMinute,
              final int millisOfSecond) {
          long instant = getChronology().getDateTimeMillis(
              year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
          setMillis(instant);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the property object for the specified type, which contains many useful methods.
       *
       * @param type  the field type to get the chronology for
       * @return the property object
       * @throws IllegalArgumentException if the field is null or unsupported
       * @since 1.2
       */
      public Property property(DateTimeFieldType type) {
          if (type == null) {
              throw new IllegalArgumentException("The DateTimeFieldType must not be null");
          }
          DateTimeField field = type.getField(getChronology());
          if (field.isSupported() == false) {
              throw new IllegalArgumentException("Field '" + type + "' is not supported");
          }
          return new Property(this, field);
      }
  
      /**
       * Get the era property.
       * 
       * @return the era property
       */
      public Property era() {
          return new Property(this, getChronology().era());
      }
  
      /**
       * Get the century of era property.
       * 
       * @return the year of era property
       */
      public Property centuryOfEra() {
          return new Property(this, getChronology().centuryOfEra());
      }
  
      /**
       * Get the year of century property.
       * 
       * @return the year of era property
       */
      public Property yearOfCentury() {
          return new Property(this, getChronology().yearOfCentury());
      }
  
      /**
       * Get the year of era property.
       * 
       * @return the year of era property
       */
      public Property yearOfEra() {
          return new Property(this, getChronology().yearOfEra());
      }
  
      /**
       * Get the year property.
       * 
       * @return the year property
       */
      public Property year() {
          return new Property(this, getChronology().year());
      }
  
      /**
       * Get the year of a week based year property.
       * 
       * @return the year of a week based year property
       */
      public Property weekyear() {
          return new Property(this, getChronology().weekyear());
      }
  
      /**
       * Get the month of year property.
       * 
       * @return the month of year property
       */
      public Property monthOfYear() {
          return new Property(this, getChronology().monthOfYear());
      }
  
      /**
       * Get the week of a week based year property.
       * 
       * @return the week of a week based year property
       */
      public Property weekOfWeekyear() {
          return new Property(this, getChronology().weekOfWeekyear());
      }
  
      /**
       * Get the day of year property.
       * 
       * @return the day of year property
       */
      public Property dayOfYear() {
          return new Property(this, getChronology().dayOfYear());
      }
  
      /**
       * Get the day of month property.
       * <p>
       * The values for day of month are defined in {@link DateTimeConstants}.
       * 
       * @return the day of month property
       */
      public Property dayOfMonth() {
          return new Property(this, getChronology().dayOfMonth());
      }
  
      /**
       * Get the day of week property.
       * <p>
       * The values for day of week are defined in {@link DateTimeConstants}.
       * 
       * @return the day of week property
       */
      public Property dayOfWeek() {
  