0001: /*
0002: * Copyright 2001-2006 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.Serializable;
0019: import java.util.Calendar;
0020: import java.util.Date;
0021: import java.util.Locale;
0022:
0023: import org.joda.time.base.BasePartial;
0024: import org.joda.time.chrono.ISOChronology;
0025: import org.joda.time.field.AbstractPartialFieldProperty;
0026: import org.joda.time.field.FieldUtils;
0027: import org.joda.time.format.ISODateTimeFormat;
0028:
0029: /**
0030: * TimeOfDay is an immutable partial supporting the hour, minute, second
0031: * and millisecond fields.
0032: * <p>
0033: * NOTE: This class only supports the four fields listed above. Thus, you
0034: * cannot query the millisOfDay or secondOfDay fields for example.
0035: * The new <code>LocalTime</code> class removes this restriction.
0036: * <p>
0037: * Calculations on TimeOfDay are performed using a {@link Chronology}.
0038: * This chronology is set to be in the UTC time zone for all calculations.
0039: * <p>
0040: * Each individual field can be queried in two ways:
0041: * <ul>
0042: * <li><code>getHourOfDay()</code>
0043: * <li><code>hourOfDay().get()</code>
0044: * </ul>
0045: * The second technique also provides access to other useful methods on the
0046: * field:
0047: * <ul>
0048: * <li>numeric value - <code>hourOfDay().get()</code>
0049: * <li>text value - <code>hourOfDay().getAsText()</code>
0050: * <li>short text value - <code>hourOfDay().getAsShortText()</code>
0051: * <li>maximum/minimum values - <code>hourOfDay().getMaximumValue()</code>
0052: * <li>add/subtract - <code>hourOfDay().addToCopy()</code>
0053: * <li>set - <code>hourOfDay().setCopy()</code>
0054: * </ul>
0055: * <p>
0056: * TimeOfDay is thread-safe and immutable, provided that the Chronology is as well.
0057: * All standard Chronology classes supplied are thread-safe and immutable.
0058: *
0059: * @author Stephen Colebourne
0060: * @author Brian S O'Neill
0061: * @since 1.0
0062: * @deprecated Use LocalTime which has a much better internal implementation and
0063: * has been available since 1.3
0064: */
0065: public final class TimeOfDay extends BasePartial implements
0066: ReadablePartial, Serializable {
0067: // NOTE: No toDateTime(YearMonthDay) as semantics are confusing when
0068: // different chronologies
0069:
0070: /** Serialization version */
0071: private static final long serialVersionUID = 3633353405803318660L;
0072: /** The singleton set of field types */
0073: private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
0074: DateTimeFieldType.hourOfDay(),
0075: DateTimeFieldType.minuteOfHour(),
0076: DateTimeFieldType.secondOfMinute(),
0077: DateTimeFieldType.millisOfSecond(), };
0078:
0079: /** Constant for midnight. */
0080: public static final TimeOfDay MIDNIGHT = new TimeOfDay(0, 0, 0, 0);
0081:
0082: /** The index of the hourOfDay field in the field array */
0083: public static final int HOUR_OF_DAY = 0;
0084: /** The index of the minuteOfHour field in the field array */
0085: public static final int MINUTE_OF_HOUR = 1;
0086: /** The index of the secondOfMinute field in the field array */
0087: public static final int SECOND_OF_MINUTE = 2;
0088: /** The index of the millisOfSecond field in the field array */
0089: public static final int MILLIS_OF_SECOND = 3;
0090:
0091: //-----------------------------------------------------------------------
0092: /**
0093: * Constructs a TimeOfDay from a <code>java.util.Calendar</code>
0094: * using exactly the same field values avoiding any time zone effects.
0095: * <p>
0096: * Each field is queried from the Calendar and assigned to the TimeOfDay.
0097: * This is useful to ensure that the field values are the same in the
0098: * created TimeOfDay no matter what the time zone is. For example, if
0099: * the Calendar states that the time is 04:29, then the created TimeOfDay
0100: * will always have the time 04:29 irrespective of time zone issues.
0101: * <p>
0102: * This factory method ignores the type of the calendar and always
0103: * creates a TimeOfDay with ISO chronology.
0104: *
0105: * @param calendar the Calendar to extract fields from
0106: * @return the created TimeOfDay
0107: * @throws IllegalArgumentException if the calendar is null
0108: * @throws IllegalArgumentException if the time is invalid for the ISO chronology
0109: * @since 1.2
0110: */
0111: public static TimeOfDay fromCalendarFields(Calendar calendar) {
0112: if (calendar == null) {
0113: throw new IllegalArgumentException(
0114: "The calendar must not be null");
0115: }
0116: return new TimeOfDay(calendar.get(Calendar.HOUR_OF_DAY),
0117: calendar.get(Calendar.MINUTE), calendar
0118: .get(Calendar.SECOND), calendar
0119: .get(Calendar.MILLISECOND));
0120: }
0121:
0122: /**
0123: * Constructs a TimeOfDay from a <code>java.util.Date</code>
0124: * using exactly the same field values avoiding any time zone effects.
0125: * <p>
0126: * Each field is queried from the Date and assigned to the TimeOfDay.
0127: * This is useful to ensure that the field values are the same in the
0128: * created TimeOfDay no matter what the time zone is. For example, if
0129: * the Calendar states that the time is 04:29, then the created TimeOfDay
0130: * will always have the time 04:29 irrespective of time zone issues.
0131: * <p>
0132: * This factory method always creates a TimeOfDay with ISO chronology.
0133: *
0134: * @param date the Date to extract fields from
0135: * @return the created TimeOfDay
0136: * @throws IllegalArgumentException if the calendar is null
0137: * @throws IllegalArgumentException if the date is invalid for the ISO chronology
0138: * @since 1.2
0139: */
0140: public static TimeOfDay fromDateFields(Date date) {
0141: if (date == null) {
0142: throw new IllegalArgumentException(
0143: "The date must not be null");
0144: }
0145: return new TimeOfDay(date.getHours(), date.getMinutes(), date
0146: .getSeconds(), (int) (date.getTime() % 1000));
0147: }
0148:
0149: //-----------------------------------------------------------------------
0150: /**
0151: * Constructs a TimeOfDay from the specified millis of day using the
0152: * ISO chronology.
0153: * <p>
0154: * The millisOfDay value may exceed the number of millis in one day,
0155: * but additional days will be ignored.
0156: * This method uses the UTC time zone internally.
0157: *
0158: * @param millisOfDay the number of milliseconds into a day to convert
0159: */
0160: public static TimeOfDay fromMillisOfDay(long millisOfDay) {
0161: return fromMillisOfDay(millisOfDay, null);
0162: }
0163:
0164: /**
0165: * Constructs a TimeOfDay from the specified millis of day using the
0166: * specified chronology.
0167: * <p>
0168: * The millisOfDay value may exceed the number of millis in one day,
0169: * but additional days will be ignored.
0170: * This method uses the UTC time zone internally.
0171: *
0172: * @param millisOfDay the number of milliseconds into a day to convert
0173: * @param chrono the chronology, null means ISO chronology
0174: */
0175: public static TimeOfDay fromMillisOfDay(long millisOfDay,
0176: Chronology chrono) {
0177: chrono = DateTimeUtils.getChronology(chrono);
0178: chrono = chrono.withUTC();
0179: return new TimeOfDay(millisOfDay, chrono);
0180: }
0181:
0182: // Constructors
0183: //-----------------------------------------------------------------------
0184: /**
0185: * Constructs a TimeOfDay with the current time, using ISOChronology in
0186: * the default zone to extract the fields.
0187: * <p>
0188: * The constructor uses the default time zone, resulting in the local time
0189: * being initialised. Once the constructor is complete, all further calculations
0190: * are performed without reference to a timezone (by switching to UTC).
0191: */
0192: public TimeOfDay() {
0193: super ();
0194: }
0195:
0196: /**
0197: * Constructs a TimeOfDay with the current time, using ISOChronology in
0198: * the specified zone to extract the fields.
0199: * <p>
0200: * The constructor uses the specified time zone to obtain the current time.
0201: * Once the constructor is complete, all further calculations
0202: * are performed without reference to a timezone (by switching to UTC).
0203: *
0204: * @param zone the zone to use, null means default zone
0205: * @since 1.1
0206: */
0207: public TimeOfDay(DateTimeZone zone) {
0208: super (ISOChronology.getInstance(zone));
0209: }
0210:
0211: /**
0212: * Constructs a TimeOfDay with the current time, using the specified chronology
0213: * and zone to extract the fields.
0214: * <p>
0215: * The constructor uses the time zone of the chronology specified.
0216: * Once the constructor is complete, all further calculations are performed
0217: * without reference to a timezone (by switching to UTC).
0218: *
0219: * @param chronology the chronology, null means ISOChronology in the default zone
0220: */
0221: public TimeOfDay(Chronology chronology) {
0222: super (chronology);
0223: }
0224:
0225: /**
0226: * Constructs a TimeOfDay extracting the partial fields from the specified
0227: * milliseconds using the ISOChronology in the default zone.
0228: * <p>
0229: * The constructor uses the default time zone, resulting in the local time
0230: * being initialised. Once the constructor is complete, all further calculations
0231: * are performed without reference to a timezone (by switching to UTC).
0232: *
0233: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0234: */
0235: public TimeOfDay(long instant) {
0236: super (instant);
0237: }
0238:
0239: /**
0240: * Constructs a TimeOfDay extracting the partial fields from the specified
0241: * milliseconds using the chronology provided.
0242: * <p>
0243: * The constructor uses the time zone of the chronology specified.
0244: * Once the constructor is complete, all further calculations are performed
0245: * without reference to a timezone (by switching to UTC).
0246: *
0247: * @param instant the milliseconds from 1970-01-01T00:00:00Z
0248: * @param chronology the chronology, null means ISOChronology in the default zone
0249: */
0250: public TimeOfDay(long instant, Chronology chronology) {
0251: super (instant, chronology);
0252: }
0253:
0254: /**
0255: * Constructs a TimeOfDay from an Object that represents a time.
0256: * <p>
0257: * The recognised object types are defined in
0258: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0259: * include ReadableInstant, String, Calendar and Date.
0260: * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
0261: * <p>
0262: * The chronology used will be derived from the object, defaulting to ISO.
0263: * <p>
0264: * NOTE: Prior to v1.3 the string format was described by
0265: * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
0266: *
0267: * @param instant the datetime object, null means now
0268: * @throws IllegalArgumentException if the instant is invalid
0269: */
0270: public TimeOfDay(Object instant) {
0271: super (instant, null, ISODateTimeFormat.timeParser());
0272: }
0273:
0274: /**
0275: * Constructs a TimeOfDay from an Object that represents a time, using the
0276: * specified chronology.
0277: * <p>
0278: * The recognised object types are defined in
0279: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0280: * include ReadableInstant, String, Calendar and Date.
0281: * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
0282: * <p>
0283: * The constructor uses the time zone of the chronology specified.
0284: * Once the constructor is complete, all further calculations are performed
0285: * without reference to a timezone (by switching to UTC).
0286: * The specified chronology overrides that of the object.
0287: * <p>
0288: * NOTE: Prior to v1.3 the string format was described by
0289: * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
0290: *
0291: * @param instant the datetime object, null means now
0292: * @param chronology the chronology, null means ISO default
0293: * @throws IllegalArgumentException if the instant is invalid
0294: */
0295: public TimeOfDay(Object instant, Chronology chronology) {
0296: super (instant, DateTimeUtils.getChronology(chronology),
0297: ISODateTimeFormat.timeParser());
0298: }
0299:
0300: /**
0301: * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds
0302: * using <code>ISOChronology</code> in the default zone.
0303: * <p>
0304: * The constructor uses the no time zone initialising the fields as provided.
0305: * Once the constructor is complete, all further calculations
0306: * are performed without reference to a timezone (by switching to UTC).
0307: *
0308: * @param hourOfDay the hour of the day
0309: * @param minuteOfHour the minute of the hour
0310: */
0311: public TimeOfDay(int hourOfDay, int minuteOfHour) {
0312: this (hourOfDay, minuteOfHour, 0, 0, null);
0313: }
0314:
0315: /**
0316: * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds.
0317: * <p>
0318: * The constructor uses the time zone of the chronology specified.
0319: * Once the constructor is complete, all further calculations are performed
0320: * without reference to a timezone (by switching to UTC).
0321: *
0322: * @param hourOfDay the hour of the day
0323: * @param minuteOfHour the minute of the hour
0324: * @param chronology the chronology, null means ISOChronology in the default zone
0325: */
0326: public TimeOfDay(int hourOfDay, int minuteOfHour,
0327: Chronology chronology) {
0328: this (hourOfDay, minuteOfHour, 0, 0, chronology);
0329: }
0330:
0331: /**
0332: * Constructs a TimeOfDay with specified time field values and zero milliseconds
0333: * using <code>ISOChronology</code> in the default zone.
0334: * <p>
0335: * The constructor uses the no time zone initialising the fields as provided.
0336: * Once the constructor is complete, all further calculations
0337: * are performed without reference to a timezone (by switching to UTC).
0338: *
0339: * @param hourOfDay the hour of the day
0340: * @param minuteOfHour the minute of the hour
0341: * @param secondOfMinute the second of the minute
0342: */
0343: public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute) {
0344: this (hourOfDay, minuteOfHour, secondOfMinute, 0, null);
0345: }
0346:
0347: /**
0348: * Constructs a TimeOfDay with specified time field values and zero milliseconds.
0349: * <p>
0350: * The constructor uses the time zone of the chronology specified.
0351: * Once the constructor is complete, all further calculations are performed
0352: * without reference to a timezone (by switching to UTC).
0353: *
0354: * @param hourOfDay the hour of the day
0355: * @param minuteOfHour the minute of the hour
0356: * @param secondOfMinute the second of the minute
0357: * @param chronology the chronology, null means ISOChronology in the default zone
0358: */
0359: public TimeOfDay(int hourOfDay, int minuteOfHour,
0360: int secondOfMinute, Chronology chronology) {
0361: this (hourOfDay, minuteOfHour, secondOfMinute, 0, chronology);
0362: }
0363:
0364: /**
0365: * Constructs a TimeOfDay with specified time field values using
0366: * <code>ISOChronology</code> in the default zone.
0367: * <p>
0368: * The constructor uses the no time zone initialising the fields as provided.
0369: * Once the constructor is complete, all further calculations
0370: * are performed without reference to a timezone (by switching to UTC).
0371: *
0372: * @param hourOfDay the hour of the day
0373: * @param minuteOfHour the minute of the hour
0374: * @param secondOfMinute the second of the minute
0375: * @param millisOfSecond the millisecond of the second
0376: */
0377: public TimeOfDay(int hourOfDay, int minuteOfHour,
0378: int secondOfMinute, int millisOfSecond) {
0379: this (hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond,
0380: null);
0381: }
0382:
0383: /**
0384: * Constructs a TimeOfDay with specified time field values and chronology.
0385: * <p>
0386: * The constructor uses the time zone of the chronology specified.
0387: * Once the constructor is complete, all further calculations are performed
0388: * without reference to a timezone (by switching to UTC).
0389: *
0390: * @param hourOfDay the hour of the day
0391: * @param minuteOfHour the minute of the hour
0392: * @param secondOfMinute the second of the minute
0393: * @param millisOfSecond the millisecond of the second
0394: * @param chronology the chronology, null means ISOChronology in the default zone
0395: */
0396: public TimeOfDay(int hourOfDay, int minuteOfHour,
0397: int secondOfMinute, int millisOfSecond,
0398: Chronology chronology) {
0399: super (new int[] { hourOfDay, minuteOfHour, secondOfMinute,
0400: millisOfSecond }, chronology);
0401: }
0402:
0403: /**
0404: * Constructs a TimeOfDay with chronology from this instance and new values.
0405: *
0406: * @param partial the partial to base this new instance on
0407: * @param values the new set of values
0408: */
0409: TimeOfDay(TimeOfDay partial, int[] values) {
0410: super (partial, values);
0411: }
0412:
0413: /**
0414: * Constructs a TimeOfDay with values from this instance and a new chronology.
0415: *
0416: * @param partial the partial to base this new instance on
0417: * @param chrono the new chronology
0418: */
0419: TimeOfDay(TimeOfDay partial, Chronology chrono) {
0420: super (partial, chrono);
0421: }
0422:
0423: //-----------------------------------------------------------------------
0424: /**
0425: * Gets the number of fields in this partial.
0426: *
0427: * @return the field count
0428: */
0429: public int size() {
0430: return 4;
0431: }
0432:
0433: /**
0434: * Gets the field for a specific index in the chronology specified.
0435: * <p>
0436: * This method must not use any instance variables.
0437: *
0438: * @param index the index to retrieve
0439: * @param chrono the chronology to use
0440: * @return the field
0441: */
0442: protected DateTimeField getField(int index, Chronology chrono) {
0443: switch (index) {
0444: case HOUR_OF_DAY:
0445: return chrono.hourOfDay();
0446: case MINUTE_OF_HOUR:
0447: return chrono.minuteOfHour();
0448: case SECOND_OF_MINUTE:
0449: return chrono.secondOfMinute();
0450: case MILLIS_OF_SECOND:
0451: return chrono.millisOfSecond();
0452: default:
0453: throw new IndexOutOfBoundsException("Invalid index: "
0454: + index);
0455: }
0456: }
0457:
0458: /**
0459: * Gets the field type at the specified index.
0460: *
0461: * @param index the index to retrieve
0462: * @return the field at the specified index
0463: * @throws IndexOutOfBoundsException if the index is invalid
0464: */
0465: public DateTimeFieldType getFieldType(int index) {
0466: return FIELD_TYPES[index];
0467: }
0468:
0469: /**
0470: * Gets an array of the field type of each of the fields that this partial supports.
0471: * <p>
0472: * The fields are returned largest to smallest, Hour, Minute, Second, Millis.
0473: *
0474: * @return the array of field types (cloned), largest to smallest
0475: */
0476: public DateTimeFieldType[] getFieldTypes() {
0477: return (DateTimeFieldType[]) FIELD_TYPES.clone();
0478: }
0479:
0480: //-----------------------------------------------------------------------
0481: /**
0482: * Returns a copy of this time with the specified chronology.
0483: * This instance is immutable and unaffected by this method call.
0484: * <p>
0485: * This method retains the values of the fields, thus the result will
0486: * typically refer to a different instant.
0487: * <p>
0488: * The time zone of the specified chronology is ignored, as TimeOfDay
0489: * operates without a time zone.
0490: *
0491: * @param newChronology the new chronology, null means ISO
0492: * @return a copy of this datetime with a different chronology
0493: * @throws IllegalArgumentException if the values are invalid for the new chronology
0494: */
0495: public TimeOfDay withChronologyRetainFields(Chronology newChronology) {
0496: newChronology = DateTimeUtils.getChronology(newChronology);
0497: newChronology = newChronology.withUTC();
0498: if (newChronology == getChronology()) {
0499: return this ;
0500: } else {
0501: TimeOfDay newTimeOfDay = new TimeOfDay(this , newChronology);
0502: newChronology.validate(newTimeOfDay, getValues());
0503: return newTimeOfDay;
0504: }
0505: }
0506:
0507: /**
0508: * Returns a copy of this time with the specified field set to a new value.
0509: * <p>
0510: * For example, if the field type is <code>minuteOfHour</code> then the day
0511: * would be changed in the returned instance.
0512: * <p>
0513: * These three lines are equivalent:
0514: * <pre>
0515: * TimeOfDay updated = tod.withField(DateTimeFieldType.minuteOfHour(), 6);
0516: * TimeOfDay updated = tod.minuteOfHour().setCopy(6);
0517: * TimeOfDay updated = tod.property(DateTimeFieldType.minuteOfHour()).setCopy(6);
0518: * </pre>
0519: *
0520: * @param fieldType the field type to set, not null
0521: * @param value the value to set
0522: * @return a copy of this instance with the field set
0523: * @throws IllegalArgumentException if the value is null or invalid
0524: */
0525: public TimeOfDay withField(DateTimeFieldType fieldType, int value) {
0526: int index = indexOfSupported(fieldType);
0527: if (value == getValue(index)) {
0528: return this ;
0529: }
0530: int[] newValues = getValues();
0531: newValues = getField(index).set(this , index, newValues, value);
0532: return new TimeOfDay(this , newValues);
0533: }
0534:
0535: /**
0536: * Returns a copy of this time with the value of the specified field increased,
0537: * wrapping to what would be a new day if required.
0538: * <p>
0539: * If the addition is zero, then <code>this</code> is returned.
0540: * <p>
0541: * These three lines are equivalent:
0542: * <pre>
0543: * TimeOfDay added = tod.withFieldAdded(DurationFieldType.minutes(), 6);
0544: * TimeOfDay added = tod.plusMinutes(6);
0545: * TimeOfDay added = tod.minuteOfHour().addToCopy(6);
0546: * </pre>
0547: *
0548: * @param fieldType the field type to add to, not null
0549: * @param amount the amount to add
0550: * @return a copy of this instance with the field updated
0551: * @throws IllegalArgumentException if the value is null or invalid
0552: * @throws ArithmeticException if the new datetime exceeds the capacity
0553: */
0554: public TimeOfDay withFieldAdded(DurationFieldType fieldType,
0555: int amount) {
0556: int index = indexOfSupported(fieldType);
0557: if (amount == 0) {
0558: return this ;
0559: }
0560: int[] newValues = getValues();
0561: newValues = getField(index).addWrapPartial(this , index,
0562: newValues, amount);
0563: return new TimeOfDay(this , newValues);
0564: }
0565:
0566: /**
0567: * Returns a copy of this time with the specified period added,
0568: * wrapping to what would be a new day if required.
0569: * <p>
0570: * If the addition is zero, then <code>this</code> is returned.
0571: * Fields in the period that aren't present in the partial are ignored.
0572: * <p>
0573: * This method is typically used to add multiple copies of complex
0574: * period instances. Adding one field is best achieved using methods
0575: * like {@link #withFieldAdded(DurationFieldType, int)}
0576: * or {@link #plusHours(int)}.
0577: *
0578: * @param period the period to add to this one, null means zero
0579: * @param scalar the amount of times to add, such as -1 to subtract once
0580: * @return a copy of this instance with the period added
0581: * @throws ArithmeticException if the new datetime exceeds the capacity
0582: */
0583: public TimeOfDay withPeriodAdded(ReadablePeriod period, int scalar) {
0584: if (period == null || scalar == 0) {
0585: return this ;
0586: }
0587: int[] newValues = getValues();
0588: for (int i = 0; i < period.size(); i++) {
0589: DurationFieldType fieldType = period.getFieldType(i);
0590: int index = indexOf(fieldType);
0591: if (index >= 0) {
0592: newValues = getField(index).addWrapPartial(
0593: this ,
0594: index,
0595: newValues,
0596: FieldUtils.safeMultiply(period.getValue(i),
0597: scalar));
0598: }
0599: }
0600: return new TimeOfDay(this , newValues);
0601: }
0602:
0603: //-----------------------------------------------------------------------
0604: /**
0605: * Returns a copy of this time with the specified period added,
0606: * wrapping to what would be a new day if required.
0607: * <p>
0608: * If the amount is zero or null, then <code>this</code> is returned.
0609: * <p>
0610: * This method is typically used to add complex period instances.
0611: * Adding one field is best achieved using methods
0612: * like {@link #plusHours(int)}.
0613: *
0614: * @param period the duration to add to this one, null means zero
0615: * @return a copy of this instance with the period added
0616: * @throws ArithmeticException if the new datetime exceeds the capacity of a long
0617: */
0618: public TimeOfDay plus(ReadablePeriod period) {
0619: return withPeriodAdded(period, 1);
0620: }
0621:
0622: //-----------------------------------------------------------------------
0623: /**
0624: * Returns a copy of this time plus the specified number of hours.
0625: * <p>
0626: * This time instance is immutable and unaffected by this method call.
0627: * <p>
0628: * The following three lines are identical in effect:
0629: * <pre>
0630: * TimeOfDay added = dt.plusHours(6);
0631: * TimeOfDay added = dt.plus(Period.hours(6));
0632: * TimeOfDay added = dt.withFieldAdded(DurationFieldType.hours(), 6);
0633: * </pre>
0634: *
0635: * @param hours the amount of hours to add, may be negative
0636: * @return the new time plus the increased hours
0637: * @since 1.1
0638: */
0639: public TimeOfDay plusHours(int hours) {
0640: return withFieldAdded(DurationFieldType.hours(), hours);
0641: }
0642:
0643: /**
0644: * Returns a copy of this time plus the specified number of minutes.
0645: * <p>
0646: * This time instance is immutable and unaffected by this method call.
0647: * <p>
0648: * The following three lines are identical in effect:
0649: * <pre>
0650: * TimeOfDay added = dt.plusMinutes(6);
0651: * TimeOfDay added = dt.plus(Period.minutes(6));
0652: * TimeOfDay added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
0653: * </pre>
0654: *
0655: * @param minutes the amount of minutes to add, may be negative
0656: * @return the new time plus the increased minutes
0657: * @since 1.1
0658: */
0659: public TimeOfDay plusMinutes(int minutes) {
0660: return withFieldAdded(DurationFieldType.minutes(), minutes);
0661: }
0662:
0663: /**
0664: * Returns a copy of this time plus the specified number of seconds.
0665: * <p>
0666: * This time instance is immutable and unaffected by this method call.
0667: * <p>
0668: * The following three lines are identical in effect:
0669: * <pre>
0670: * TimeOfDay added = dt.plusSeconds(6);
0671: * TimeOfDay added = dt.plus(Period.seconds(6));
0672: * TimeOfDay added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
0673: * </pre>
0674: *
0675: * @param seconds the amount of seconds to add, may be negative
0676: * @return the new time plus the increased seconds
0677: * @since 1.1
0678: */
0679: public TimeOfDay plusSeconds(int seconds) {
0680: return withFieldAdded(DurationFieldType.seconds(), seconds);
0681: }
0682:
0683: /**
0684: * Returns a copy of this time plus the specified number of millis.
0685: * <p>
0686: * This time instance is immutable and unaffected by this method call.
0687: * <p>
0688: * The following three lines are identical in effect:
0689: * <pre>
0690: * TimeOfDay added = dt.plusMillis(6);
0691: * TimeOfDay added = dt.plus(Period.millis(6));
0692: * TimeOfDay added = dt.withFieldAdded(DurationFieldType.millis(), 6);
0693: * </pre>
0694: *
0695: * @param millis the amount of millis to add, may be negative
0696: * @return the new time plus the increased millis
0697: * @since 1.1
0698: */
0699: public TimeOfDay plusMillis(int millis) {
0700: return withFieldAdded(DurationFieldType.millis(), millis);
0701: }
0702:
0703: //-----------------------------------------------------------------------
0704: /**
0705: * Returns a copy of this time with the specified period taken away,
0706: * wrapping to what would be a new day if required.
0707: * <p>
0708: * If the amount is zero or null, then <code>this</code> is returned.
0709: * <p>
0710: * This method is typically used to subtract complex period instances.
0711: * Subtracting one field is best achieved using methods
0712: * like {@link #minusHours(int)}.
0713: *
0714: * @param period the period to reduce this instant by
0715: * @return a copy of this instance with the period taken away
0716: * @throws ArithmeticException if the new time exceeds capacity
0717: */
0718: public TimeOfDay minus(ReadablePeriod period) {
0719: return withPeriodAdded(period, -1);
0720: }
0721:
0722: //-----------------------------------------------------------------------
0723: /**
0724: * Returns a copy of this time minus the specified number of hours.
0725: * <p>
0726: * This time instance is immutable and unaffected by this method call.
0727: * <p>
0728: * The following three lines are identical in effect:
0729: * <pre>
0730: * TimeOfDay subtracted = dt.minusHours(6);
0731: * TimeOfDay subtracted = dt.minus(Period.hours(6));
0732: * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
0733: * </pre>
0734: *
0735: * @param hours the amount of hours to subtract, may be negative
0736: * @return the new time minus the increased hours
0737: * @since 1.1
0738: */
0739: public TimeOfDay minusHours(int hours) {
0740: return withFieldAdded(DurationFieldType.hours(), FieldUtils
0741: .safeNegate(hours));
0742: }
0743:
0744: /**
0745: * Returns a copy of this time minus the specified number of minutes.
0746: * <p>
0747: * This time instance is immutable and unaffected by this method call.
0748: * <p>
0749: * The following three lines are identical in effect:
0750: * <pre>
0751: * TimeOfDay subtracted = dt.minusMinutes(6);
0752: * TimeOfDay subtracted = dt.minus(Period.minutes(6));
0753: * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
0754: * </pre>
0755: *
0756: * @param minutes the amount of minutes to subtract, may be negative
0757: * @return the new time minus the increased minutes
0758: * @since 1.1
0759: */
0760: public TimeOfDay minusMinutes(int minutes) {
0761: return withFieldAdded(DurationFieldType.minutes(), FieldUtils
0762: .safeNegate(minutes));
0763: }
0764:
0765: /**
0766: * Returns a copy of this time minus the specified number of seconds.
0767: * <p>
0768: * This time instance is immutable and unaffected by this method call.
0769: * <p>
0770: * The following three lines are identical in effect:
0771: * <pre>
0772: * TimeOfDay subtracted = dt.minusSeconds(6);
0773: * TimeOfDay subtracted = dt.minus(Period.seconds(6));
0774: * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
0775: * </pre>
0776: *
0777: * @param seconds the amount of seconds to subtract, may be negative
0778: * @return the new time minus the increased seconds
0779: * @since 1.1
0780: */
0781: public TimeOfDay minusSeconds(int seconds) {
0782: return withFieldAdded(DurationFieldType.seconds(), FieldUtils
0783: .safeNegate(seconds));
0784: }
0785:
0786: /**
0787: * Returns a copy of this time minus the specified number of millis.
0788: * <p>
0789: * This time instance is immutable and unaffected by this method call.
0790: * <p>
0791: * The following three lines are identical in effect:
0792: * <pre>
0793: * TimeOfDay subtracted = dt.minusMillis(6);
0794: * TimeOfDay subtracted = dt.minus(Period.millis(6));
0795: * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
0796: * </pre>
0797: *
0798: * @param millis the amount of millis to subtract, may be negative
0799: * @return the new time minus the increased millis
0800: * @since 1.1
0801: */
0802: public TimeOfDay minusMillis(int millis) {
0803: return withFieldAdded(DurationFieldType.millis(), FieldUtils
0804: .safeNegate(millis));
0805: }
0806:
0807: //-----------------------------------------------------------------------
0808: /**
0809: * Gets the property object for the specified type, which contains
0810: * many useful methods.
0811: *
0812: * @param type the field type to get the property for
0813: * @return the property object
0814: * @throws IllegalArgumentException if the field is null or unsupported
0815: */
0816: public Property property(DateTimeFieldType type) {
0817: return new Property(this , indexOfSupported(type));
0818: }
0819:
0820: //-----------------------------------------------------------------------
0821: /**
0822: * Converts this object to a LocalTime with the same time and chronology.
0823: *
0824: * @return a LocalTime with the same time and chronology
0825: * @since 1.3
0826: */
0827: public LocalTime toLocalTime() {
0828: return new LocalTime(getHourOfDay(), getMinuteOfHour(),
0829: getSecondOfMinute(), getMillisOfSecond(),
0830: getChronology());
0831: }
0832:
0833: //-----------------------------------------------------------------------
0834: /**
0835: * Converts this partial to a full datetime using the default time zone
0836: * setting the time fields from this instance and the date fields from
0837: * the current time.
0838: *
0839: * @return this date as a datetime with the time as the current time
0840: */
0841: public DateTime toDateTimeToday() {
0842: return toDateTimeToday(null);
0843: }
0844:
0845: /**
0846: * Converts this partial to a full datetime using the specified time zone
0847: * setting the time fields from this instance and the date fields from
0848: * the current time.
0849: * <p>
0850: * This method uses the chronology from this instance plus the time zone
0851: * specified.
0852: *
0853: * @param zone the zone to use, null means default
0854: * @return this date as a datetime with the time as the current time
0855: */
0856: public DateTime toDateTimeToday(DateTimeZone zone) {
0857: Chronology chrono = getChronology().withZone(zone);
0858: long instantMillis = DateTimeUtils.currentTimeMillis();
0859: long resolved = chrono.set(this , instantMillis);
0860: return new DateTime(resolved, chrono);
0861: }
0862:
0863: //-----------------------------------------------------------------------
0864: /**
0865: * Get the hour of day (0-23) field value.
0866: *
0867: * @return the hour of day
0868: */
0869: public int getHourOfDay() {
0870: return getValue(HOUR_OF_DAY);
0871: }
0872:
0873: /**
0874: * Get the minute of hour field value.
0875: *
0876: * @return the minute of hour
0877: */
0878: public int getMinuteOfHour() {
0879: return getValue(MINUTE_OF_HOUR);
0880: }
0881:
0882: /**
0883: * Get the second of minute field value.
0884: *
0885: * @return the second of minute
0886: */
0887: public int getSecondOfMinute() {
0888: return getValue(SECOND_OF_MINUTE);
0889: }
0890:
0891: /**
0892: * Get the millis of second field value.
0893: *
0894: * @return the millis of second
0895: */
0896: public int getMillisOfSecond() {
0897: return getValue(MILLIS_OF_SECOND);
0898: }
0899:
0900: //-----------------------------------------------------------------------
0901: /**
0902: * Returns a copy of this time with the hour of day field updated.
0903: * <p>
0904: * TimeOfDay is immutable, so there are no set methods.
0905: * Instead, this method returns a new instance with the value of
0906: * hour of day changed.
0907: *
0908: * @param hour the hour of day to set
0909: * @return a copy of this object with the field set
0910: * @throws IllegalArgumentException if the value is invalid
0911: * @since 1.3
0912: */
0913: public TimeOfDay withHourOfDay(int hour) {
0914: int[] newValues = getValues();
0915: newValues = getChronology().hourOfDay().set(this , HOUR_OF_DAY,
0916: newValues, hour);
0917: return new TimeOfDay(this , newValues);
0918: }
0919:
0920: /**
0921: * Returns a copy of this time with the minute of hour field updated.
0922: * <p>
0923: * TimeOfDay is immutable, so there are no set methods.
0924: * Instead, this method returns a new instance with the value of
0925: * minute of hour changed.
0926: *
0927: * @param minute the minute of hour to set
0928: * @return a copy of this object with the field set
0929: * @throws IllegalArgumentException if the value is invalid
0930: * @since 1.3
0931: */
0932: public TimeOfDay withMinuteOfHour(int minute) {
0933: int[] newValues = getValues();
0934: newValues = getChronology().minuteOfHour().set(this ,
0935: MINUTE_OF_HOUR, newValues, minute);
0936: return new TimeOfDay(this , newValues);
0937: }
0938:
0939: /**
0940: * Returns a copy of this time with the second of minute field updated.
0941: * <p>
0942: * TimeOfDay is immutable, so there are no set methods.
0943: * Instead, this method returns a new instance with the value of
0944: * second of minute changed.
0945: *
0946: * @param second the second of minute to set
0947: * @return a copy of this object with the field set
0948: * @throws IllegalArgumentException if the value is invalid
0949: * @since 1.3
0950: */
0951: public TimeOfDay withSecondOfMinute(int second) {
0952: int[] newValues = getValues();
0953: newValues = getChronology().secondOfMinute().set(this ,
0954: SECOND_OF_MINUTE, newValues, second);
0955: return new TimeOfDay(this , newValues);
0956: }
0957:
0958: /**
0959: * Returns a copy of this time with the millis of second field updated.
0960: * <p>
0961: * TimeOfDay is immutable, so there are no set methods.
0962: * Instead, this method returns a new instance with the value of
0963: * millis of second changed.
0964: *
0965: * @param millis the millis of second to set
0966: * @return a copy of this object with the field set
0967: * @throws IllegalArgumentException if the value is invalid
0968: * @since 1.3
0969: */
0970: public TimeOfDay withMillisOfSecond(int millis) {
0971: int[] newValues = getValues();
0972: newValues = getChronology().millisOfSecond().set(this ,
0973: MILLIS_OF_SECOND, newValues, millis);
0974: return new TimeOfDay(this , newValues);
0975: }
0976:
0977: //-----------------------------------------------------------------------
0978: /**
0979: * Get the hour of day field property which provides access to advanced functionality.
0980: *
0981: * @return the hour of day property
0982: */
0983: public Property hourOfDay() {
0984: return new Property(this , HOUR_OF_DAY);
0985: }
0986:
0987: /**
0988: * Get the minute of hour field property which provides access to advanced functionality.
0989: *
0990: * @return the minute of hour property
0991: */
0992: public Property minuteOfHour() {
0993: return new Property(this , MINUTE_OF_HOUR);
0994: }
0995:
0996: /**
0997: * Get the second of minute field property which provides access to advanced functionality.
0998: *
0999: * @return the second of minute property
1000: */
1001: public Property secondOfMinute() {
1002: return new Property(this , SECOND_OF_MINUTE);
1003: }
1004:
1005: /**
1006: * Get the millis of second property which provides access to advanced functionality.
1007: *
1008: * @return the millis of second property
1009: */
1010: public Property millisOfSecond() {
1011: return new Property(this , MILLIS_OF_SECOND);
1012: }
1013:
1014: //-----------------------------------------------------------------------
1015: /**
1016: * Output the time in the ISO8601 format THH:mm:ss.SSS.
1017: *
1018: * @return ISO8601 formatted string
1019: */
1020: public String toString() {
1021: return ISODateTimeFormat.tTime().print(this );
1022: }
1023:
1024: //-----------------------------------------------------------------------
1025: /**
1026: * The property class for <code>TimeOfDay</code>.
1027: * <p>
1028: * This class binds a <code>TimeOfDay</code> to a <code>DateTimeField</code>.
1029: *
1030: * @author Stephen Colebourne
1031: * @since 1.0
1032: * @deprecated Use LocalTime which has a much better internal implementation
1033: */
1034: public static class Property extends AbstractPartialFieldProperty
1035: implements Serializable {
1036:
1037: /** Serialization version */
1038: private static final long serialVersionUID = 5598459141741063833L;
1039:
1040: /** The partial */
1041: private final TimeOfDay iTimeOfDay;
1042: /** The field index */
1043: private final int iFieldIndex;
1044:
1045: /**
1046: * Constructs a property.
1047: *
1048: * @param partial the partial instance
1049: * @param fieldIndex the index in the partial
1050: */
1051: Property(TimeOfDay partial, int fieldIndex) {
1052: super ();
1053: iTimeOfDay = partial;
1054: iFieldIndex = fieldIndex;
1055: }
1056:
1057: /**
1058: * Gets the field that this property uses.
1059: *
1060: * @return the field
1061: */
1062: public DateTimeField getField() {
1063: return iTimeOfDay.getField(iFieldIndex);
1064: }
1065:
1066: /**
1067: * Gets the partial that this property belongs to.
1068: *
1069: * @return the partial
1070: */
1071: protected ReadablePartial getReadablePartial() {
1072: return iTimeOfDay;
1073: }
1074:
1075: /**
1076: * Gets the partial that this property belongs to.
1077: *
1078: * @return the partial
1079: */
1080: public TimeOfDay getTimeOfDay() {
1081: return iTimeOfDay;
1082: }
1083:
1084: /**
1085: * Gets the value of this field.
1086: *
1087: * @return the field value
1088: */
1089: public int get() {
1090: return iTimeOfDay.getValue(iFieldIndex);
1091: }
1092:
1093: //-----------------------------------------------------------------------
1094: /**
1095: * Adds to the value of this field in a copy of this TimeOfDay,
1096: * wrapping to what would be the next day if necessary.
1097: * <p>
1098: * The value will be added to this field. If the value is too large to be
1099: * added solely to this field then it will affect larger fields.
1100: * Smaller fields are unaffected.
1101: * <p>
1102: * If the result would be too large, beyond 23:59:59:999, then the
1103: * calculation wraps to 00:00:00.000. For the alternate strict behaviour
1104: * with no wrapping see {@link #addNoWrapToCopy(int)}.
1105: * <p>
1106: * The TimeOfDay attached to this property is unchanged by this call.
1107: * Instead, a new instance is returned.
1108: *
1109: * @param valueToAdd the value to add to the field in the copy
1110: * @return a copy of the TimeOfDay with the field value changed
1111: * @throws IllegalArgumentException if the value isn't valid
1112: */
1113: public TimeOfDay addToCopy(int valueToAdd) {
1114: int[] newValues = iTimeOfDay.getValues();
1115: newValues = getField().addWrapPartial(iTimeOfDay,
1116: iFieldIndex, newValues, valueToAdd);
1117: return new TimeOfDay(iTimeOfDay, newValues);
1118: }
1119:
1120: /**
1121: * Adds to the value of this field in a copy of this TimeOfDay,
1122: * throwing an Exception if the bounds are exceeded.
1123: * <p>
1124: * The value will be added to this field. If the value is too large to be
1125: * added solely to this field then it will affect larger fields.
1126: * Smaller fields are unaffected.
1127: * <p>
1128: * If the result would be too large (beyond 23:59:59:999) or too
1129: * small (less than 00:00:00.000) then an Execption is thrown.
1130: * For the alternate behaviour which wraps to the next 'day',
1131: * see {@link #addToCopy(int)}.
1132: * <p>
1133: * The TimeOfDay attached to this property is unchanged by this call.
1134: * Instead, a new instance is returned.
1135: *
1136: * @param valueToAdd the value to add to the field in the copy
1137: * @return a copy of the TimeOfDay with the field value changed
1138: * @throws IllegalArgumentException if the value isn't valid
1139: */
1140: public TimeOfDay addNoWrapToCopy(int valueToAdd) {
1141: int[] newValues = iTimeOfDay.getValues();
1142: newValues = getField().add(iTimeOfDay, iFieldIndex,
1143: newValues, valueToAdd);
1144: return new TimeOfDay(iTimeOfDay, newValues);
1145: }
1146:
1147: /**
1148: * Adds to the value of this field in a copy of this TimeOfDay wrapping
1149: * within this field if the maximum value is reached.
1150: * <p>
1151: * The value will be added to this field. If the value is too large to be
1152: * added solely to this field then it wraps within this field.
1153: * Other fields are unaffected.
1154: * <p>
1155: * For example,
1156: * <code>12:59:37</code> addWrapField one minute returns <code>12:00:37</code>.
1157: * <p>
1158: * The TimeOfDay attached to this property is unchanged by this call.
1159: * Instead, a new instance is returned.
1160: *
1161: * @param valueToAdd the value to add to the field in the copy
1162: * @return a copy of the TimeOfDay with the field value changed
1163: * @throws IllegalArgumentException if the value isn't valid
1164: */
1165: public TimeOfDay addWrapFieldToCopy(int valueToAdd) {
1166: int[] newValues = iTimeOfDay.getValues();
1167: newValues = getField().addWrapField(iTimeOfDay,
1168: iFieldIndex, newValues, valueToAdd);
1169: return new TimeOfDay(iTimeOfDay, newValues);
1170: }
1171:
1172: //-----------------------------------------------------------------------
1173: /**
1174: * Sets this field in a copy of the TimeOfDay.
1175: * <p>
1176: * The TimeOfDay attached to this property is unchanged by this call.
1177: * Instead, a new instance is returned.
1178: *
1179: * @param value the value to set the field in the copy to
1180: * @return a copy of the TimeOfDay with the field value changed
1181: * @throws IllegalArgumentException if the value isn't valid
1182: */
1183: public TimeOfDay setCopy(int value) {
1184: int[] newValues = iTimeOfDay.getValues();
1185: newValues = getField().set(iTimeOfDay, iFieldIndex,
1186: newValues, value);
1187: return new TimeOfDay(iTimeOfDay, newValues);
1188: }
1189:
1190: /**
1191: * Sets this field in a copy of the TimeOfDay to a parsed text value.
1192: * <p>
1193: * The TimeOfDay attached to this property is unchanged by this call.
1194: * Instead, a new instance is returned.
1195: *
1196: * @param text the text value to set
1197: * @param locale optional locale to use for selecting a text symbol
1198: * @return a copy of the TimeOfDay with the field value changed
1199: * @throws IllegalArgumentException if the text value isn't valid
1200: */
1201: public TimeOfDay setCopy(String text, Locale locale) {
1202: int[] newValues = iTimeOfDay.getValues();
1203: newValues = getField().set(iTimeOfDay, iFieldIndex,
1204: newValues, text, locale);
1205: return new TimeOfDay(iTimeOfDay, newValues);
1206: }
1207:
1208: /**
1209: * Sets this field in a copy of the TimeOfDay to a parsed text value.
1210: * <p>
1211: * The TimeOfDay attached to this property is unchanged by this call.
1212: * Instead, a new instance is returned.
1213: *
1214: * @param text the text value to set
1215: * @return a copy of the TimeOfDay with the field value changed
1216: * @throws IllegalArgumentException if the text value isn't valid
1217: */
1218: public TimeOfDay setCopy(String text) {
1219: return setCopy(text, null);
1220: }
1221:
1222: //-----------------------------------------------------------------------
1223: /**
1224: * Returns a new TimeOfDay with this field set to the maximum value
1225: * for this field.
1226: * <p>
1227: * The TimeOfDay attached to this property is unchanged by this call.
1228: *
1229: * @return a copy of the TimeOfDay with this field set to its maximum
1230: * @since 1.2
1231: */
1232: public TimeOfDay withMaximumValue() {
1233: return setCopy(getMaximumValue());
1234: }
1235:
1236: /**
1237: * Returns a new TimeOfDay with this field set to the minimum value
1238: * for this field.
1239: * <p>
1240: * The TimeOfDay attached to this property is unchanged by this call.
1241: *
1242: * @return a copy of the TimeOfDay with this field set to its minimum
1243: * @since 1.2
1244: */
1245: public TimeOfDay withMinimumValue() {
1246: return setCopy(getMinimumValue());
1247: }
1248: }
1249:
1250: }
|