View Javadoc

1   /*
2    *  Copyright 2001-2011 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time;
17  
18  import java.io.Serializable;
19  import java.util.Calendar;
20  import java.util.Date;
21  import java.util.Locale;
22  
23  import org.joda.time.base.BasePartial;
24  import org.joda.time.chrono.ISOChronology;
25  import org.joda.time.field.AbstractPartialFieldProperty;
26  import org.joda.time.field.FieldUtils;
27  import org.joda.time.format.ISODateTimeFormat;
28  
29  /**
30   * TimeOfDay is an immutable partial supporting the hour, minute, second
31   * and millisecond fields.
32   * <p>
33   * NOTE: This class only supports the four fields listed above. Thus, you
34   * cannot query the millisOfDay or secondOfDay fields for example.
35   * The new <code>LocalTime</code> class removes this restriction.
36   * <p>
37   * Calculations on TimeOfDay are performed using a {@link Chronology}.
38   * This chronology is set to be in the UTC time zone for all calculations.
39   * <p>
40   * Each individual field can be queried in two ways:
41   * <ul>
42   * <li><code>getHourOfDay()</code>
43   * <li><code>hourOfDay().get()</code>
44   * </ul>
45   * The second technique also provides access to other useful methods on the
46   * field:
47   * <ul>
48   * <li>numeric value - <code>hourOfDay().get()</code>
49   * <li>text value - <code>hourOfDay().getAsText()</code>
50   * <li>short text value - <code>hourOfDay().getAsShortText()</code>
51   * <li>maximum/minimum values - <code>hourOfDay().getMaximumValue()</code>
52   * <li>add/subtract - <code>hourOfDay().addToCopy()</code>
53   * <li>set - <code>hourOfDay().setCopy()</code>
54   * </ul>
55   * <p>
56   * TimeOfDay is thread-safe and immutable, provided that the Chronology is as well.
57   * All standard Chronology classes supplied are thread-safe and immutable.
58   *
59   * @author Stephen Colebourne
60   * @author Brian S O'Neill
61   * @since 1.0
62   * @deprecated Use LocalTime which has a much better internal implementation and
63   *  has been available since 1.3
64   */
65  @Deprecated
66  public final class TimeOfDay
67          extends BasePartial
68          implements ReadablePartial, Serializable {
69      // NOTE: No toDateTime(YearMonthDay) as semantics are confusing when
70      // different chronologies
71  
72      /** Serialization version */
73      private static final long serialVersionUID = 3633353405803318660L;
74      /** The singleton set of field types */
75      private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
76          DateTimeFieldType.hourOfDay(),
77          DateTimeFieldType.minuteOfHour(),
78          DateTimeFieldType.secondOfMinute(),
79          DateTimeFieldType.millisOfSecond(),
80      };
81  
82      /** Constant for midnight. */
83      public static final TimeOfDay MIDNIGHT = new TimeOfDay(0, 0, 0, 0);
84  
85      /** The index of the hourOfDay field in the field array */
86      public static final int HOUR_OF_DAY = 0;
87      /** The index of the minuteOfHour field in the field array */
88      public static final int MINUTE_OF_HOUR = 1;
89      /** The index of the secondOfMinute field in the field array */
90      public static final int SECOND_OF_MINUTE = 2;
91      /** The index of the millisOfSecond field in the field array */
92      public static final int MILLIS_OF_SECOND = 3;
93  
94      //-----------------------------------------------------------------------
95      /**
96       * Constructs a TimeOfDay from a <code>java.util.Calendar</code>
97       * using exactly the same field values avoiding any time zone effects.
98       * <p>
99       * 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 }