001/*
002 *  Copyright 2001-2011 Stephen Colebourne
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.joda.time;
017
018import java.io.Serializable;
019import java.util.Calendar;
020import java.util.Date;
021import java.util.Locale;
022
023import org.joda.time.base.BasePartial;
024import org.joda.time.chrono.ISOChronology;
025import org.joda.time.field.AbstractPartialFieldProperty;
026import org.joda.time.field.FieldUtils;
027import org.joda.time.format.ISODateTimeFormat;
028
029/**
030 * TimeOfDay is an immutable partial supporting the hour, minute, second
031 * and millisecond fields.
032 * <p>
033 * NOTE: This class only supports the four fields listed above. Thus, you
034 * cannot query the millisOfDay or secondOfDay fields for example.
035 * The new <code>LocalTime</code> class removes this restriction.
036 * <p>
037 * Calculations on TimeOfDay are performed using a {@link Chronology}.
038 * This chronology is set to be in the UTC time zone for all calculations.
039 * <p>
040 * Each individual field can be queried in two ways:
041 * <ul>
042 * <li><code>getHourOfDay()</code>
043 * <li><code>hourOfDay().get()</code>
044 * </ul>
045 * The second technique also provides access to other useful methods on the
046 * field:
047 * <ul>
048 * <li>numeric value - <code>hourOfDay().get()</code>
049 * <li>text value - <code>hourOfDay().getAsText()</code>
050 * <li>short text value - <code>hourOfDay().getAsShortText()</code>
051 * <li>maximum/minimum values - <code>hourOfDay().getMaximumValue()</code>
052 * <li>add/subtract - <code>hourOfDay().addToCopy()</code>
053 * <li>set - <code>hourOfDay().setCopy()</code>
054 * </ul>
055 * <p>
056 * TimeOfDay is thread-safe and immutable, provided that the Chronology is as well.
057 * All standard Chronology classes supplied are thread-safe and immutable.
058 *
059 * @author Stephen Colebourne
060 * @author Brian S O'Neill
061 * @since 1.0
062 * @deprecated Use LocalTime which has a much better internal implementation and
063 *  has been available since 1.3
064 */
065@Deprecated
066public final class TimeOfDay
067        extends BasePartial
068        implements ReadablePartial, Serializable {
069    // NOTE: No toDateTime(YearMonthDay) as semantics are confusing when
070    // different chronologies
071
072    /** Serialization version */
073    private static final long serialVersionUID = 3633353405803318660L;
074    /** The singleton set of field types */
075    private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
076        DateTimeFieldType.hourOfDay(),
077        DateTimeFieldType.minuteOfHour(),
078        DateTimeFieldType.secondOfMinute(),
079        DateTimeFieldType.millisOfSecond(),
080    };
081
082    /** Constant for midnight. */
083    public static final TimeOfDay MIDNIGHT = new TimeOfDay(0, 0, 0, 0);
084
085    /** The index of the hourOfDay field in the field array */
086    public static final int HOUR_OF_DAY = 0;
087    /** The index of the minuteOfHour field in the field array */
088    public static final int MINUTE_OF_HOUR = 1;
089    /** The index of the secondOfMinute field in the field array */
090    public static final int SECOND_OF_MINUTE = 2;
091    /** The index of the millisOfSecond field in the field array */
092    public static final int MILLIS_OF_SECOND = 3;
093
094    //-----------------------------------------------------------------------
095    /**
096     * Constructs a TimeOfDay from a <code>java.util.Calendar</code>
097     * using exactly the same field values avoiding any time zone effects.
098     * <p>
099     * Each field is queried from the Calendar and assigned to the TimeOfDay.
100     * This is useful to ensure that the field values are the same in the
101     * created TimeOfDay no matter what the time zone is. For example, if
102     * the Calendar states that the time is 04:29, then the created TimeOfDay
103     * will always have the time 04:29 irrespective of time zone issues.
104     * <p>
105     * This factory method ignores the type of the calendar and always
106     * creates a TimeOfDay with ISO chronology.
107     *
108     * @param calendar  the Calendar to extract fields from
109     * @return the created TimeOfDay
110     * @throws IllegalArgumentException if the calendar is null
111     * @throws IllegalArgumentException if the time is invalid for the ISO chronology
112     * @since 1.2
113     */
114    public static TimeOfDay fromCalendarFields(Calendar calendar) {
115        if (calendar == null) {
116            throw new IllegalArgumentException("The calendar must not be null");
117        }
118        return new TimeOfDay(
119            calendar.get(Calendar.HOUR_OF_DAY),
120            calendar.get(Calendar.MINUTE),
121            calendar.get(Calendar.SECOND),
122            calendar.get(Calendar.MILLISECOND)
123        );
124    }
125
126    /**
127     * Constructs a TimeOfDay from a <code>java.util.Date</code>
128     * using exactly the same field values avoiding any time zone effects.
129     * <p>
130     * Each field is queried from the Date and assigned to the TimeOfDay.
131     * This is useful to ensure that the field values are the same in the
132     * created TimeOfDay no matter what the time zone is. For example, if
133     * the Calendar states that the time is 04:29, then the created TimeOfDay
134     * will always have the time 04:29 irrespective of time zone issues.
135     * <p>
136     * This factory method always creates a TimeOfDay with ISO chronology.
137     *
138     * @param date  the Date to extract fields from
139     * @return the created TimeOfDay
140     * @throws IllegalArgumentException if the calendar is null
141     * @throws IllegalArgumentException if the date is invalid for the ISO chronology
142     * @since 1.2
143     */
144    public static TimeOfDay fromDateFields(Date date) {
145        if (date == null) {
146            throw new IllegalArgumentException("The date must not be null");
147        }
148        return new TimeOfDay(
149            date.getHours(),
150            date.getMinutes(),
151            date.getSeconds(),
152            (((int) (date.getTime() % 1000)) + 1000) % 1000
153        );
154    }
155
156    //-----------------------------------------------------------------------
157    /**
158     * Constructs a TimeOfDay from the specified millis of day using the
159     * ISO chronology.
160     * <p>
161     * The millisOfDay value may exceed the number of millis in one day,
162     * but additional days will be ignored.
163     * This method uses the UTC time zone internally.
164     *
165     * @param millisOfDay  the number of milliseconds into a day to convert
166     */
167    public static TimeOfDay fromMillisOfDay(long millisOfDay) {
168        return fromMillisOfDay(millisOfDay, null);
169    }
170
171    /**
172     * Constructs a TimeOfDay from the specified millis of day using the
173     * specified chronology.
174     * <p>
175     * The millisOfDay value may exceed the number of millis in one day,
176     * but additional days will be ignored.
177     * This method uses the UTC time zone internally.
178     *
179     * @param millisOfDay  the number of milliseconds into a day to convert
180     * @param chrono  the chronology, null means ISO chronology
181     */
182    public static TimeOfDay fromMillisOfDay(long millisOfDay, Chronology chrono) {
183        chrono = DateTimeUtils.getChronology(chrono);
184        chrono = chrono.withUTC();
185        return new TimeOfDay(millisOfDay, chrono);
186    }
187
188    // Constructors
189    //-----------------------------------------------------------------------
190    /**
191     * Constructs a TimeOfDay with the current time, using ISOChronology in
192     * the default zone to extract the fields.
193     * <p>
194     * The constructor uses the default time zone, resulting in the local time
195     * being initialised. Once the constructor is complete, all further calculations
196     * are performed without reference to a timezone (by switching to UTC).
197     */
198    public TimeOfDay() {
199        super();
200    }
201
202    /**
203     * Constructs a TimeOfDay with the current time, using ISOChronology in
204     * the specified zone to extract the fields.
205     * <p>
206     * The constructor uses the specified time zone to obtain the current time.
207     * Once the constructor is complete, all further calculations
208     * are performed without reference to a timezone (by switching to UTC).
209     * 
210     * @param zone  the zone to use, null means default zone
211     * @since 1.1
212     */
213    public TimeOfDay(DateTimeZone zone) {
214        super(ISOChronology.getInstance(zone));
215    }
216
217    /**
218     * Constructs a TimeOfDay with the current time, using the specified chronology
219     * and zone to extract the fields.
220     * <p>
221     * The constructor uses the time zone of the chronology specified.
222     * Once the constructor is complete, all further calculations are performed
223     * without reference to a timezone (by switching to UTC).
224     *
225     * @param chronology  the chronology, null means ISOChronology in the default zone
226     */
227    public TimeOfDay(Chronology chronology) {
228        super(chronology);
229    }
230
231    /**
232     * Constructs a TimeOfDay extracting the partial fields from the specified
233     * milliseconds using the ISOChronology in the default zone.
234     * <p>
235     * The constructor uses the default time zone, resulting in the local time
236     * being initialised. Once the constructor is complete, all further calculations
237     * are performed without reference to a timezone (by switching to UTC).
238     *
239     * @param instant  the milliseconds from 1970-01-01T00:00:00Z
240     */
241    public TimeOfDay(long instant) {
242        super(instant);
243    }
244
245    /**
246     * Constructs a TimeOfDay extracting the partial fields from the specified
247     * milliseconds using the chronology provided.
248     * <p>
249     * The constructor uses the time zone of the chronology specified.
250     * Once the constructor is complete, all further calculations are performed
251     * without reference to a timezone (by switching to UTC).
252     *
253     * @param instant  the milliseconds from 1970-01-01T00:00:00Z
254     * @param chronology  the chronology, null means ISOChronology in the default zone
255     */
256    public TimeOfDay(long instant, Chronology chronology) {
257        super(instant, chronology);
258    }
259
260    /**
261     * Constructs a TimeOfDay from an Object that represents a time.
262     * <p>
263     * The recognised object types are defined in
264     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
265     * include ReadableInstant, String, Calendar and Date.
266     * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
267     * <p>
268     * The chronology used will be derived from the object, defaulting to ISO.
269     * <p>
270     * NOTE: Prior to v1.3 the string format was described by
271     * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
272     *
273     * @param instant  the datetime object, null means now
274     * @throws IllegalArgumentException if the instant is invalid
275     */
276    public TimeOfDay(Object instant) {
277        super(instant, null, ISODateTimeFormat.timeParser());
278    }
279
280    /**
281     * Constructs a TimeOfDay from an Object that represents a time, using the
282     * specified chronology.
283     * <p>
284     * The recognised object types are defined in
285     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
286     * include ReadableInstant, String, Calendar and Date.
287     * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
288     * <p>
289     * The constructor uses the time zone of the chronology specified.
290     * Once the constructor is complete, all further calculations are performed
291     * without reference to a timezone (by switching to UTC).
292     * The specified chronology overrides that of the object.
293     * <p>
294     * NOTE: Prior to v1.3 the string format was described by
295     * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
296     *
297     * @param instant  the datetime object, null means now
298     * @param chronology  the chronology, null means ISO default
299     * @throws IllegalArgumentException if the instant is invalid
300     */
301    public TimeOfDay(Object instant, Chronology chronology) {
302        super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.timeParser());
303    }
304
305    /**
306     * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds
307     * using <code>ISOChronology</code> in the default zone.
308     * <p>
309     * The constructor uses the no time zone initialising the fields as provided.
310     * Once the constructor is complete, all further calculations
311     * are performed without reference to a timezone (by switching to UTC).
312     *
313     * @param hourOfDay  the hour of the day
314     * @param minuteOfHour  the minute of the hour
315     */
316    public TimeOfDay(int hourOfDay, int minuteOfHour) {
317        this(hourOfDay, minuteOfHour, 0, 0, null);
318    }
319
320    /**
321     * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds.
322     * <p>
323     * The constructor uses the time zone of the chronology specified.
324     * Once the constructor is complete, all further calculations are performed
325     * without reference to a timezone (by switching to UTC).
326     *
327     * @param hourOfDay  the hour of the day
328     * @param minuteOfHour  the minute of the hour
329     * @param chronology  the chronology, null means ISOChronology in the default zone
330     */
331    public TimeOfDay(int hourOfDay, int minuteOfHour, Chronology chronology) {
332        this(hourOfDay, minuteOfHour, 0, 0, chronology);
333    }
334
335    /**
336     * Constructs a TimeOfDay with specified time field values and zero milliseconds
337     * using <code>ISOChronology</code> in the default zone.
338     * <p>
339     * The constructor uses the no time zone initialising the fields as provided.
340     * Once the constructor is complete, all further calculations
341     * are performed without reference to a timezone (by switching to UTC).
342     *
343     * @param hourOfDay  the hour of the day
344     * @param minuteOfHour  the minute of the hour
345     * @param secondOfMinute  the second of the minute
346     */
347    public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute) {
348        this(hourOfDay, minuteOfHour, secondOfMinute, 0, null);
349    }
350
351    /**
352     * Constructs a TimeOfDay with specified time field values and zero milliseconds.
353     * <p>
354     * The constructor uses the time zone of the chronology specified.
355     * Once the constructor is complete, all further calculations are performed
356     * without reference to a timezone (by switching to UTC).
357     *
358     * @param hourOfDay  the hour of the day
359     * @param minuteOfHour  the minute of the hour
360     * @param secondOfMinute  the second of the minute
361     * @param chronology  the chronology, null means ISOChronology in the default zone
362     */
363    public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute, Chronology chronology) {
364        this(hourOfDay, minuteOfHour, secondOfMinute, 0, chronology);
365    }
366
367    /**
368     * Constructs a TimeOfDay with specified time field values using
369     * <code>ISOChronology</code> in the default zone.
370     * <p>
371     * The constructor uses the no time zone initialising the fields as provided.
372     * Once the constructor is complete, all further calculations
373     * are performed without reference to a timezone (by switching to UTC).
374     *
375     * @param hourOfDay  the hour of the day
376     * @param minuteOfHour  the minute of the hour
377     * @param secondOfMinute  the second of the minute
378     * @param millisOfSecond  the millisecond of the second
379     */
380    public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond) {
381        this(hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, null);
382    }
383
384    /**
385     * Constructs a TimeOfDay with specified time field values and chronology.
386     * <p>
387     * The constructor uses the time zone of the chronology specified.
388     * Once the constructor is complete, all further calculations are performed
389     * without reference to a timezone (by switching to UTC).
390     *
391     * @param hourOfDay  the hour of the day
392     * @param minuteOfHour  the minute of the hour
393     * @param secondOfMinute  the second of the minute
394     * @param millisOfSecond  the millisecond of the second
395     * @param chronology  the chronology, null means ISOChronology in the default zone
396     */
397    public TimeOfDay(int hourOfDay, int minuteOfHour,
398            int secondOfMinute, int millisOfSecond, Chronology chronology) {
399        super(new int[] {hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond}, chronology);
400    }
401
402    /**
403     * Constructs a TimeOfDay with chronology from this instance and new values.
404     *
405     * @param partial  the partial to base this new instance on
406     * @param values  the new set of values
407     */
408    TimeOfDay(TimeOfDay partial, int[] values) {
409        super(partial, values);
410    }
411
412    /**
413     * Constructs a TimeOfDay with values from this instance and a new chronology.
414     *
415     * @param partial  the partial to base this new instance on
416     * @param chrono  the new chronology
417     */
418    TimeOfDay(TimeOfDay partial, Chronology chrono) {
419        super(partial, chrono);
420    }
421
422    //-----------------------------------------------------------------------
423    /**
424     * Gets the number of fields in this partial.
425     * 
426     * @return the field count
427     */
428    public int size() {
429        return 4;
430    }
431
432    /**
433     * Gets the field for a specific index in the chronology specified.
434     * <p>
435     * This method must not use any instance variables.
436     * 
437     * @param index  the index to retrieve
438     * @param chrono  the chronology to use
439     * @return the field
440     */
441    protected DateTimeField getField(int index, Chronology chrono) {
442        switch (index) {
443            case HOUR_OF_DAY:
444                return chrono.hourOfDay();
445            case MINUTE_OF_HOUR:
446                return chrono.minuteOfHour();
447            case SECOND_OF_MINUTE:
448                return chrono.secondOfMinute();
449            case MILLIS_OF_SECOND:
450                return chrono.millisOfSecond();
451            default:
452                throw new IndexOutOfBoundsException("Invalid index: " + index);
453        }
454    }
455
456    /**
457     * Gets the field type at the specified index.
458     *
459     * @param index  the index to retrieve
460     * @return the field at the specified index
461     * @throws IndexOutOfBoundsException if the index is invalid
462     */
463    public DateTimeFieldType getFieldType(int index) {
464        return FIELD_TYPES[index];
465    }
466
467    /**
468     * Gets an array of the field type of each of the fields that this partial supports.
469     * <p>
470     * The fields are returned largest to smallest, Hour, Minute, Second, Millis.
471     *
472     * @return the array of field types (cloned), largest to smallest
473     */
474    public DateTimeFieldType[] getFieldTypes() {
475        return (DateTimeFieldType[]) FIELD_TYPES.clone();
476    }
477
478    //-----------------------------------------------------------------------
479    /**
480     * Returns a copy of this time with the specified chronology.
481     * This instance is immutable and unaffected by this method call.
482     * <p>
483     * This method retains the values of the fields, thus the result will
484     * typically refer to a different instant.
485     * <p>
486     * The time zone of the specified chronology is ignored, as TimeOfDay
487     * operates without a time zone.
488     *
489     * @param newChronology  the new chronology, null means ISO
490     * @return a copy of this datetime with a different chronology
491     * @throws IllegalArgumentException if the values are invalid for the new chronology
492     */
493    public TimeOfDay withChronologyRetainFields(Chronology newChronology) {
494        newChronology = DateTimeUtils.getChronology(newChronology);
495        newChronology = newChronology.withUTC();
496        if (newChronology == getChronology()) {
497            return this;
498        } else {
499            TimeOfDay newTimeOfDay = new TimeOfDay(this, newChronology);
500            newChronology.validate(newTimeOfDay, getValues());
501            return newTimeOfDay;
502        }
503    }
504
505    /**
506     * Returns a copy of this time with the specified field set to a new value.
507     * <p>
508     * For example, if the field type is <code>minuteOfHour</code> then the day
509     * would be changed in the returned instance.
510     * <p>
511     * These three lines are equivalent:
512     * <pre>
513     * TimeOfDay updated = tod.withField(DateTimeFieldType.minuteOfHour(), 6);
514     * TimeOfDay updated = tod.minuteOfHour().setCopy(6);
515     * TimeOfDay updated = tod.property(DateTimeFieldType.minuteOfHour()).setCopy(6);
516     * </pre>
517     *
518     * @param fieldType  the field type to set, not null
519     * @param value  the value to set
520     * @return a copy of this instance with the field set
521     * @throws IllegalArgumentException if the value is null or invalid
522     */
523    public TimeOfDay withField(DateTimeFieldType fieldType, int value) {
524        int index = indexOfSupported(fieldType);
525        if (value == getValue(index)) {
526            return this;
527        }
528        int[] newValues = getValues();
529        newValues = getField(index).set(this, index, newValues, value);
530        return new TimeOfDay(this, newValues);
531    }
532
533    /**
534     * Returns a copy of this time with the value of the specified field increased,
535     * wrapping to what would be a new day if required.
536     * <p>
537     * If the addition is zero, then <code>this</code> is returned.
538     * <p>
539     * These three lines are equivalent:
540     * <pre>
541     * TimeOfDay added = tod.withFieldAdded(DurationFieldType.minutes(), 6);
542     * TimeOfDay added = tod.plusMinutes(6);
543     * TimeOfDay added = tod.minuteOfHour().addToCopy(6);
544     * </pre>
545     * 
546     * @param fieldType  the field type to add to, not null
547     * @param amount  the amount to add
548     * @return a copy of this instance with the field updated
549     * @throws IllegalArgumentException if the value is null or invalid
550     * @throws ArithmeticException if the new datetime exceeds the capacity
551     */
552    public TimeOfDay withFieldAdded(DurationFieldType fieldType, int amount) {
553        int index = indexOfSupported(fieldType);
554        if (amount == 0) {
555            return this;
556        }
557        int[] newValues = getValues();
558        newValues = getField(index).addWrapPartial(this, index, newValues, amount);
559        return new TimeOfDay(this, newValues);
560    }
561
562    /**
563     * Returns a copy of this time with the specified period added,
564     * wrapping to what would be a new day if required.
565     * <p>
566     * If the addition is zero, then <code>this</code> is returned.
567     * Fields in the period that aren't present in the partial are ignored.
568     * <p>
569     * This method is typically used to add multiple copies of complex
570     * period instances. Adding one field is best achieved using methods
571     * like {@link #withFieldAdded(DurationFieldType, int)}
572     * or {@link #plusHours(int)}.
573     * 
574     * @param period  the period to add to this one, null means zero
575     * @param scalar  the amount of times to add, such as -1 to subtract once
576     * @return a copy of this instance with the period added
577     * @throws ArithmeticException if the new datetime exceeds the capacity
578     */
579    public TimeOfDay withPeriodAdded(ReadablePeriod period, int scalar) {
580        if (period == null || scalar == 0) {
581            return this;
582        }
583        int[] newValues = getValues();
584        for (int i = 0; i < period.size(); i++) {
585            DurationFieldType fieldType = period.getFieldType(i);
586            int index = indexOf(fieldType);
587            if (index >= 0) {
588                newValues = getField(index).addWrapPartial(this, index, newValues,
589                        FieldUtils.safeMultiply(period.getValue(i), scalar));
590            }
591        }
592        return new TimeOfDay(this, newValues);
593    }
594
595    //-----------------------------------------------------------------------
596    /**
597     * Returns a copy of this time with the specified period added,
598     * wrapping to what would be a new day if required.
599     * <p>
600     * If the amount is zero or null, then <code>this</code> is returned.
601     * <p>
602     * This method is typically used to add complex period instances.
603     * Adding one field is best achieved using methods
604     * like {@link #plusHours(int)}.
605     * 
606     * @param period  the duration to add to this one, null means zero
607     * @return a copy of this instance with the period added
608     * @throws ArithmeticException if the new datetime exceeds the capacity of a long
609     */
610    public TimeOfDay plus(ReadablePeriod period) {
611        return withPeriodAdded(period, 1);
612    }
613
614    //-----------------------------------------------------------------------
615    /**
616     * Returns a copy of this time plus the specified number of hours.
617     * <p>
618     * This time instance is immutable and unaffected by this method call.
619     * <p>
620     * The following three lines are identical in effect:
621     * <pre>
622     * TimeOfDay added = dt.plusHours(6);
623     * TimeOfDay added = dt.plus(Period.hours(6));
624     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.hours(), 6);
625     * </pre>
626     *
627     * @param hours  the amount of hours to add, may be negative
628     * @return the new time plus the increased hours
629     * @since 1.1
630     */
631    public TimeOfDay plusHours(int hours) {
632        return withFieldAdded(DurationFieldType.hours(), hours);
633    }
634
635    /**
636     * Returns a copy of this time plus the specified number of minutes.
637     * <p>
638     * This time instance is immutable and unaffected by this method call.
639     * <p>
640     * The following three lines are identical in effect:
641     * <pre>
642     * TimeOfDay added = dt.plusMinutes(6);
643     * TimeOfDay added = dt.plus(Period.minutes(6));
644     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
645     * </pre>
646     *
647     * @param minutes  the amount of minutes to add, may be negative
648     * @return the new time plus the increased minutes
649     * @since 1.1
650     */
651    public TimeOfDay plusMinutes(int minutes) {
652        return withFieldAdded(DurationFieldType.minutes(), minutes);
653    }
654
655    /**
656     * Returns a copy of this time plus the specified number of seconds.
657     * <p>
658     * This time instance is immutable and unaffected by this method call.
659     * <p>
660     * The following three lines are identical in effect:
661     * <pre>
662     * TimeOfDay added = dt.plusSeconds(6);
663     * TimeOfDay added = dt.plus(Period.seconds(6));
664     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
665     * </pre>
666     *
667     * @param seconds  the amount of seconds to add, may be negative
668     * @return the new time plus the increased seconds
669     * @since 1.1
670     */
671    public TimeOfDay plusSeconds(int seconds) {
672        return withFieldAdded(DurationFieldType.seconds(), seconds);
673    }
674
675    /**
676     * Returns a copy of this time plus the specified number of millis.
677     * <p>
678     * This time instance is immutable and unaffected by this method call.
679     * <p>
680     * The following three lines are identical in effect:
681     * <pre>
682     * TimeOfDay added = dt.plusMillis(6);
683     * TimeOfDay added = dt.plus(Period.millis(6));
684     * TimeOfDay added = dt.withFieldAdded(DurationFieldType.millis(), 6);
685     * </pre>
686     *
687     * @param millis  the amount of millis to add, may be negative
688     * @return the new time plus the increased millis
689     * @since 1.1
690     */
691    public TimeOfDay plusMillis(int millis) {
692        return withFieldAdded(DurationFieldType.millis(), millis);
693    }
694
695    //-----------------------------------------------------------------------
696    /**
697     * Returns a copy of this time with the specified period taken away,
698     * wrapping to what would be a new day if required.
699     * <p>
700     * If the amount is zero or null, then <code>this</code> is returned.
701     * <p>
702     * This method is typically used to subtract complex period instances.
703     * Subtracting one field is best achieved using methods
704     * like {@link #minusHours(int)}.
705     * 
706     * @param period  the period to reduce this instant by
707     * @return a copy of this instance with the period taken away
708     * @throws ArithmeticException if the new time exceeds capacity
709     */
710    public TimeOfDay minus(ReadablePeriod period) {
711        return withPeriodAdded(period, -1);
712    }
713
714    //-----------------------------------------------------------------------
715    /**
716     * Returns a copy of this time minus the specified number of hours.
717     * <p>
718     * This time instance is immutable and unaffected by this method call.
719     * <p>
720     * The following three lines are identical in effect:
721     * <pre>
722     * TimeOfDay subtracted = dt.minusHours(6);
723     * TimeOfDay subtracted = dt.minus(Period.hours(6));
724     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
725     * </pre>
726     *
727     * @param hours  the amount of hours to subtract, may be negative
728     * @return the new time minus the increased hours
729     * @since 1.1
730     */
731    public TimeOfDay minusHours(int hours) {
732        return withFieldAdded(DurationFieldType.hours(), FieldUtils.safeNegate(hours));
733    }
734
735    /**
736     * Returns a copy of this time minus the specified number of minutes.
737     * <p>
738     * This time instance is immutable and unaffected by this method call.
739     * <p>
740     * The following three lines are identical in effect:
741     * <pre>
742     * TimeOfDay subtracted = dt.minusMinutes(6);
743     * TimeOfDay subtracted = dt.minus(Period.minutes(6));
744     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
745     * </pre>
746     *
747     * @param minutes  the amount of minutes to subtract, may be negative
748     * @return the new time minus the increased minutes
749     * @since 1.1
750     */
751    public TimeOfDay minusMinutes(int minutes) {
752        return withFieldAdded(DurationFieldType.minutes(), FieldUtils.safeNegate(minutes));
753    }
754
755    /**
756     * Returns a copy of this time minus the specified number of seconds.
757     * <p>
758     * This time instance is immutable and unaffected by this method call.
759     * <p>
760     * The following three lines are identical in effect:
761     * <pre>
762     * TimeOfDay subtracted = dt.minusSeconds(6);
763     * TimeOfDay subtracted = dt.minus(Period.seconds(6));
764     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
765     * </pre>
766     *
767     * @param seconds  the amount of seconds to subtract, may be negative
768     * @return the new time minus the increased seconds
769     * @since 1.1
770     */
771    public TimeOfDay minusSeconds(int seconds) {
772        return withFieldAdded(DurationFieldType.seconds(), FieldUtils.safeNegate(seconds));
773    }
774
775    /**
776     * Returns a copy of this time minus the specified number of millis.
777     * <p>
778     * This time instance is immutable and unaffected by this method call.
779     * <p>
780     * The following three lines are identical in effect:
781     * <pre>
782     * TimeOfDay subtracted = dt.minusMillis(6);
783     * TimeOfDay subtracted = dt.minus(Period.millis(6));
784     * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
785     * </pre>
786     *
787     * @param millis  the amount of millis to subtract, may be negative
788     * @return the new time minus the increased millis
789     * @since 1.1
790     */
791    public TimeOfDay minusMillis(int millis) {
792        return withFieldAdded(DurationFieldType.millis(), FieldUtils.safeNegate(millis));
793    }
794
795    //-----------------------------------------------------------------------
796    /**
797     * Gets the property object for the specified type, which contains
798     * many useful methods.
799     *
800     * @param type  the field type to get the property for
801     * @return the property object
802     * @throws IllegalArgumentException if the field is null or unsupported
803     */
804    public Property property(DateTimeFieldType type) {
805        return new Property(this, indexOfSupported(type));
806    }
807
808    //-----------------------------------------------------------------------
809    /**
810     * Converts this object to a LocalTime with the same time and chronology.
811     *
812     * @return a LocalTime with the same time and chronology
813     * @since 1.3
814     */
815    public LocalTime toLocalTime() {
816        return new LocalTime(getHourOfDay(), getMinuteOfHour(),
817                getSecondOfMinute(), getMillisOfSecond(), getChronology());
818    }
819
820    //-----------------------------------------------------------------------
821    /**
822     * Converts this partial to a full datetime using the default time zone
823     * setting the time fields from this instance and the date fields from
824     * the current time.
825     *
826     * @return this date as a datetime with the time as the current time
827     */
828    public DateTime toDateTimeToday() {
829        return toDateTimeToday(null);
830    }
831
832    /**
833     * Converts this partial to a full datetime using the specified time zone
834     * setting the time fields from this instance and the date fields from
835     * the current time.
836     * <p>
837     * This method uses the chronology from this instance plus the time zone
838     * specified.
839     *
840     * @param zone  the zone to use, null means default
841     * @return this date as a datetime with the time as the current time
842     */
843    public DateTime toDateTimeToday(DateTimeZone zone) {
844        Chronology chrono = getChronology().withZone(zone);
845        long instantMillis = DateTimeUtils.currentTimeMillis();
846        long resolved = chrono.set(this, instantMillis);
847        return new DateTime(resolved, chrono);
848    }
849
850    //-----------------------------------------------------------------------
851    /**
852     * Get the hour of day (0-23) field value.
853     *
854     * @return the hour of day
855     */
856    public int getHourOfDay() {
857        return getValue(HOUR_OF_DAY);
858    }
859
860    /**
861     * Get the minute of hour field value.
862     *
863     * @return the minute of hour
864     */
865    public int getMinuteOfHour() {
866        return getValue(MINUTE_OF_HOUR);
867    }
868
869    /**
870     * Get the second of minute field value.
871     *
872     * @return the second of minute
873     */
874    public int getSecondOfMinute() {
875        return getValue(SECOND_OF_MINUTE);
876    }
877
878    /**
879     * Get the millis of second field value.
880     *
881     * @return the millis of second
882     */
883    public int getMillisOfSecond() {
884        return getValue(MILLIS_OF_SECOND);
885    }
886
887    //-----------------------------------------------------------------------
888    /**
889     * Returns a copy of this time with the hour of day field updated.
890     * <p>
891     * TimeOfDay is immutable, so there are no set methods.
892     * Instead, this method returns a new instance with the value of
893     * hour of day changed.
894     *
895     * @param hour  the hour of day to set
896     * @return a copy of this object with the field set
897     * @throws IllegalArgumentException if the value is invalid
898     * @since 1.3
899     */
900    public TimeOfDay withHourOfDay(int hour) {
901        int[] newValues = getValues();
902        newValues = getChronology().hourOfDay().set(this, HOUR_OF_DAY, newValues, hour);
903        return new TimeOfDay(this, newValues);
904    }
905
906    /**
907     * Returns a copy of this time with the minute of hour field updated.
908     * <p>
909     * TimeOfDay is immutable, so there are no set methods.
910     * Instead, this method returns a new instance with the value of
911     * minute of hour changed.
912     *
913     * @param minute  the minute of hour to set
914     * @return a copy of this object with the field set
915     * @throws IllegalArgumentException if the value is invalid
916     * @since 1.3
917     */
918    public TimeOfDay withMinuteOfHour(int minute) {
919        int[] newValues = getValues();
920        newValues = getChronology().minuteOfHour().set(this, MINUTE_OF_HOUR, newValues, minute);
921        return new TimeOfDay(this, newValues);
922    }
923
924    /**
925     * Returns a copy of this time with the second of minute field updated.
926     * <p>
927     * TimeOfDay is immutable, so there are no set methods.
928     * Instead, this method returns a new instance with the value of
929     * second of minute changed.
930     *
931     * @param second  the second of minute to set
932     * @return a copy of this object with the field set
933     * @throws IllegalArgumentException if the value is invalid
934     * @since 1.3
935     */
936    public TimeOfDay withSecondOfMinute(int second) {
937        int[] newValues = getValues();
938        newValues = getChronology().secondOfMinute().set(this, SECOND_OF_MINUTE, newValues, second);
939        return new TimeOfDay(this, newValues);
940    }
941
942    /**
943     * Returns a copy of this time with the millis of second field updated.
944     * <p>
945     * TimeOfDay is immutable, so there are no set methods.
946     * Instead, this method returns a new instance with the value of
947     * millis of second changed.
948     *
949     * @param millis  the millis of second to set
950     * @return a copy of this object with the field set
951     * @throws IllegalArgumentException if the value is invalid
952     * @since 1.3
953     */
954    public TimeOfDay withMillisOfSecond(int millis) {
955        int[] newValues = getValues();
956        newValues = getChronology().millisOfSecond().set(this, MILLIS_OF_SECOND, newValues, millis);
957        return new TimeOfDay(this, newValues);
958    }
959
960    //-----------------------------------------------------------------------
961    /**
962     * Get the hour of day field property which provides access to advanced functionality.
963     * 
964     * @return the hour of day property
965     */
966    public Property hourOfDay() {
967        return new Property(this, HOUR_OF_DAY);
968    }
969
970    /**
971     * Get the minute of hour field property which provides access to advanced functionality.
972     * 
973     * @return the minute of hour property
974     */
975    public Property minuteOfHour() {
976        return new Property(this, MINUTE_OF_HOUR);
977    }
978
979    /**
980     * Get the second of minute field property which provides access to advanced functionality.
981     * 
982     * @return the second of minute property
983     */
984    public Property secondOfMinute() {
985        return new Property(this, SECOND_OF_MINUTE);
986    }
987
988    /**
989     * Get the millis of second property which provides access to advanced functionality.
990     * 
991     * @return the millis of second property
992     */
993    public Property millisOfSecond() {
994        return new Property(this, MILLIS_OF_SECOND);
995    }
996
997    //-----------------------------------------------------------------------
998    /**
999     * Output the time in the ISO8601 format THH:mm:ss.SSS.
1000     * 
1001     * @return ISO8601 formatted string
1002     */
1003    public String toString() {
1004        return ISODateTimeFormat.tTime().print(this);
1005    }
1006
1007    //-----------------------------------------------------------------------
1008    /**
1009     * The property class for <code>TimeOfDay</code>.
1010     * <p>
1011     * This class binds a <code>TimeOfDay</code> to a <code>DateTimeField</code>.
1012     * 
1013     * @author Stephen Colebourne
1014     * @since 1.0
1015     * @deprecated Use LocalTime which has a much better internal implementation
1016     */
1017    @Deprecated
1018    public static class Property extends AbstractPartialFieldProperty implements Serializable {
1019
1020        /** Serialization version */
1021        private static final long serialVersionUID = 5598459141741063833L;
1022
1023        /** The partial */
1024        private final TimeOfDay iTimeOfDay;
1025        /** The field index */
1026        private final int iFieldIndex;
1027
1028        /**
1029         * Constructs a property.
1030         * 
1031         * @param partial  the partial instance
1032         * @param fieldIndex  the index in the partial
1033         */
1034        Property(TimeOfDay partial, int fieldIndex) {
1035            super();
1036            iTimeOfDay = partial;
1037            iFieldIndex = fieldIndex;
1038        }
1039
1040        /**
1041         * Gets the field that this property uses.
1042         * 
1043         * @return the field
1044         */
1045        public DateTimeField getField() {
1046            return iTimeOfDay.getField(iFieldIndex);
1047        }
1048
1049        /**
1050         * Gets the partial that this property belongs to.
1051         * 
1052         * @return the partial
1053         */
1054        protected ReadablePartial getReadablePartial() {
1055            return iTimeOfDay;
1056        }
1057
1058        /**
1059         * Gets the partial that this property belongs to.
1060         * 
1061         * @return the partial
1062         */
1063        public TimeOfDay getTimeOfDay() {
1064            return iTimeOfDay;
1065        }
1066
1067        /**
1068         * Gets the value of this field.
1069         * 
1070         * @return the field value
1071         */
1072        public int get() {
1073            return iTimeOfDay.getValue(iFieldIndex);
1074        }
1075
1076        //-----------------------------------------------------------------------
1077        /**
1078         * Adds to the value of this field in a copy of this TimeOfDay,
1079         * wrapping to what would be the next day if necessary.
1080         * <p>
1081         * The value will be added to this field. If the value is too large to be
1082         * added solely to this field then it will affect larger fields.
1083         * Smaller fields are unaffected.
1084         * <p>
1085         * If the result would be too large, beyond 23:59:59:999, then the
1086         * calculation wraps to 00:00:00.000. For the alternate strict behaviour
1087         * with no wrapping see {@link #addNoWrapToCopy(int)}.
1088         * <p>
1089         * The TimeOfDay attached to this property is unchanged by this call.
1090         * Instead, a new instance is returned.
1091         * 
1092         * @param valueToAdd  the value to add to the field in the copy
1093         * @return a copy of the TimeOfDay with the field value changed
1094         * @throws IllegalArgumentException if the value isn't valid
1095         */
1096        public TimeOfDay addToCopy(int valueToAdd) {
1097            int[] newValues = iTimeOfDay.getValues();
1098            newValues = getField().addWrapPartial(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1099            return new TimeOfDay(iTimeOfDay, newValues);
1100        }
1101
1102        /**
1103         * Adds to the value of this field in a copy of this TimeOfDay,
1104         * throwing an Exception if the bounds are exceeded.
1105         * <p>
1106         * The value will be added to this field. If the value is too large to be
1107         * added solely to this field then it will affect larger fields.
1108         * Smaller fields are unaffected.
1109         * <p>
1110         * If the result would be too large (beyond 23:59:59:999) or too
1111         * small (less than 00:00:00.000) then an Execption is thrown.
1112         * For the alternate behaviour which wraps to the next 'day',
1113         * see {@link #addToCopy(int)}.
1114         * <p>
1115         * The TimeOfDay attached to this property is unchanged by this call.
1116         * Instead, a new instance is returned.
1117         * 
1118         * @param valueToAdd  the value to add to the field in the copy
1119         * @return a copy of the TimeOfDay with the field value changed
1120         * @throws IllegalArgumentException if the value isn't valid
1121         */
1122        public TimeOfDay addNoWrapToCopy(int valueToAdd) {
1123            int[] newValues = iTimeOfDay.getValues();
1124            newValues = getField().add(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1125            return new TimeOfDay(iTimeOfDay, newValues);
1126        }
1127
1128        /**
1129         * Adds to the value of this field in a copy of this TimeOfDay wrapping
1130         * within this field if the maximum value is reached.
1131         * <p>
1132         * The value will be added to this field. If the value is too large to be
1133         * added solely to this field then it wraps within this field.
1134         * Other fields are unaffected.
1135         * <p>
1136         * For example,
1137         * <code>12:59:37</code> addWrapField one minute returns <code>12:00:37</code>.
1138         * <p>
1139         * The TimeOfDay attached to this property is unchanged by this call.
1140         * Instead, a new instance is returned.
1141         * 
1142         * @param valueToAdd  the value to add to the field in the copy
1143         * @return a copy of the TimeOfDay with the field value changed
1144         * @throws IllegalArgumentException if the value isn't valid
1145         */
1146        public TimeOfDay addWrapFieldToCopy(int valueToAdd) {
1147            int[] newValues = iTimeOfDay.getValues();
1148            newValues = getField().addWrapField(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1149            return new TimeOfDay(iTimeOfDay, newValues);
1150        }
1151
1152        //-----------------------------------------------------------------------
1153        /**
1154         * Sets this field in a copy of the TimeOfDay.
1155         * <p>
1156         * The TimeOfDay attached to this property is unchanged by this call.
1157         * Instead, a new instance is returned.
1158         * 
1159         * @param value  the value to set the field in the copy to
1160         * @return a copy of the TimeOfDay with the field value changed
1161         * @throws IllegalArgumentException if the value isn't valid
1162         */
1163        public TimeOfDay setCopy(int value) {
1164            int[] newValues = iTimeOfDay.getValues();
1165            newValues = getField().set(iTimeOfDay, iFieldIndex, newValues, value);
1166            return new TimeOfDay(iTimeOfDay, newValues);
1167        }
1168
1169        /**
1170         * Sets this field in a copy of the TimeOfDay to a parsed text value.
1171         * <p>
1172         * The TimeOfDay attached to this property is unchanged by this call.
1173         * Instead, a new instance is returned.
1174         * 
1175         * @param text  the text value to set
1176         * @param locale  optional locale to use for selecting a text symbol
1177         * @return a copy of the TimeOfDay with the field value changed
1178         * @throws IllegalArgumentException if the text value isn't valid
1179         */
1180        public TimeOfDay setCopy(String text, Locale locale) {
1181            int[] newValues = iTimeOfDay.getValues();
1182            newValues = getField().set(iTimeOfDay, iFieldIndex, newValues, text, locale);
1183            return new TimeOfDay(iTimeOfDay, newValues);
1184        }
1185
1186        /**
1187         * Sets this field in a copy of the TimeOfDay to a parsed text value.
1188         * <p>
1189         * The TimeOfDay attached to this property is unchanged by this call.
1190         * Instead, a new instance is returned.
1191         * 
1192         * @param text  the text value to set
1193         * @return a copy of the TimeOfDay with the field value changed
1194         * @throws IllegalArgumentException if the text value isn't valid
1195         */
1196        public TimeOfDay setCopy(String text) {
1197            return setCopy(text, null);
1198        }
1199
1200        //-----------------------------------------------------------------------
1201        /**
1202         * Returns a new TimeOfDay with this field set to the maximum value
1203         * for this field.
1204         * <p>
1205         * The TimeOfDay attached to this property is unchanged by this call.
1206         *
1207         * @return a copy of the TimeOfDay with this field set to its maximum
1208         * @since 1.2
1209         */
1210        public TimeOfDay withMaximumValue() {
1211            return setCopy(getMaximumValue());
1212        }
1213
1214        /**
1215         * Returns a new TimeOfDay with this field set to the minimum value
1216         * for this field.
1217         * <p>
1218         * The TimeOfDay attached to this property is unchanged by this call.
1219         *
1220         * @return a copy of the TimeOfDay with this field set to its minimum
1221         * @since 1.2
1222         */
1223        public TimeOfDay withMinimumValue() {
1224            return setCopy(getMinimumValue());
1225        }
1226    }
1227
1228}