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