0001: /*
0002: * Copyright 2001-2005 Stephen Colebourne
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.joda.time;
0017:
0018: import java.io.IOException;
0019: import java.io.ObjectInputStream;
0020: import java.io.ObjectOutputStream;
0021: import java.io.Serializable;
0022: import java.util.Locale;
0023:
0024: import org.joda.time.base.BaseDateTime;
0025: import org.joda.time.chrono.ISOChronology;
0026: import org.joda.time.field.AbstractReadableInstantFieldProperty;
0027: import org.joda.time.field.FieldUtils;
0028: import org.joda.time.format.ISODateTimeFormat;
0029:
0030: /**
0031: * MutableDateTime is the standard implementation of a modifiable datetime class.
0032: * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z.
0033: * <p>
0034: * This class uses a Chronology internally. The Chronology determines how the
0035: * millisecond instant value is converted into the date time fields.
0036: * The default Chronology is <code>ISOChronology</code> which is the agreed
0037: * international standard and compatable with the modern Gregorian calendar.
0038: * <p>
0039: * Each individual field can be accessed in two ways:
0040: * <ul>
0041: * <li><code>getHourOfDay()</code>
0042: * <li><code>hourOfDay().get()</code>
0043: * </ul>
0044: * The second technique also provides access to other useful methods on the
0045: * field:
0046: * <ul>
0047: * <li>get numeric value
0048: * <li>set numeric value
0049: * <li>add to numeric value
0050: * <li>add to numeric value wrapping with the field
0051: * <li>get text vlaue
0052: * <li>get short text value
0053: * <li>set text value
0054: * <li>field maximum value
0055: * <li>field minimum value
0056: * </ul>
0057: *
0058: * <p>
0059: * MutableDateTime is mutable and not thread-safe, unless concurrent threads
0060: * are not invoking mutator methods.
0061: *
0062: * @author Guy Allard
0063: * @author Brian S O'Neill
0064: * @author Stephen Colebourne
0065: * @author Mike Schrag
0066: * @since 1.0
0067: * @see DateTime
0068: */
0069: public class MutableDateTime extends BaseDateTime implements
0070: ReadWritableDateTime, Cloneable, Serializable {
0071:
0072: /** Serialization version */
0073: private static final long serialVersionUID = 2852608688135209575L;
0074:
0075: /** Rounding is disabled */
0076: public static final int ROUND_NONE = 0;
0077: /** Rounding mode as described by {@link DateTimeField#roundFloor} */
0078: public static final int ROUND_FLOOR = 1;
0079: /** Rounding mode as described by {@link DateTimeField#roundCeiling} */
0080: public static final int ROUND_CEILING = 2;
0081: /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */
0082: public static final int ROUND_HALF_FLOOR = 3;
0083: /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */
0084: public static final int ROUND_HALF_CEILING = 4;
0085: /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */
0086: public static final int ROUND_HALF_EVEN = 5;
0087:
0088: /** The field to round on */
0089: private DateTimeField iRoundingField;
0090: /** The mode of rounding */
0091: private int iRoundingMode;
0092:
0093: //-----------------------------------------------------------------------
0094: /**
0095: * Constructs an instance set to the current system millisecond time
0096: * using <code>ISOChronology</code> in the default time zone.
0097: */
0098: public MutableDateTime() {
0099: super ();
0100: }
0101:
0102: /**
0103: * Constructs an instance set to the current system millisecond time
0104: * using <code>ISOChronology</code> in the specified time zone.
0105: * <p>
0106: * If the specified time zone is null, the default zone is used.
0107: *
0108: * @param zone the time zone, null means default zone
0109: */
0110: public MutableDateTime(DateTimeZone zone) {
0111: super (zone);
0112: }
0113:
0114: /**
0115: * Constructs an instance set to the current system millisecond time
0116: * using the specified chronology.
0117: * <p>
0118: * If the chronology is null, <code>ISOChronology</code>
0119: * in the default time zone is used.
0120: *
0121: * @param chronology the chronology, null means ISOChronology in default zone
0122: */
0123: public MutableDateTime(Chronology chronology) {
0124: super (chronology);
0125: }
0126:
0127: //-----------------------------------------------------------------------
0128: /**
0129: * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
0130: * using <code>ISOChronology</code> in the default time zone.
0131: *
0132: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0133: */
0134: public MutableDateTime(long instant) {
0135: super (instant);
0136: }
0137:
0138: /**
0139: * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
0140: * using <code>ISOChronology</code> in the specified time zone.
0141: * <p>
0142: * If the specified time zone is null, the default zone is used.
0143: *
0144: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0145: * @param zone the time zone, null means default zone
0146: */
0147: public MutableDateTime(long instant, DateTimeZone zone) {
0148: super (instant, zone);
0149: }
0150:
0151: /**
0152: * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z
0153: * using the specified chronology.
0154: * <p>
0155: * If the chronology is null, <code>ISOChronology</code>
0156: * in the default time zone is used.
0157: *
0158: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0159: * @param chronology the chronology, null means ISOChronology in default zone
0160: */
0161: public MutableDateTime(long instant, Chronology chronology) {
0162: super (instant, chronology);
0163: }
0164:
0165: //-----------------------------------------------------------------------
0166: /**
0167: * Constructs an instance from an Object that represents a datetime.
0168: * <p>
0169: * If the object implies a chronology (such as GregorianCalendar does),
0170: * then that chronology will be used. Otherwise, ISO default is used.
0171: * Thus if a GregorianCalendar is passed in, the chronology used will
0172: * be GJ, but if a Date is passed in the chronology will be ISO.
0173: * <p>
0174: * The recognised object types are defined in
0175: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0176: * include ReadableInstant, String, Calendar and Date.
0177: *
0178: * @param instant the datetime object, null means now
0179: * @throws IllegalArgumentException if the instant is invalid
0180: */
0181: public MutableDateTime(Object instant) {
0182: super (instant, (Chronology) null);
0183: }
0184:
0185: /**
0186: * Constructs an instance from an Object that represents a datetime,
0187: * forcing the time zone to that specified.
0188: * <p>
0189: * If the object implies a chronology (such as GregorianCalendar does),
0190: * then that chronology will be used, but with the time zone adjusted.
0191: * Otherwise, ISO is used in the specified time zone.
0192: * If the specified time zone is null, the default zone is used.
0193: * Thus if a GregorianCalendar is passed in, the chronology used will
0194: * be GJ, but if a Date is passed in the chronology will be ISO.
0195: * <p>
0196: * The recognised object types are defined in
0197: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0198: * include ReadableInstant, String, Calendar and Date.
0199: *
0200: * @param instant the datetime object, null means now
0201: * @param zone the time zone, null means default time zone
0202: * @throws IllegalArgumentException if the instant is invalid
0203: */
0204: public MutableDateTime(Object instant, DateTimeZone zone) {
0205: super (instant, zone);
0206: }
0207:
0208: /**
0209: * Constructs an instance from an Object that represents a datetime,
0210: * using the specified chronology.
0211: * <p>
0212: * If the chronology is null, ISO in the default time zone is used.
0213: * Any chronology implied by the object (such as GregorianCalendar does)
0214: * is ignored.
0215: * <p>
0216: * The recognised object types are defined in
0217: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0218: * include ReadableInstant, String, Calendar and Date.
0219: *
0220: * @param instant the datetime object, null means now
0221: * @param chronology the chronology, null means ISOChronology in default zone
0222: * @throws IllegalArgumentException if the instant is invalid
0223: */
0224: public MutableDateTime(Object instant, Chronology chronology) {
0225: super (instant, DateTimeUtils.getChronology(chronology));
0226: }
0227:
0228: //-----------------------------------------------------------------------
0229: /**
0230: * Constructs an instance from datetime field values
0231: * using <code>ISOChronology</code> in the default time zone.
0232: *
0233: * @param year the year
0234: * @param monthOfYear the month of the year
0235: * @param dayOfMonth the day of the month
0236: * @param hourOfDay the hour of the day
0237: * @param minuteOfHour the minute of the hour
0238: * @param secondOfMinute the second of the minute
0239: * @param millisOfSecond the millisecond of the second
0240: */
0241: public MutableDateTime(int year, int monthOfYear, int dayOfMonth,
0242: int hourOfDay, int minuteOfHour, int secondOfMinute,
0243: int millisOfSecond) {
0244: super (year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour,
0245: secondOfMinute, millisOfSecond);
0246: }
0247:
0248: /**
0249: * Constructs an instance from datetime field values
0250: * using <code>ISOChronology</code> in the specified time zone.
0251: * <p>
0252: * If the specified time zone is null, the default zone is used.
0253: *
0254: * @param year the year
0255: * @param monthOfYear the month of the year
0256: * @param dayOfMonth the day of the month
0257: * @param hourOfDay the hour of the day
0258: * @param minuteOfHour the minute of the hour
0259: * @param secondOfMinute the second of the minute
0260: * @param millisOfSecond the millisecond of the second
0261: * @param zone the time zone, null means default time zone
0262: */
0263: public MutableDateTime(int year, int monthOfYear, int dayOfMonth,
0264: int hourOfDay, int minuteOfHour, int secondOfMinute,
0265: int millisOfSecond, DateTimeZone zone) {
0266: super (year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour,
0267: secondOfMinute, millisOfSecond, zone);
0268: }
0269:
0270: /**
0271: * Constructs an instance from datetime field values
0272: * using the specified chronology.
0273: * <p>
0274: * If the chronology is null, <code>ISOChronology</code>
0275: * in the default time zone is used.
0276: *
0277: * @param year the year
0278: * @param monthOfYear the month of the year
0279: * @param dayOfMonth the day of the month
0280: * @param hourOfDay the hour of the day
0281: * @param minuteOfHour the minute of the hour
0282: * @param secondOfMinute the second of the minute
0283: * @param millisOfSecond the millisecond of the second
0284: * @param chronology the chronology, null means ISOChronology in default zone
0285: */
0286: public MutableDateTime(int year, int monthOfYear, int dayOfMonth,
0287: int hourOfDay, int minuteOfHour, int secondOfMinute,
0288: int millisOfSecond, Chronology chronology) {
0289: super (year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour,
0290: secondOfMinute, millisOfSecond, chronology);
0291: }
0292:
0293: //-----------------------------------------------------------------------
0294: /**
0295: * Gets the field used for rounding this instant, returning null if rounding
0296: * is not enabled.
0297: *
0298: * @return the rounding field
0299: */
0300: public DateTimeField getRoundingField() {
0301: return iRoundingField;
0302: }
0303:
0304: /**
0305: * Gets the rounding mode for this instant, returning ROUND_NONE if rounding
0306: * is not enabled.
0307: *
0308: * @return the rounding mode constant
0309: */
0310: public int getRoundingMode() {
0311: return iRoundingMode;
0312: }
0313:
0314: /**
0315: * Sets the status of rounding to use the specified field and ROUND_FLOOR mode.
0316: * A null field will disable rounding.
0317: * Once set, the instant is then rounded using the new field and mode.
0318: * <p>
0319: * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
0320: * to be rounded. This can be used to control the precision of the instant,
0321: * for example by setting a rounding field of minuteOfDay, the seconds and
0322: * milliseconds will always be zero.
0323: *
0324: * @param field rounding field or null to disable
0325: */
0326: public void setRounding(DateTimeField field) {
0327: setRounding(field, MutableDateTime.ROUND_FLOOR);
0328: }
0329:
0330: /**
0331: * Sets the status of rounding to use the specified field and mode.
0332: * A null field or mode of ROUND_NONE will disable rounding.
0333: * Once set, the instant is then rounded using the new field and mode.
0334: * <p>
0335: * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)}
0336: * to be rounded. This can be used to control the precision of the instant,
0337: * for example by setting a rounding field of minuteOfDay, the seconds and
0338: * milliseconds will always be zero.
0339: *
0340: * @param field rounding field or null to disable
0341: * @param mode rounding mode or ROUND_NONE to disable
0342: * @throws IllegalArgumentException if mode is unknown, no exception if field is null
0343: */
0344: public void setRounding(DateTimeField field, int mode) {
0345: if (field != null
0346: && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) {
0347: throw new IllegalArgumentException(
0348: "Illegal rounding mode: " + mode);
0349: }
0350: iRoundingField = (mode == ROUND_NONE ? null : field);
0351: iRoundingMode = (field == null ? ROUND_NONE : mode);
0352: setMillis(getMillis());
0353: }
0354:
0355: //-----------------------------------------------------------------------
0356: /**
0357: * Set the milliseconds of the datetime.
0358: * <p>
0359: * All changes to the millisecond field occurs via this method.
0360: *
0361: * @param instant the milliseconds since 1970-01-01T00:00:00Z to set the
0362: * datetime to
0363: */
0364: public void setMillis(long instant) {
0365: switch (iRoundingMode) {
0366: case ROUND_NONE:
0367: break;
0368: case ROUND_FLOOR:
0369: instant = iRoundingField.roundFloor(instant);
0370: break;
0371: case ROUND_CEILING:
0372: instant = iRoundingField.roundCeiling(instant);
0373: break;
0374: case ROUND_HALF_FLOOR:
0375: instant = iRoundingField.roundHalfFloor(instant);
0376: break;
0377: case ROUND_HALF_CEILING:
0378: instant = iRoundingField.roundHalfCeiling(instant);
0379: break;
0380: case ROUND_HALF_EVEN:
0381: instant = iRoundingField.roundHalfEven(instant);
0382: break;
0383: }
0384:
0385: super .setMillis(instant);
0386: }
0387:
0388: /**
0389: * Sets the millisecond instant of this instant from another.
0390: * <p>
0391: * This method does not change the chronology of this instant, just the
0392: * millisecond instant.
0393: *
0394: * @param instant the instant to use, null means now
0395: */
0396: public void setMillis(ReadableInstant instant) {
0397: long instantMillis = DateTimeUtils.getInstantMillis(instant);
0398: setMillis(instantMillis); // set via this class not super
0399: }
0400:
0401: //-----------------------------------------------------------------------
0402: /**
0403: * Add an amount of time to the datetime.
0404: *
0405: * @param duration the millis to add
0406: * @throws ArithmeticException if the result exceeds the capacity of the instant
0407: */
0408: public void add(long duration) {
0409: setMillis(FieldUtils.safeAdd(getMillis(), duration)); // set via this class not super
0410: }
0411:
0412: /**
0413: * Adds a duration to this instant.
0414: * <p>
0415: * This will typically change the value of most fields.
0416: *
0417: * @param duration the duration to add, null means add zero
0418: * @throws ArithmeticException if the result exceeds the capacity of the instant
0419: */
0420: public void add(ReadableDuration duration) {
0421: add(duration, 1);
0422: }
0423:
0424: /**
0425: * Adds a duration to this instant specifying how many times to add.
0426: * <p>
0427: * This will typically change the value of most fields.
0428: *
0429: * @param duration the duration to add, null means add zero
0430: * @param scalar direction and amount to add, which may be negative
0431: * @throws ArithmeticException if the result exceeds the capacity of the instant
0432: */
0433: public void add(ReadableDuration duration, int scalar) {
0434: if (duration != null) {
0435: add(FieldUtils.safeMultiply(duration.getMillis(), scalar));
0436: }
0437: }
0438:
0439: /**
0440: * Adds a period to this instant.
0441: * <p>
0442: * This will typically change the value of most fields.
0443: *
0444: * @param period the period to add, null means add zero
0445: * @throws ArithmeticException if the result exceeds the capacity of the instant
0446: */
0447: public void add(ReadablePeriod period) {
0448: add(period, 1);
0449: }
0450:
0451: /**
0452: * Adds a period to this instant specifying how many times to add.
0453: * <p>
0454: * This will typically change the value of most fields.
0455: *
0456: * @param period the period to add, null means add zero
0457: * @param scalar direction and amount to add, which may be negative
0458: * @throws ArithmeticException if the result exceeds the capacity of the instant
0459: */
0460: public void add(ReadablePeriod period, int scalar) {
0461: if (period != null) {
0462: setMillis(getChronology().add(period, getMillis(), scalar)); // set via this class not super
0463: }
0464: }
0465:
0466: //-----------------------------------------------------------------------
0467: /**
0468: * Set the chronology of the datetime.
0469: * <p>
0470: * All changes to the chronology occur via this method.
0471: *
0472: * @param chronology the chronology to use, null means ISOChronology in default zone
0473: */
0474: public void setChronology(Chronology chronology) {
0475: super .setChronology(chronology);
0476: }
0477:
0478: //-----------------------------------------------------------------------
0479: /**
0480: * Sets the time zone of the datetime, changing the chronology and field values.
0481: * <p>
0482: * Changing the zone using this method retains the millisecond instant.
0483: * The millisecond instant is adjusted in the new zone to compensate.
0484: *
0485: * chronology. Setting the time zone does not affect the millisecond value
0486: * of this instant.
0487: * <p>
0488: * If the chronology already has this time zone, no change occurs.
0489: *
0490: * @param newZone the time zone to use, null means default zone
0491: * @see #setZoneRetainFields
0492: */
0493: public void setZone(DateTimeZone newZone) {
0494: newZone = DateTimeUtils.getZone(newZone);
0495: Chronology chrono = getChronology();
0496: if (chrono.getZone() != newZone) {
0497: setChronology(chrono.withZone(newZone)); // set via this class not super
0498: }
0499: }
0500:
0501: /**
0502: * Sets the time zone of the datetime, changing the chronology and millisecond.
0503: * <p>
0504: * Changing the zone using this method retains the field values.
0505: * The millisecond instant is adjusted in the new zone to compensate.
0506: * <p>
0507: * If the chronology already has this time zone, no change occurs.
0508: *
0509: * @param newZone the time zone to use, null means default zone
0510: * @see #setZone
0511: */
0512: public void setZoneRetainFields(DateTimeZone newZone) {
0513: newZone = DateTimeUtils.getZone(newZone);
0514: DateTimeZone originalZone = DateTimeUtils.getZone(getZone());
0515: if (newZone == originalZone) {
0516: return;
0517: }
0518:
0519: long millis = originalZone.getMillisKeepLocal(newZone,
0520: getMillis());
0521: setChronology(getChronology().withZone(newZone)); // set via this class not super
0522: setMillis(millis);
0523: }
0524:
0525: //-----------------------------------------------------------------------
0526: /**
0527: * Sets the value of one of the fields of the instant, such as hourOfDay.
0528: *
0529: * @param type a field type, usually obtained from DateTimeFieldType, not null
0530: * @param value the value to set the field to
0531: * @throws IllegalArgumentException if the value is null or invalid
0532: */
0533: public void set(DateTimeFieldType type, int value) {
0534: if (type == null) {
0535: throw new IllegalArgumentException("Field must not be null");
0536: }
0537: setMillis(type.getField(getChronology())
0538: .set(getMillis(), value));
0539: }
0540:
0541: /**
0542: * Adds to the instant specifying the duration and multiple to add.
0543: *
0544: * @param type a field type, usually obtained from DateTimeFieldType, not null
0545: * @param amount the amount to add of this duration
0546: * @throws IllegalArgumentException if the value is null or invalid
0547: * @throws ArithmeticException if the result exceeds the capacity of the instant
0548: */
0549: public void add(DurationFieldType type, int amount) {
0550: if (type == null) {
0551: throw new IllegalArgumentException("Field must not be null");
0552: }
0553: setMillis(type.getField(getChronology()).add(getMillis(),
0554: amount));
0555: }
0556:
0557: //-----------------------------------------------------------------------
0558: /**
0559: * Set the year to the specified value.
0560: *
0561: * @param year the year
0562: * @throws IllegalArgumentException if the value is invalid
0563: */
0564: public void setYear(final int year) {
0565: setMillis(getChronology().year().set(getMillis(), year));
0566: }
0567:
0568: /**
0569: * Add a number of years to the date.
0570: *
0571: * @param years the years to add
0572: * @throws IllegalArgumentException if the value is invalid
0573: */
0574: public void addYears(final int years) {
0575: setMillis(getChronology().years().add(getMillis(), years));
0576: }
0577:
0578: //-----------------------------------------------------------------------
0579: /**
0580: * Set the weekyear to the specified value.
0581: *
0582: * @param weekyear the weekyear
0583: * @throws IllegalArgumentException if the value is invalid
0584: */
0585: public void setWeekyear(final int weekyear) {
0586: setMillis(getChronology().weekyear().set(getMillis(), weekyear));
0587: }
0588:
0589: /**
0590: * Add a number of weekyears to the date.
0591: *
0592: * @param weekyears the weekyears to add
0593: * @throws IllegalArgumentException if the value is invalid
0594: */
0595: public void addWeekyears(final int weekyears) {
0596: setMillis(getChronology().weekyears().add(getMillis(),
0597: weekyears));
0598: }
0599:
0600: //-----------------------------------------------------------------------
0601: /**
0602: * Set the month of the year to the specified value.
0603: *
0604: * @param monthOfYear the month of the year
0605: * @throws IllegalArgumentException if the value is invalid
0606: */
0607: public void setMonthOfYear(final int monthOfYear) {
0608: setMillis(getChronology().monthOfYear().set(getMillis(),
0609: monthOfYear));
0610: }
0611:
0612: /**
0613: * Add a number of months to the date.
0614: *
0615: * @param months the months to add
0616: * @throws IllegalArgumentException if the value is invalid
0617: */
0618: public void addMonths(final int months) {
0619: setMillis(getChronology().months().add(getMillis(), months));
0620: }
0621:
0622: //-----------------------------------------------------------------------
0623: /**
0624: * Set the week of weekyear to the specified value.
0625: *
0626: * @param weekOfWeekyear the week of the weekyear
0627: * @throws IllegalArgumentException if the value is invalid
0628: */
0629: public void setWeekOfWeekyear(final int weekOfWeekyear) {
0630: setMillis(getChronology().weekOfWeekyear().set(getMillis(),
0631: weekOfWeekyear));
0632: }
0633:
0634: /**
0635: * Add a number of weeks to the date.
0636: *
0637: * @param weeks the weeks to add
0638: * @throws IllegalArgumentException if the value is invalid
0639: */
0640: public void addWeeks(final int weeks) {
0641: setMillis(getChronology().weeks().add(getMillis(), weeks));
0642: }
0643:
0644: //-----------------------------------------------------------------------
0645: /**
0646: * Set the day of year to the specified value.
0647: *
0648: * @param dayOfYear the day of the year
0649: * @throws IllegalArgumentException if the value is invalid
0650: */
0651: public void setDayOfYear(final int dayOfYear) {
0652: setMillis(getChronology().dayOfYear().set(getMillis(),
0653: dayOfYear));
0654: }
0655:
0656: /**
0657: * Set the day of the month to the specified value.
0658: *
0659: * @param dayOfMonth the day of the month
0660: * @throws IllegalArgumentException if the value is invalid
0661: */
0662: public void setDayOfMonth(final int dayOfMonth) {
0663: setMillis(getChronology().dayOfMonth().set(getMillis(),
0664: dayOfMonth));
0665: }
0666:
0667: /**
0668: * Set the day of week to the specified value.
0669: *
0670: * @param dayOfWeek the day of the week
0671: * @throws IllegalArgumentException if the value is invalid
0672: */
0673: public void setDayOfWeek(final int dayOfWeek) {
0674: setMillis(getChronology().dayOfWeek().set(getMillis(),
0675: dayOfWeek));
0676: }
0677:
0678: /**
0679: * Add a number of days to the date.
0680: *
0681: * @param days the days to add
0682: * @throws IllegalArgumentException if the value is invalid
0683: */
0684: public void addDays(final int days) {
0685: setMillis(getChronology().days().add(getMillis(), days));
0686: }
0687:
0688: //-----------------------------------------------------------------------
0689: /**
0690: * Set the hour of the day to the specified value.
0691: *
0692: * @param hourOfDay the hour of day
0693: * @throws IllegalArgumentException if the value is invalid
0694: */
0695: public void setHourOfDay(final int hourOfDay) {
0696: setMillis(getChronology().hourOfDay().set(getMillis(),
0697: hourOfDay));
0698: }
0699:
0700: /**
0701: * Add a number of hours to the date.
0702: *
0703: * @param hours the hours to add
0704: * @throws IllegalArgumentException if the value is invalid
0705: */
0706: public void addHours(final int hours) {
0707: setMillis(getChronology().hours().add(getMillis(), hours));
0708: }
0709:
0710: //-----------------------------------------------------------------------
0711: /**
0712: * Set the minute of the day to the specified value.
0713: *
0714: * @param minuteOfDay the minute of day
0715: * @throws IllegalArgumentException if the value is invalid
0716: */
0717: public void setMinuteOfDay(final int minuteOfDay) {
0718: setMillis(getChronology().minuteOfDay().set(getMillis(),
0719: minuteOfDay));
0720: }
0721:
0722: /**
0723: * Set the minute of the hour to the specified value.
0724: *
0725: * @param minuteOfHour the minute of hour
0726: * @throws IllegalArgumentException if the value is invalid
0727: */
0728: public void setMinuteOfHour(final int minuteOfHour) {
0729: setMillis(getChronology().minuteOfHour().set(getMillis(),
0730: minuteOfHour));
0731: }
0732:
0733: /**
0734: * Add a number of minutes to the date.
0735: *
0736: * @param minutes the minutes to add
0737: * @throws IllegalArgumentException if the value is invalid
0738: */
0739: public void addMinutes(final int minutes) {
0740: setMillis(getChronology().minutes().add(getMillis(), minutes));
0741: }
0742:
0743: //-----------------------------------------------------------------------
0744: /**
0745: * Set the second of the day to the specified value.
0746: *
0747: * @param secondOfDay the second of day
0748: * @throws IllegalArgumentException if the value is invalid
0749: */
0750: public void setSecondOfDay(final int secondOfDay) {
0751: setMillis(getChronology().secondOfDay().set(getMillis(),
0752: secondOfDay));
0753: }
0754:
0755: /**
0756: * Set the second of the minute to the specified value.
0757: *
0758: * @param secondOfMinute the second of minute
0759: * @throws IllegalArgumentException if the value is invalid
0760: */
0761: public void setSecondOfMinute(final int secondOfMinute) {
0762: setMillis(getChronology().secondOfMinute().set(getMillis(),
0763: secondOfMinute));
0764: }
0765:
0766: /**
0767: * Add a number of seconds to the date.
0768: *
0769: * @param seconds the seconds to add
0770: * @throws IllegalArgumentException if the value is invalid
0771: */
0772: public void addSeconds(final int seconds) {
0773: setMillis(getChronology().seconds().add(getMillis(), seconds));
0774: }
0775:
0776: //-----------------------------------------------------------------------
0777: /**
0778: * Set the millis of the day to the specified value.
0779: *
0780: * @param millisOfDay the millis of day
0781: * @throws IllegalArgumentException if the value is invalid
0782: */
0783: public void setMillisOfDay(final int millisOfDay) {
0784: setMillis(getChronology().millisOfDay().set(getMillis(),
0785: millisOfDay));
0786: }
0787:
0788: /**
0789: * Set the millis of the second to the specified value.
0790: *
0791: * @param millisOfSecond the millis of second
0792: * @throws IllegalArgumentException if the value is invalid
0793: */
0794: public void setMillisOfSecond(final int millisOfSecond) {
0795: setMillis(getChronology().millisOfSecond().set(getMillis(),
0796: millisOfSecond));
0797: }
0798:
0799: /**
0800: * Add a number of milliseconds to the date. The implementation of this
0801: * method differs from the {@link #add(long)} method in that a
0802: * DateTimeField performs the addition.
0803: *
0804: * @param millis the milliseconds to add
0805: * @throws IllegalArgumentException if the value is invalid
0806: */
0807: public void addMillis(final int millis) {
0808: setMillis(getChronology().millis().add(getMillis(), millis));
0809: }
0810:
0811: //-----------------------------------------------------------------------
0812: /**
0813: * Set the date from milliseconds.
0814: * The time part of this object will be unaffected.
0815: *
0816: * @param instant an instant to copy the date from, time part ignored
0817: * @throws IllegalArgumentException if the value is invalid
0818: */
0819: public void setDate(final long instant) {
0820: setMillis(getChronology().millisOfDay().set(instant,
0821: getMillisOfDay()));
0822: }
0823:
0824: /**
0825: * Set the date from another instant.
0826: * The time part of this object will be unaffected.
0827: *
0828: * @param instant an instant to copy the date from, time part ignored
0829: * @throws IllegalArgumentException if the object is invalid
0830: */
0831: public void setDate(final ReadableInstant instant) {
0832: long instantMillis = DateTimeUtils.getInstantMillis(instant);
0833: Chronology instantChrono = DateTimeUtils
0834: .getInstantChronology(instant);
0835: DateTimeZone zone = instantChrono.getZone();
0836: if (zone != null) {
0837: instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC,
0838: instantMillis);
0839: }
0840: setDate(instantMillis);
0841: }
0842:
0843: /**
0844: * Set the date from fields.
0845: * The time part of this object will be unaffected.
0846: *
0847: * @param year the year
0848: * @param monthOfYear the month of the year
0849: * @param dayOfMonth the day of the month
0850: * @throws IllegalArgumentException if the value is invalid
0851: */
0852: public void setDate(final int year, final int monthOfYear,
0853: final int dayOfMonth) {
0854: Chronology c = getChronology();
0855: long instantMidnight = c.getDateTimeMillis(year, monthOfYear,
0856: dayOfMonth, 0);
0857: setDate(instantMidnight);
0858: }
0859:
0860: //-----------------------------------------------------------------------
0861: /**
0862: * Set the time from milliseconds.
0863: * The date part of this object will be unaffected.
0864: *
0865: * @param millis an instant to copy the time from, date part ignored
0866: * @throws IllegalArgumentException if the value is invalid
0867: */
0868: public void setTime(final long millis) {
0869: int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay()
0870: .get(millis);
0871: setMillis(getChronology().millisOfDay().set(getMillis(),
0872: millisOfDay));
0873: }
0874:
0875: /**
0876: * Set the time from another instant.
0877: * The date part of this object will be unaffected.
0878: *
0879: * @param instant an instant to copy the time from, date part ignored
0880: * @throws IllegalArgumentException if the object is invalid
0881: */
0882: public void setTime(final ReadableInstant instant) {
0883: long instantMillis = DateTimeUtils.getInstantMillis(instant);
0884: Chronology instantChrono = DateTimeUtils
0885: .getInstantChronology(instant);
0886: DateTimeZone zone = instantChrono.getZone();
0887: if (zone != null) {
0888: instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC,
0889: instantMillis);
0890: }
0891: setTime(instantMillis);
0892: }
0893:
0894: /**
0895: * Set the time from fields.
0896: * The date part of this object will be unaffected.
0897: *
0898: * @param hour the hour
0899: * @param minuteOfHour the minute of the hour
0900: * @param secondOfMinute the second of the minute
0901: * @param millisOfSecond the millisecond of the second
0902: * @throws IllegalArgumentException if the value is invalid
0903: */
0904: public void setTime(final int hour, final int minuteOfHour,
0905: final int secondOfMinute, final int millisOfSecond) {
0906: long instant = getChronology().getDateTimeMillis(getMillis(),
0907: hour, minuteOfHour, secondOfMinute, millisOfSecond);
0908: setMillis(instant);
0909: }
0910:
0911: /**
0912: * Set the date and time from fields.
0913: *
0914: * @param year the year
0915: * @param monthOfYear the month of the year
0916: * @param dayOfMonth the day of the month
0917: * @param hourOfDay the hour of the day
0918: * @param minuteOfHour the minute of the hour
0919: * @param secondOfMinute the second of the minute
0920: * @param millisOfSecond the millisecond of the second
0921: * @throws IllegalArgumentException if the value is invalid
0922: */
0923: public void setDateTime(final int year, final int monthOfYear,
0924: final int dayOfMonth, final int hourOfDay,
0925: final int minuteOfHour, final int secondOfMinute,
0926: final int millisOfSecond) {
0927: long instant = getChronology().getDateTimeMillis(year,
0928: monthOfYear, dayOfMonth, hourOfDay, minuteOfHour,
0929: secondOfMinute, millisOfSecond);
0930: setMillis(instant);
0931: }
0932:
0933: //-----------------------------------------------------------------------
0934: /**
0935: * Gets the property object for the specified type, which contains many useful methods.
0936: *
0937: * @param type the field type to get the chronology for
0938: * @return the property object
0939: * @throws IllegalArgumentException if the field is null or unsupported
0940: * @since 1.2
0941: */
0942: public Property property(DateTimeFieldType type) {
0943: if (type == null) {
0944: throw new IllegalArgumentException(
0945: "The DateTimeFieldType must not be null");
0946: }
0947: DateTimeField field = type.getField(getChronology());
0948: if (field.isSupported() == false) {
0949: throw new IllegalArgumentException("Field '" + type
0950: + "' is not supported");
0951: }
0952: return new Property(this , field);
0953: }
0954:
0955: /**
0956: * Get the era property.
0957: *
0958: * @return the era property
0959: */
0960: public Property era() {
0961: return new Property(this , getChronology().era());
0962: }
0963:
0964: /**
0965: * Get the century of era property.
0966: *
0967: * @return the year of era property
0968: */
0969: public Property centuryOfEra() {
0970: return new Property(this , getChronology().centuryOfEra());
0971: }
0972:
0973: /**
0974: * Get the year of century property.
0975: *
0976: * @return the year of era property
0977: */
0978: public Property yearOfCentury() {
0979: return new Property(this , getChronology().yearOfCentury());
0980: }
0981:
0982: /**
0983: * Get the year of era property.
0984: *
0985: * @return the year of era property
0986: */
0987: public Property yearOfEra() {
0988: return new Property(this , getChronology().yearOfEra());
0989: }
0990:
0991: /**
0992: * Get the year property.
0993: *
0994: * @return the year property
0995: */
0996: public Property year() {
0997: return new Property(this , getChronology().year());
0998: }
0999:
1000: /**
1001: * Get the year of a week based year property.
1002: *
1003: * @return the year of a week based year property
1004: */
1005: public Property weekyear() {
1006: return new Property(this , getChronology().weekyear());
1007: }
1008:
1009: /**
1010: * Get the month of year property.
1011: *
1012: * @return the month of year property
1013: */
1014: public Property monthOfYear() {
1015: return new Property(this , getChronology().monthOfYear());
1016: }
1017:
1018: /**
1019: * Get the week of a week based year property.
1020: *
1021: * @return the week of a week based year property
1022: */
1023: public Property weekOfWeekyear() {
1024: return new Property(this , getChronology().weekOfWeekyear());
1025: }
1026:
1027: /**
1028: * Get the day of year property.
1029: *
1030: * @return the day of year property
1031: */
1032: public Property dayOfYear() {
1033: return new Property(this , getChronology().dayOfYear());
1034: }
1035:
1036: /**
1037: * Get the day of month property.
1038: * <p>
1039: * The values for day of month are defined in {@link DateTimeConstants}.
1040: *
1041: * @return the day of month property
1042: */
1043: public Property dayOfMonth() {
1044: return new Property(this , getChronology().dayOfMonth());
1045: }
1046:
1047: /**
1048: * Get the day of week property.
1049: * <p>
1050: * The values for day of week are defined in {@link DateTimeConstants}.
1051: *
1052: * @return the day of week property
1053: */
1054: public Property dayOfWeek() {
1055: return new Property(this , getChronology().dayOfWeek());
1056: }
1057:
1058: //-----------------------------------------------------------------------
1059: /**
1060: * Get the hour of day field property
1061: *
1062: * @return the hour of day property
1063: */
1064: public Property hourOfDay() {
1065: return new Property(this , getChronology().hourOfDay());
1066: }
1067:
1068: /**
1069: * Get the minute of day property
1070: *
1071: * @return the minute of day property
1072: */
1073: public Property minuteOfDay() {
1074: return new Property(this , getChronology().minuteOfDay());
1075: }
1076:
1077: /**
1078: * Get the minute of hour field property
1079: *
1080: * @return the minute of hour property
1081: */
1082: public Property minuteOfHour() {
1083: return new Property(this , getChronology().minuteOfHour());
1084: }
1085:
1086: /**
1087: * Get the second of day property
1088: *
1089: * @return the second of day property
1090: */
1091: public Property secondOfDay() {
1092: return new Property(this , getChronology().secondOfDay());
1093: }
1094:
1095: /**
1096: * Get the second of minute field property
1097: *
1098: * @return the second of minute property
1099: */
1100: public Property secondOfMinute() {
1101: return new Property(this , getChronology().secondOfMinute());
1102: }
1103:
1104: /**
1105: * Get the millis of day property
1106: *
1107: * @return the millis of day property
1108: */
1109: public Property millisOfDay() {
1110: return new Property(this , getChronology().millisOfDay());
1111: }
1112:
1113: /**
1114: * Get the millis of second property
1115: *
1116: * @return the millis of second property
1117: */
1118: public Property millisOfSecond() {
1119: return new Property(this , getChronology().millisOfSecond());
1120: }
1121:
1122: //-----------------------------------------------------------------------
1123: /**
1124: * Clone this object without having to cast the returned object.
1125: *
1126: * @return a clone of the this object.
1127: */
1128: public MutableDateTime copy() {
1129: return (MutableDateTime) clone();
1130: }
1131:
1132: //-----------------------------------------------------------------------
1133: /**
1134: * Clone this object.
1135: *
1136: * @return a clone of this object.
1137: */
1138: public Object clone() {
1139: try {
1140: return super .clone();
1141: } catch (CloneNotSupportedException ex) {
1142: throw new InternalError("Clone error");
1143: }
1144: }
1145:
1146: /**
1147: * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZ).
1148: *
1149: * @return ISO8601 time formatted string.
1150: */
1151: public String toString() {
1152: return ISODateTimeFormat.dateTime().print(this );
1153: }
1154:
1155: /**
1156: * MutableDateTime.Property binds a MutableDateTime to a
1157: * DateTimeField allowing powerful datetime functionality to be easily
1158: * accessed.
1159: * <p>
1160: * The example below shows how to use the property to change the value of a
1161: * MutableDateTime object.
1162: * <pre>
1163: * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123);
1164: * dt.year().add(20);
1165: * dt.second().roundFloor().minute().set(10);
1166: * </pre>
1167: * <p>
1168: * MutableDateTime.Propery itself is thread-safe and immutable, but the
1169: * MutableDateTime being operated on is not.
1170: *
1171: * @author Stephen Colebourne
1172: * @author Brian S O'Neill
1173: * @since 1.0
1174: */
1175: public static final class Property extends
1176: AbstractReadableInstantFieldProperty {
1177:
1178: /** Serialization version */
1179: private static final long serialVersionUID = -4481126543819298617L;
1180:
1181: /** The instant this property is working against */
1182: private MutableDateTime iInstant;
1183: /** The field this property is working against */
1184: private DateTimeField iField;
1185:
1186: /**
1187: * Constructor.
1188: *
1189: * @param instant the instant to set
1190: * @param field the field to use
1191: */
1192: Property(MutableDateTime instant, DateTimeField field) {
1193: super ();
1194: iInstant = instant;
1195: iField = field;
1196: }
1197:
1198: /**
1199: * Writes the property in a safe serialization format.
1200: */
1201: private void writeObject(ObjectOutputStream oos)
1202: throws IOException {
1203: oos.writeObject(iInstant);
1204: oos.writeObject(iField.getType());
1205: }
1206:
1207: /**
1208: * Reads the property from a safe serialization format.
1209: */
1210: private void readObject(ObjectInputStream oos)
1211: throws IOException, ClassNotFoundException {
1212: iInstant = (MutableDateTime) oos.readObject();
1213: DateTimeFieldType type = (DateTimeFieldType) oos
1214: .readObject();
1215: iField = type.getField(iInstant.getChronology());
1216: }
1217:
1218: //-----------------------------------------------------------------------
1219: /**
1220: * Gets the field being used.
1221: *
1222: * @return the field
1223: */
1224: public DateTimeField getField() {
1225: return iField;
1226: }
1227:
1228: /**
1229: * Gets the milliseconds of the datetime that this property is linked to.
1230: *
1231: * @return the milliseconds
1232: */
1233: protected long getMillis() {
1234: return iInstant.getMillis();
1235: }
1236:
1237: /**
1238: * Gets the chronology of the datetime that this property is linked to.
1239: *
1240: * @return the chronology
1241: * @since 1.4
1242: */
1243: protected Chronology getChronology() {
1244: return iInstant.getChronology();
1245: }
1246:
1247: /**
1248: * Gets the mutable datetime being used.
1249: *
1250: * @return the mutable datetime
1251: */
1252: public MutableDateTime getMutableDateTime() {
1253: return iInstant;
1254: }
1255:
1256: //-----------------------------------------------------------------------
1257: /**
1258: * Adds a value to the millis value.
1259: *
1260: * @param value the value to add
1261: * @return the mutable datetime being used, so calls can be chained
1262: * @see DateTimeField#add(long,int)
1263: */
1264: public MutableDateTime add(int value) {
1265: iInstant.setMillis(getField().add(iInstant.getMillis(),
1266: value));
1267: return iInstant;
1268: }
1269:
1270: /**
1271: * Adds a value to the millis value.
1272: *
1273: * @param value the value to add
1274: * @return the mutable datetime being used, so calls can be chained
1275: * @see DateTimeField#add(long,long)
1276: */
1277: public MutableDateTime add(long value) {
1278: iInstant.setMillis(getField().add(iInstant.getMillis(),
1279: value));
1280: return iInstant;
1281: }
1282:
1283: /**
1284: * Adds a value, possibly wrapped, to the millis value.
1285: *
1286: * @param value the value to add
1287: * @return the mutable datetime being used, so calls can be chained
1288: * @see DateTimeField#addWrapField
1289: */
1290: public MutableDateTime addWrapField(int value) {
1291: iInstant.setMillis(getField().addWrapField(
1292: iInstant.getMillis(), value));
1293: return iInstant;
1294: }
1295:
1296: //-----------------------------------------------------------------------
1297: /**
1298: * Sets a value.
1299: *
1300: * @param value the value to set.
1301: * @return the mutable datetime being used, so calls can be chained
1302: * @see DateTimeField#set(long,int)
1303: */
1304: public MutableDateTime set(int value) {
1305: iInstant.setMillis(getField().set(iInstant.getMillis(),
1306: value));
1307: return iInstant;
1308: }
1309:
1310: /**
1311: * Sets a text value.
1312: *
1313: * @param text the text value to set
1314: * @param locale optional locale to use for selecting a text symbol
1315: * @return the mutable datetime being used, so calls can be chained
1316: * @throws IllegalArgumentException if the text value isn't valid
1317: * @see DateTimeField#set(long,java.lang.String,java.util.Locale)
1318: */
1319: public MutableDateTime set(String text, Locale locale) {
1320: iInstant.setMillis(getField().set(iInstant.getMillis(),
1321: text, locale));
1322: return iInstant;
1323: }
1324:
1325: /**
1326: * Sets a text value.
1327: *
1328: * @param text the text value to set
1329: * @return the mutable datetime being used, so calls can be chained
1330: * @throws IllegalArgumentException if the text value isn't valid
1331: * @see DateTimeField#set(long,java.lang.String)
1332: */
1333: public MutableDateTime set(String text) {
1334: set(text, null);
1335: return iInstant;
1336: }
1337:
1338: //-----------------------------------------------------------------------
1339: /**
1340: * Round to the lowest whole unit of this field.
1341: *
1342: * @return the mutable datetime being used, so calls can be chained
1343: * @see DateTimeField#roundFloor
1344: */
1345: public MutableDateTime roundFloor() {
1346: iInstant.setMillis(getField().roundFloor(
1347: iInstant.getMillis()));
1348: return iInstant;
1349: }
1350:
1351: /**
1352: * Round to the highest whole unit of this field.
1353: *
1354: * @return the mutable datetime being used, so calls can be chained
1355: * @see DateTimeField#roundCeiling
1356: */
1357: public MutableDateTime roundCeiling() {
1358: iInstant.setMillis(getField().roundCeiling(
1359: iInstant.getMillis()));
1360: return iInstant;
1361: }
1362:
1363: /**
1364: * Round to the nearest whole unit of this field, favoring the floor if
1365: * halfway.
1366: *
1367: * @return the mutable datetime being used, so calls can be chained
1368: * @see DateTimeField#roundHalfFloor
1369: */
1370: public MutableDateTime roundHalfFloor() {
1371: iInstant.setMillis(getField().roundHalfFloor(
1372: iInstant.getMillis()));
1373: return iInstant;
1374: }
1375:
1376: /**
1377: * Round to the nearest whole unit of this field, favoring the ceiling if
1378: * halfway.
1379: *
1380: * @return the mutable datetime being used, so calls can be chained
1381: * @see DateTimeField#roundHalfCeiling
1382: */
1383: public MutableDateTime roundHalfCeiling() {
1384: iInstant.setMillis(getField().roundHalfCeiling(
1385: iInstant.getMillis()));
1386: return iInstant;
1387: }
1388:
1389: /**
1390: * Round to the nearest whole unit of this field. If halfway, the ceiling
1391: * is favored over the floor only if it makes this field's value even.
1392: *
1393: * @return the mutable datetime being used, so calls can be chained
1394: * @see DateTimeField#roundHalfEven
1395: */
1396: public MutableDateTime roundHalfEven() {
1397: iInstant.setMillis(getField().roundHalfEven(
1398: iInstant.getMillis()));
1399: return iInstant;
1400: }
1401: }
1402:
1403: }
|