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.IOException;
19  import java.io.ObjectInputStream;
20  import java.io.ObjectOutputStream;
21  import java.io.Serializable;
22  import java.util.Calendar;
23  import java.util.Date;
24  import java.util.HashSet;
25  import java.util.Locale;
26  import java.util.Set;
27  
28  import org.joda.convert.FromString;
29  import org.joda.convert.ToString;
30  import org.joda.time.base.BaseLocal;
31  import org.joda.time.chrono.ISOChronology;
32  import org.joda.time.convert.ConverterManager;
33  import org.joda.time.convert.PartialConverter;
34  import org.joda.time.field.AbstractReadableInstantFieldProperty;
35  import org.joda.time.format.DateTimeFormat;
36  import org.joda.time.format.DateTimeFormatter;
37  import org.joda.time.format.ISODateTimeFormat;
38  
39  /**
40   * LocalTime is an immutable time class representing a time
41   * without a time zone.
42   * <p>
43   * LocalTime implements the {@link ReadablePartial} interface.
44   * To do this, the interface methods focus on the key fields -
45   * HourOfDay, MinuteOfHour, SecondOfMinute and MillisOfSecond.
46   * However, <b>all</b> time fields may in fact be queried.
47   * <p>
48   * Calculations on LocalTime are performed using a {@link Chronology}.
49   * This chronology will be set internally to be in the UTC time zone
50   * for all calculations.
51   *
52   * <p>Each individual field can be queried in two ways:
53   * <ul>
54   * <li><code>getHourOfDay()</code>
55   * <li><code>hourOfDay().get()</code>
56   * </ul>
57   * The second technique also provides access to other useful methods on the
58   * field:
59   * <ul>
60   * <li>numeric value
61   * <li>text value
62   * <li>short text value
63   * <li>maximum/minimum values
64   * <li>add/subtract
65   * <li>set
66   * <li>rounding
67   * </ul>
68   *
69   * <p>
70   * LocalTime is thread-safe and immutable, provided that the Chronology is as well.
71   * All standard Chronology classes supplied are thread-safe and immutable.
72   *
73   * @author Stephen Colebourne
74   * @since 1.3
75   */
76  public final class LocalTime
77          extends BaseLocal
78          implements ReadablePartial, Serializable {
79  
80      /** Serialization lock */
81      private static final long serialVersionUID = -12873158713873L;
82  
83      /** Constant for midnight. */
84      public static final LocalTime MIDNIGHT = new LocalTime(0, 0, 0, 0);
85  
86      /** The index of the hourOfDay field in the field array */
87      private static final int HOUR_OF_DAY = 0;
88      /** The index of the minuteOfHour field in the field array */
89      private static final int MINUTE_OF_HOUR = 1;
90      /** The index of the secondOfMinute field in the field array */
91      private static final int SECOND_OF_MINUTE = 2;
92      /** The index of the millisOfSecond field in the field array */
93      private static final int MILLIS_OF_SECOND = 3;
94      /** Set of known duration types. */
95      private static final Set<DurationFieldType> TIME_DURATION_TYPES = new HashSet<DurationFieldType>();
96      static {
97          TIME_DURATION_TYPES.add(DurationFieldType.millis());
98          TIME_DURATION_TYPES.add(DurationFieldType.seconds());
99          TIME_DURATION_TYPES.add(DurationFieldType.minutes());
100         TIME_DURATION_TYPES.add(DurationFieldType.hours());
101     }
102 
103     /** The local millis from 1970-01-01T00:00:00 */
104     private final long iLocalMillis;
105     /** The chronology to use, in UTC */
106     private final Chronology iChronology;
107 
108     //-----------------------------------------------------------------------
109     /**
110      * Obtains a {@code LocalTime} set to the current system millisecond time
111      * using <code>ISOChronology</code> in the default time zone.
112      * The resulting object does not use the zone.
113      * 
114      * @return the current time, not null
115      * @since 2.0
116      */
117     public static LocalTime now() {
118         return new LocalTime();
119     }
120 
121     /**
122      * Obtains a {@code LocalTime} set to the current system millisecond time
123      * using <code>ISOChronology</code> in the specified time zone.
124      * The resulting object does not use the zone.
125      *
126      * @param zone  the time zone, not null
127      * @return the current time, not null
128      * @since 2.0
129      */
130     public static LocalTime now(DateTimeZone zone) {
131         if (zone == null) {
132             throw new NullPointerException("Zone must not be null");
133         }
134         return new LocalTime(zone);
135     }
136 
137     /**
138      * Obtains a {@code LocalTime} set to the current system millisecond time
139      * using the specified chronology.
140      * The resulting object does not use the zone.
141      *
142      * @param chronology  the chronology, not null
143      * @return the current time, not null
144      * @since 2.0
145      */
146     public static LocalTime now(Chronology chronology) {
147         if (chronology == null) {
148             throw new NullPointerException("Chronology must not be null");
149         }
150         return new LocalTime(chronology);
151     }
152 
153     //-----------------------------------------------------------------------
154     /**
155      * Parses a {@code LocalTime} from the specified string.
156      * <p>
157      * This uses {@link ISODateTimeFormat#localTimeParser()}.
158      * 
159      * @param str  the string to parse, not null
160      * @since 2.0
161      */
162     @FromString
163     public static LocalTime parse(String str) {
164         return parse(str, ISODateTimeFormat.localTimeParser());
165     }
166 
167     /**
168      * Parses a {@code LocalTime} from the specified string using a formatter.
169      * 
170      * @param str  the string to parse, not null
171      * @param formatter  the formatter to use, not null
172      * @since 2.0
173      */
174     public static LocalTime parse(String str, DateTimeFormatter formatter) {
175         return formatter.parseLocalTime(str);
176     }
177 
178     //-----------------------------------------------------------------------
179     /**
180      * Constructs a LocalTime from the specified millis of day using the
181      * ISO chronology.
182      * <p>
183      * The millisOfDay value may exceed the number of millis in one day,
184      * but additional days will be ignored.
185      * This method uses the UTC time zone internally.
186      *
187      * @param millisOfDay  the number of milliseconds into a day to convert
188      */
189     public static LocalTime fromMillisOfDay(long millisOfDay) {
190         return fromMillisOfDay(millisOfDay, null);
191     }
192 
193     /**
194      * Constructs a LocalTime from the specified millis of day using the
195      * specified chronology.
196      * <p>
197      * The millisOfDay value may exceed the number of millis in one day,
198      * but additional days will be ignored.
199      * This method uses the UTC time zone internally.
200      *
201      * @param millisOfDay  the number of milliseconds into a day to convert
202      * @param chrono  the chronology, null means ISO chronology
203      */
204     public static LocalTime fromMillisOfDay(long millisOfDay, Chronology chrono) {
205         chrono = DateTimeUtils.getChronology(chrono).withUTC();
206         return new LocalTime(millisOfDay, chrono);
207     }
208 
209     //-----------------------------------------------------------------------
210     /**
211      * Constructs a LocalTime from a <code>java.util.Calendar</code>
212      * using exactly the same field values.
213      * <p>
214      * Each field is queried from the Calendar and assigned to the LocalTime.
215      * This is useful if you have been using the Calendar as a local time,
216      * ignoring the zone.
217      * <p>
218      * One advantage of this method is that this method is unaffected if the
219      * version of the time zone data differs between the JDK and Joda-Time.
220      * That is because the local field values are transferred, calculated using
221      * the JDK time zone data and without using the Joda-Time time zone data.
222      * <p>
223      * This factory method ignores the type of the calendar and always
224      * creates a LocalTime with ISO chronology. It is expected that you
225      * will only pass in instances of <code>GregorianCalendar</code> however
226      * this is not validated.
227      *
228      * @param calendar  the Calendar to extract fields from
229      * @return the created LocalTime
230      * @throws IllegalArgumentException if the calendar is null
231      * @throws IllegalArgumentException if the date is invalid for the ISO chronology
232      */
233     public static LocalTime fromCalendarFields(Calendar calendar) {
234         if (calendar == null) {
235             throw new IllegalArgumentException("The calendar must not be null");
236         }
237         return new LocalTime(
238             calendar.get(Calendar.HOUR_OF_DAY),
239             calendar.get(Calendar.MINUTE),
240             calendar.get(Calendar.SECOND),
241             calendar.get(Calendar.MILLISECOND)
242         );
243     }
244 
245     /**
246      * Constructs a LocalTime from a <code>java.util.Date</code>
247      * using exactly the same field values.
248      * <p>
249      * Each field is queried from the Date and assigned to the LocalTime.
250      * This is useful if you have been using the Date as a local time,
251      * ignoring the zone.
252      * <p>
253      * One advantage of this method is that this method is unaffected if the
254      * version of the time zone data differs between the JDK and Joda-Time.
255      * That is because the local field values are transferred, calculated using
256      * the JDK time zone data and without using the Joda-Time time zone data.
257      * <p>
258      * This factory method always creates a LocalTime with ISO chronology.
259      *
260      * @param date  the Date to extract fields from
261      * @return the created LocalTime
262      * @throws IllegalArgumentException if the calendar is null
263      * @throws IllegalArgumentException if the date is invalid for the ISO chronology
264      */
265     @SuppressWarnings("deprecation")
266     public static LocalTime fromDateFields(Date date) {
267         if (date == null) {
268             throw new IllegalArgumentException("The date must not be null");
269         }
270         return new LocalTime(
271             date.getHours(),
272             date.getMinutes(),
273             date.getSeconds(),
274             (((int) (date.getTime() % 1000)) + 1000) % 1000
275         );
276     }
277 
278     //-----------------------------------------------------------------------
279     /**
280      * Constructs an instance set to the current local time evaluated using
281      * ISO chronology in the default zone.
282      * <p>
283      * Once the constructor is completed, the zone is no longer used.
284      * 
285      * @see #now()
286      */
287     public LocalTime() {
288         this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance());
289     }
290 
291     /**
292      * Constructs an instance set to the current local time evaluated using
293      * ISO chronology in the specified zone.
294      * <p>
295      * If the specified time zone is null, the default zone is used.
296      * Once the constructor is completed, the zone is no longer used.
297      *
298      * @param zone  the time zone, null means default zone
299      * @see #now(DateTimeZone)
300      */
301     public LocalTime(DateTimeZone zone) {
302         this(DateTimeUtils.currentTimeMillis(), ISOChronology.getInstance(zone));
303     }
304 
305     /**
306      * Constructs an instance set to the current local time evaluated using
307      * specified chronology and zone.
308      * <p>
309      * If the chronology is null, ISO chronology in the default time zone is used.
310      * Once the constructor is completed, the zone is no longer used.
311      *
312      * @param chronology  the chronology, null means ISOChronology in default zone
313      * @see #now(Chronology)
314      */
315     public LocalTime(Chronology chronology) {
316         this(DateTimeUtils.currentTimeMillis(), chronology);
317     }
318 
319     //-----------------------------------------------------------------------
320     /**
321      * Constructs an instance set to the local time defined by the specified
322      * instant evaluated using ISO chronology in the default zone.
323      * <p>
324      * Once the constructor is completed, the zone is no longer used.
325      *
326      * @param instant  the milliseconds from 1970-01-01T00:00:00Z
327      */
328     public LocalTime(long instant) {
329         this(instant, ISOChronology.getInstance());
330     }
331 
332     /**
333      * Constructs an instance set to the local time defined by the specified
334      * instant evaluated using ISO chronology in the specified zone.
335      * <p>
336      * If the specified time zone is null, the default zone is used.
337      * Once the constructor is completed, the zone is no longer used.
338      *
339      * @param instant  the milliseconds from 1970-01-01T00:00:00Z
340      * @param zone  the time zone, null means default zone
341      */
342     public LocalTime(long instant, DateTimeZone zone) {
343         this(instant, ISOChronology.getInstance(zone));
344     }
345 
346     /**
347      * Constructs an instance set to the local time defined by the specified
348      * instant evaluated using the specified chronology.
349      * <p>
350      * If the chronology is null, ISO chronology in the default zone is used.
351      * Once the constructor is completed, the zone is no longer used.
352      *
353      * @param instant  the milliseconds from 1970-01-01T00:00:00Z
354      * @param chronology  the chronology, null means ISOChronology in default zone
355      */
356     public LocalTime(long instant, Chronology chronology) {
357         chronology = DateTimeUtils.getChronology(chronology);
358         
359         long localMillis = chronology.getZone().getMillisKeepLocal(DateTimeZone.UTC, instant);
360         chronology = chronology.withUTC();
361         iLocalMillis = chronology.millisOfDay().get(localMillis);
362         iChronology = chronology;
363     }
364 
365     //-----------------------------------------------------------------------
366     /**
367      * Constructs an instance from an Object that represents a datetime.
368      * <p>
369      * If the object contains no chronology, <code>ISOChronology</code> is used.
370      * If the object contains no time zone, the default zone is used.
371      * Once the constructor is completed, the zone is no longer used.
372      * <p>
373      * The recognised object types are defined in
374      * {@link org.joda.time.convert.ConverterManager ConverterManager} and
375      * include ReadablePartial, ReadableInstant, String, Calendar and Date.
376      * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}.
377      * The default String converter ignores the zone and only parses the field values.
378      *
379      * @param instant  the datetime object
380      * @throws IllegalArgumentException if the instant is invalid
381      */
382     public LocalTime(Object instant) {
383         this(instant, (Chronology) null);
384     }
385 
386     /**
387      * Constructs an instance from an Object that represents a datetime,
388      * forcing the time zone to that specified.
389      * <p>
390      * If the object contains no chronology, <code>ISOChronology</code> is used.
391      * If the specified time zone is null, the default zone is used.
392      * Once the constructor is completed, the zone is no longer used.
393      * <p>
394      * The recognised object types are defined in
395      * {@link org.joda.time.convert.ConverterManager ConverterManager} and
396      * include ReadablePartial, ReadableInstant, String, Calendar and Date.
397      * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}.
398      * The default String converter ignores the zone and only parses the field values.
399      *
400      * @param instant  the datetime object
401      * @param zone  the time zone
402      * @throws IllegalArgumentException if the instant is invalid
403      */
404     public LocalTime(Object instant, DateTimeZone zone) {
405         PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant);
406         Chronology chronology = converter.getChronology(instant, zone);
407         chronology = DateTimeUtils.getChronology(chronology);
408         iChronology = chronology.withUTC();
409         int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localTimeParser());
410         iLocalMillis = iChronology.getDateTimeMillis(0L, values[0], values[1], values[2], values[3]);
411     }
412 
413     /**
414      * Constructs an instance from an Object that represents a datetime,
415      * using the specified chronology.
416      * <p>
417      * If the chronology is null, ISO in the default time zone is used.
418      * Once the constructor is completed, the zone is no longer used.
419      * <p>
420      * The recognised object types are defined in
421      * {@link org.joda.time.convert.ConverterManager ConverterManager} and
422      * include ReadablePartial, ReadableInstant, String, Calendar and Date.
423      * The String formats are described by {@link ISODateTimeFormat#localTimeParser()}.
424      * The default String converter ignores the zone and only parses the field values.
425      *
426      * @param instant  the datetime object
427      * @param chronology  the chronology
428      * @throws IllegalArgumentException if the instant is invalid
429      */
430     public LocalTime(Object instant, Chronology chronology) {
431         PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant);
432         chronology = converter.getChronology(instant, chronology);
433         chronology = DateTimeUtils.getChronology(chronology);
434         iChronology = chronology.withUTC();
435         int[] values = converter.getPartialValues(this, instant, chronology, ISODateTimeFormat.localTimeParser());
436         iLocalMillis = iChronology.getDateTimeMillis(0L, values[0], values[1], values[2], values[3]);
437     }
438 
439     //-----------------------------------------------------------------------
440     /**
441      * Constructs an instance set to the specified time
442      * using <code>ISOChronology</code>.
443      *
444      * @param hourOfDay  the hour of the day, from 0 to 23
445      * @param minuteOfHour  the minute of the hour, from 0 to 59
446      */
447     public LocalTime(
448             int hourOfDay,
449             int minuteOfHour) {
450         this(hourOfDay, minuteOfHour, 0, 0, ISOChronology.getInstanceUTC());
451     }
452 
453     /**
454      * Constructs an instance set to the specified time
455      * using <code>ISOChronology</code>.
456      *
457      * @param hourOfDay  the hour of the day, from 0 to 23
458      * @param minuteOfHour  the minute of the hour, from 0 to 59
459      * @param secondOfMinute  the second of the minute, from 0 to 59
460      */
461     public LocalTime(
462             int hourOfDay,
463             int minuteOfHour,
464             int secondOfMinute) {
465         this(hourOfDay, minuteOfHour, secondOfMinute, 0, ISOChronology.getInstanceUTC());
466     }
467 
468     /**
469      * Constructs an instance set to the specified time
470      * using <code>ISOChronology</code>.
471      *
472      * @param hourOfDay  the hour of the day, from 0 to 23
473      * @param minuteOfHour  the minute of the hour, from 0 to 59
474      * @param secondOfMinute  the second of the minute, from 0 to 59
475      * @param millisOfSecond  the millisecond of the second, from 0 to 999
476      */
477     public LocalTime(
478             int hourOfDay,
479             int minuteOfHour,
480             int secondOfMinute,
481             int millisOfSecond) {
482         this(hourOfDay, minuteOfHour, secondOfMinute,
483                 millisOfSecond, ISOChronology.getInstanceUTC());
484     }
485 
486     /**
487      * Constructs an instance set to the specified time
488      * using the specified chronology, whose zone is ignored.
489      * <p>
490      * If the chronology is null, <code>ISOChronology</code> is used.
491      *
492      * @param hourOfDay  the hour of the day, valid values defined by the chronology
493      * @param minuteOfHour  the minute of the hour, valid values defined by the chronology
494      * @param secondOfMinute  the second of the minute, valid values defined by the chronology
495      * @param millisOfSecond  the millisecond of the second, valid values defined by the chronology
496      * @param chronology  the chronology, null means ISOChronology in default zone
497      */
498     public LocalTime(
499             int hourOfDay,
500             int minuteOfHour,
501             int secondOfMinute,
502             int millisOfSecond,
503             Chronology chronology) {
504         super();
505         chronology = DateTimeUtils.getChronology(chronology).withUTC();
506         long instant = chronology.getDateTimeMillis(
507             0L, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
508         iChronology = chronology;
509         iLocalMillis = instant;
510     }
511 
512     /**
513      * Handle broken serialization from other tools.
514      * @return the resolved object, not null
515      */
516     private Object readResolve() {
517         if (iChronology == null) {
518             return new LocalTime(iLocalMillis, ISOChronology.getInstanceUTC());
519         }
520         if (DateTimeZone.UTC.equals(iChronology.getZone()) == false) {
521             return new LocalTime(iLocalMillis, iChronology.withUTC());
522         }
523         return this;
524     }
525 
526     //-----------------------------------------------------------------------
527     /**
528      * Gets the number of fields in this partial, which is four.
529      * The supported fields are HourOfDay, MinuteOfHour, SecondOfMinute
530      * and MillisOfSecond.
531      *
532      * @return the field count, four
533      */
534     public int size() {
535         return 4;
536     }
537 
538     /**
539      * Gets the field for a specific index in the chronology specified.
540      * <p>
541      * This method must not use any instance variables.
542      *
543      * @param index  the index to retrieve
544      * @param chrono  the chronology to use
545      * @return the field
546      */
547     protected DateTimeField getField(int index, Chronology chrono) {
548         switch (index) {
549             case HOUR_OF_DAY:
550                 return chrono.hourOfDay();
551             case MINUTE_OF_HOUR:
552                 return chrono.minuteOfHour();
553             case SECOND_OF_MINUTE:
554                 return chrono.secondOfMinute();
555             case MILLIS_OF_SECOND:
556                 return chrono.millisOfSecond();
557             default:
558                 throw new IndexOutOfBoundsException("Invalid index: " + index);
559         }
560     }
561 
562     /**
563      * Gets the value of the field at the specifed index.
564      * <p>
565      * This method is required to support the <code>ReadablePartial</code>
566      * interface. The supported fields are HourOfDay, MinuteOfHour,
567      * SecondOfMinute and MillisOfSecond.
568      *
569      * @param index  the index, zero to three
570      * @return the value
571      * @throws IndexOutOfBoundsException if the index is invalid
572      */
573     public int getValue(int index) {
574         switch (index) {
575             case HOUR_OF_DAY:
576                 return getChronology().hourOfDay().get(getLocalMillis());
577             case MINUTE_OF_HOUR:
578                 return getChronology().minuteOfHour().get(getLocalMillis());
579             case SECOND_OF_MINUTE:
580                 return getChronology().secondOfMinute().get(getLocalMillis());
581             case MILLIS_OF_SECOND:
582                 return getChronology().millisOfSecond().get(getLocalMillis());
583             default:
584                 throw new IndexOutOfBoundsException("Invalid index: " + index);
585         }
586     }
587 
588     //-----------------------------------------------------------------------
589     /**
590      * Get the value of one of the fields of time.
591      * <p>
592      * This method gets the value of the specified field.
593      * For example:
594      * <pre>
595      * DateTime dt = new DateTime();
596      * int hourOfDay = dt.get(DateTimeFieldType.hourOfDay());
597      * </pre>
598      *
599      * @param fieldType  a field type, usually obtained from DateTimeFieldType, not null
600      * @return the value of that field
601      * @throws IllegalArgumentException if the field type is null
602      */
603     public int get(DateTimeFieldType fieldType) {
604         if (fieldType == null) {
605             throw new IllegalArgumentException("The DateTimeFieldType must not be null");
606         }
607         if (isSupported(fieldType) == false) {
608             throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
609         }
610         return fieldType.getField(getChronology()).get(getLocalMillis());
611     }
612 
613     /**
614      * Checks if the field type specified is supported by this
615      * local time and chronology.
616      * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
617      *
618      * @param type  a field type, usually obtained from DateTimeFieldType
619      * @return true if the field type is supported
620      */
621     public boolean isSupported(DateTimeFieldType type) {
622         if (type == null) {
623             return false;
624         }
625         if (isSupported(type.getDurationType()) == false) {
626             return false;
627         }
628         DurationFieldType range = type.getRangeDurationType();
629         return (isSupported(range) || range == DurationFieldType.days());
630     }
631 
632     /**
633      * Checks if the duration type specified is supported by this
634      * local time and chronology.
635      *
636      * @param type  a duration type, usually obtained from DurationFieldType
637      * @return true if the field type is supported
638      */
639     public boolean isSupported(DurationFieldType type) {
640         if (type == null) {
641             return false;
642         }
643         DurationField field = type.getField(getChronology());
644         if (TIME_DURATION_TYPES.contains(type) ||
645             field.getUnitMillis() < getChronology().days().getUnitMillis()) {
646             return field.isSupported();
647         }
648         return false;
649     }
650 
651     //-----------------------------------------------------------------------
652     /**
653      * Gets the local milliseconds from the Java epoch
654      * of 1970-01-01T00:00:00 (not fixed to any specific time zone).
655      * 
656      * @return the number of milliseconds since 1970-01-01T00:00:00
657      * @since 1.5 (previously private)
658      */
659     protected long getLocalMillis() {
660         return iLocalMillis;
661     }
662 
663     /**
664      * Gets the chronology of the time.
665      * 
666      * @return the Chronology that the time is using
667      */
668     public Chronology getChronology() {
669         return iChronology;
670     }
671 
672     //-----------------------------------------------------------------------
673     /**
674      * Compares this ReadablePartial with another returning true if the chronology,
675      * field types and values are equal.
676      *
677      * @param partial  an object to check against
678      * @return true if fields and values are equal
679      */
680     public boolean equals(Object partial) {
681         // override to perform faster
682         if (this == partial) {
683             return true;
684         }
685         if (partial instanceof LocalTime) {
686             LocalTime other = (LocalTime) partial;
687             if (iChronology.equals(other.iChronology)) {
688                 return iLocalMillis == other.iLocalMillis;
689             }
690         }
691         return super.equals(partial);
692     }
693 
694     /**
695      * Compares this partial with another returning an integer
696      * indicating the order.
697      * <p>
698      * The fields are compared in order, from largest to smallest.
699      * The first field that is non-equal is used to determine the result.
700      * <p>
701      * The specified object must be a partial instance whose field types
702      * match those of this partial.
703      *
704      * @param partial  an object to check against
705      * @return negative if this is less, zero if equal, positive if greater
706      * @throws ClassCastException if the partial is the wrong class
707      *  or if it has field types that don't match
708      * @throws NullPointerException if the partial is null
709      */
710     public int compareTo(ReadablePartial partial) {
711         // override to perform faster
712         if (this == partial) {
713             return 0;
714         }
715         if (partial instanceof LocalTime) {
716             LocalTime other = (LocalTime) partial;
717             if (iChronology.equals(other.iChronology)) {
718                 return (iLocalMillis < other.iLocalMillis ? -1 :
719                             (iLocalMillis == other.iLocalMillis ? 0 : 1));
720 
721             }
722         }
723         return super.compareTo(partial);
724     }
725 
726     //-----------------------------------------------------------------------
727     /**
728      * Returns a copy of this time with different local millis.
729      * <p>
730      * The returned object will be a new instance of the same type.
731      * Only the millis will change, the chronology is kept.
732      * The returned object will be either be a new instance or <code>this</code>.
733      *
734      * @param newMillis  the new millis, from 1970-01-01T00:00:00
735      * @return a copy of this time with different millis
736      */
737     LocalTime withLocalMillis(long newMillis) {
738         return (newMillis == getLocalMillis() ? this : new LocalTime(newMillis, getChronology()));
739     }
740 
741     //-----------------------------------------------------------------------
742     /**
743      * Returns a copy of this time with the partial set of fields replacing
744      * those from this instance.
745      * <p>
746      * For example, if the partial contains an hour and minute then those two
747      * fields will be changed in the returned instance.
748      * Unsupported fields are ignored.
749      * If the partial is null, then <code>this</code> is returned.
750      *
751      * @param partial  the partial set of fields to apply to this time, null ignored
752      * @return a copy of this time with a different set of fields
753      * @throws IllegalArgumentException if any value is invalid
754      */
755     public LocalTime withFields(ReadablePartial partial) {
756         if (partial == null) {
757             return this;
758         }
759         return withLocalMillis(getChronology().set(partial, getLocalMillis()));
760     }
761 
762     /**
763      * Returns a copy of this time with the specified field set
764      * to a new value.
765      * <p>
766      * For example, if the field type is <code>hourOfDay</code> then the hour of day
767      * field would be changed in the returned instance.
768      * If the field type is null, then <code>this</code> is returned.
769      * <p>
770      * These lines are equivalent:
771      * <pre>
772      * LocalTime updated = dt.withHourOfDay(6);
773      * LocalTime updated = dt.withField(DateTimeFieldType.hourOfDay(), 6);
774      * </pre>
775      *
776      * @param fieldType  the field type to set, not null
777      * @param value  the value to set
778      * @return a copy of this time with the field set
779      * @throws IllegalArgumentException if the value is null or invalid
780      */
781     public LocalTime withField(DateTimeFieldType fieldType, int value) {
782         if (fieldType == null) {
783             throw new IllegalArgumentException("Field must not be null");
784         }
785         if (isSupported(fieldType) == false) {
786             throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
787         }
788         long instant = fieldType.getField(getChronology()).set(getLocalMillis(), value);
789         return withLocalMillis(instant);
790     }
791 
792     /**
793      * Returns a copy of this time with the value of the specified
794      * field increased.
795      * <p>
796      * If the addition is zero or the field is null, then <code>this</code>
797      * is returned.
798      * <p>
799      * If the addition causes the maximum value of the field to be exceeded,
800      * then the value will wrap. Thus 23:59 plus two minutes yields 00:01.
801      * <p>
802      * These lines are equivalent:
803      * <pre>
804      * LocalTime added = dt.plusHours(6);
805      * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
806      * </pre>
807      *
808      * @param fieldType  the field type to add to, not null
809      * @param amount  the amount to add
810      * @return a copy of this time with the field updated
811      * @throws IllegalArgumentException if the value is null or invalid
812      * @throws ArithmeticException if the result exceeds the internal capacity
813      */
814     public LocalTime withFieldAdded(DurationFieldType fieldType, int amount) {
815         if (fieldType == null) {
816             throw new IllegalArgumentException("Field must not be null");
817         }
818         if (isSupported(fieldType) == false) {
819             throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
820         }
821         if (amount == 0) {
822             return this;
823         }
824         long instant = fieldType.getField(getChronology()).add(getLocalMillis(), amount);
825         return withLocalMillis(instant);
826     }
827 
828     //-----------------------------------------------------------------------
829     /**
830      * Returns a copy of this time with the specified period added.
831      * <p>
832      * If the addition is zero, then <code>this</code> is returned.
833      * <p>
834      * This method is typically used to add multiple copies of complex
835      * period instances. Adding one field is best achieved using methods
836      * like {@link #withFieldAdded(DurationFieldType, int)}
837      * or {@link #plusHours(int)}.
838      *
839      * @param period  the period to add to this one, null means zero
840      * @param scalar  the amount of times to add, such as -1 to subtract once
841      * @return a copy of this time with the period added
842      * @throws ArithmeticException if the result exceeds the internal capacity
843      */
844     public LocalTime withPeriodAdded(ReadablePeriod period, int scalar) {
845         if (period == null || scalar == 0) {
846             return this;
847         }
848         long instant = getChronology().add(period, getLocalMillis(), scalar);
849         return withLocalMillis(instant);
850     }
851 
852     //-----------------------------------------------------------------------
853     /**
854      * Returns a copy of this time with the specified period added.
855      * <p>
856      * If the amount is zero or null, then <code>this</code> is returned.
857      * <p>
858      * This method is typically used to add complex period instances.
859      * Adding one field is best achieved using methods
860      * like {@link #plusHours(int)}.
861      * 
862      * @param period  the period to add to this one, null means zero
863      * @return a copy of this time with the period added
864      * @throws ArithmeticException if the result exceeds the internal capacity
865      */
866     public LocalTime plus(ReadablePeriod period) {
867         return withPeriodAdded(period, 1);
868     }
869 
870     //-----------------------------------------------------------------------
871     /**
872      * Returns a copy of this time plus the specified number of hours.
873      * <p>
874      * This LocalTime instance is immutable and unaffected by this method call.
875      * <p>
876      * The following three lines are identical in effect:
877      * <pre>
878      * LocalTime added = dt.plusHours(6);
879      * LocalTime added = dt.plus(Period.hours(6));
880      * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
881      * </pre>
882      *
883      * @param hours  the amount of hours to add, may be negative
884      * @return the new LocalTime plus the increased hours
885      */
886     public LocalTime plusHours(int hours) {
887         if (hours == 0) {
888             return this;
889         }
890         long instant = getChronology().hours().add(getLocalMillis(), hours);
891         return withLocalMillis(instant);
892     }
893 
894     /**
895      * Returns a copy of this time plus the specified number of minutes.
896      * <p>
897      * This LocalTime instance is immutable and unaffected by this method call.
898      * <p>
899      * The following three lines are identical in effect:
900      * <pre>
901      * LocalTime added = dt.plusMinutes(6);
902      * LocalTime added = dt.plus(Period.minutes(6));
903      * LocalTime added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
904      * </pre>
905      *
906      * @param minutes  the amount of minutes to add, may be negative
907      * @return the new LocalTime plus the increased minutes
908      */
909     public LocalTime plusMinutes(int minutes) {
910         if (minutes == 0) {
911             return this;
912         }
913         long instant = getChronology().minutes().add(getLocalMillis(), minutes);
914         return withLocalMillis(instant);
915     }
916 
917     /**
918      * Returns a copy of this time plus the specified number of seconds.
919      * <p>
920      * This LocalTime instance is immutable and unaffected by this method call.
921      * <p>
922      * The following three lines are identical in effect:
923      * <pre>
924      * LocalTime added = dt.plusSeconds(6);
925      * LocalTime added = dt.plus(Period.seconds(6));
926      * LocalTime added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
927      * </pre>
928      *
929      * @param seconds  the amount of seconds to add, may be negative
930      * @return the new LocalTime plus the increased seconds
931      */
932     public LocalTime plusSeconds(int seconds) {
933         if (seconds == 0) {
934             return this;
935         }
936         long instant = getChronology().seconds().add(getLocalMillis(), seconds);
937         return withLocalMillis(instant);
938     }
939 
940     /**
941      * Returns a copy of this time plus the specified number of millis.
942      * <p>
943      * This LocalTime instance is immutable and unaffected by this method call.
944      * <p>
945      * The following three lines are identical in effect:
946      * <pre>
947      * LocalTime added = dt.plusMillis(6);
948      * LocalTime added = dt.plus(Period.millis(6));
949      * LocalTime added = dt.withFieldAdded(DurationFieldType.millis(), 6);
950      * </pre>
951      *
952      * @param millis  the amount of millis to add, may be negative
953      * @return the new LocalTime plus the increased millis
954      */
955     public LocalTime plusMillis(int millis) {
956         if (millis == 0) {
957             return this;
958         }
959         long instant = getChronology().millis().add(getLocalMillis(), millis);
960         return withLocalMillis(instant);
961     }
962 
963     //-----------------------------------------------------------------------
964     /**
965      * Returns a copy of this time with the specified period taken away.
966      * <p>
967      * If the amount is zero or null, then <code>this</code> is returned.
968      * <p>
969      * This method is typically used to subtract complex period instances.
970      * Subtracting one field is best achieved using methods
971      * like {@link #minusHours(int)}.
972      * 
973      * @param period  the period to reduce this instant by
974      * @return a copy of this time with the period taken away
975      * @throws ArithmeticException if the result exceeds the internal capacity
976      */
977     public LocalTime minus(ReadablePeriod period) {
978         return withPeriodAdded(period, -1);
979     }
980 
981     //-----------------------------------------------------------------------
982     /**
983      * Returns a copy of this time minus the specified number of hours.
984      * <p>
985      * This LocalTime instance is immutable and unaffected by this method call.
986      * <p>
987      * The following three lines are identical in effect:
988      * <pre>
989      * LocalTime subtracted = dt.minusHours(6);
990      * LocalTime subtracted = dt.minus(Period.hours(6));
991      * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
992      * </pre>
993      *
994      * @param hours  the amount of hours to subtract, may be negative
995      * @return the new LocalTime minus the increased hours
996      */
997     public LocalTime minusHours(int hours) {
998         if (hours == 0) {
999             return this;
1000         }
1001         long instant = getChronology().hours().subtract(getLocalMillis(), hours);
1002         return withLocalMillis(instant);
1003     }
1004 
1005     /**
1006      * Returns a copy of this time minus the specified number of minutes.
1007      * <p>
1008      * This LocalTime instance is immutable and unaffected by this method call.
1009      * <p>
1010      * The following three lines are identical in effect:
1011      * <pre>
1012      * LocalTime subtracted = dt.minusMinutes(6);
1013      * LocalTime subtracted = dt.minus(Period.minutes(6));
1014      * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
1015      * </pre>
1016      *
1017      * @param minutes  the amount of minutes to subtract, may be negative
1018      * @return the new LocalTime minus the increased minutes
1019      */
1020     public LocalTime minusMinutes(int minutes) {
1021         if (minutes == 0) {
1022             return this;
1023         }
1024         long instant = getChronology().minutes().subtract(getLocalMillis(), minutes);
1025         return withLocalMillis(instant);
1026     }
1027 
1028     /**
1029      * Returns a copy of this time minus the specified number of seconds.
1030      * <p>
1031      * This LocalTime instance is immutable and unaffected by this method call.
1032      * <p>
1033      * The following three lines are identical in effect:
1034      * <pre>
1035      * LocalTime subtracted = dt.minusSeconds(6);
1036      * LocalTime subtracted = dt.minus(Period.seconds(6));
1037      * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
1038      * </pre>
1039      *
1040      * @param seconds  the amount of seconds to subtract, may be negative
1041      * @return the new LocalTime minus the increased seconds
1042      */
1043     public LocalTime minusSeconds(int seconds) {
1044         if (seconds == 0) {
1045             return this;
1046         }
1047         long instant = getChronology().seconds().subtract(getLocalMillis(), seconds);
1048         return withLocalMillis(instant);
1049     }
1050 
1051     /**
1052      * Returns a copy of this time minus the specified number of millis.
1053      * <p>
1054      * This LocalTime instance is immutable and unaffected by this method call.
1055      * <p>
1056      * The following three lines are identical in effect:
1057      * <pre>
1058      * LocalTime subtracted = dt.minusMillis(6);
1059      * LocalTime subtracted = dt.minus(Period.millis(6));
1060      * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
1061      * </pre>
1062      *
1063      * @param millis  the amount of millis to subtract, may be negative
1064      * @return the new LocalTime minus the increased millis
1065      */
1066     public LocalTime minusMillis(int millis) {
1067         if (millis == 0) {
1068             return this;
1069         }
1070         long instant = getChronology().millis().subtract(getLocalMillis(), millis);
1071         return withLocalMillis(instant);
1072     }
1073 
1074     //-----------------------------------------------------------------------
1075     /**
1076      * Gets the property object for the specified type, which contains
1077      * many useful methods.
1078      *
1079      * @param fieldType  the field type to get the chronology for
1080      * @return the property object
1081      * @throws IllegalArgumentException if the field is null or unsupported
1082      */
1083     public Property property(DateTimeFieldType fieldType) {
1084         if (fieldType == null) {
1085             throw new IllegalArgumentException("The DateTimeFieldType must not be null");
1086         }
1087         if (isSupported(fieldType) == false) {
1088             throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
1089         }
1090         return new Property(this, fieldType.getField(getChronology()));
1091     }
1092 
1093     //-----------------------------------------------------------------------
1094     /**
1095      * Get the hour of day field value.
1096      *
1097      * @return the hour of day
1098      */
1099     public int getHourOfDay() {
1100         return getChronology().hourOfDay().get(getLocalMillis());
1101     }
1102 
1103     /**
1104      * Get the minute of hour field value.
1105      *
1106      * @return the minute of hour
1107      */
1108     public int getMinuteOfHour() {
1109         return getChronology().minuteOfHour().get(getLocalMillis());
1110     }
1111 
1112     /**
1113      * Get the second of minute field value.
1114      *
1115      * @return the second of minute
1116      */
1117     public int getSecondOfMinute() {
1118         return getChronology().secondOfMinute().get(getLocalMillis());
1119     }
1120 
1121     /**
1122      * Get the millis of second field value.
1123      *
1124      * @return the millis of second
1125      */
1126     public int getMillisOfSecond() {
1127         return getChronology().millisOfSecond().get(getLocalMillis());
1128     }
1129 
1130     /**
1131      * Get the millis of day field value.
1132      *
1133      * @return the millis of day
1134      */
1135     public int getMillisOfDay() {
1136         return getChronology().millisOfDay().get(getLocalMillis());
1137     }
1138 
1139     //-----------------------------------------------------------------------
1140     /**
1141      * Returns a copy of this time with the hour of day field updated.
1142      * <p>
1143      * LocalTime is immutable, so there are no set methods.
1144      * Instead, this method returns a new instance with the value of
1145      * hour of day changed.
1146      *
1147      * @param hour  the hour of day to set
1148      * @return a copy of this object with the field set
1149      * @throws IllegalArgumentException if the value is invalid
1150      */
1151     public LocalTime withHourOfDay(int hour) {
1152         return withLocalMillis(getChronology().hourOfDay().set(getLocalMillis(), hour));
1153     }
1154 
1155     /**
1156      * Returns a copy of this time with the minute of hour field updated.
1157      * <p>
1158      * LocalTime is immutable, so there are no set methods.
1159      * Instead, this method returns a new instance with the value of
1160      * minute of hour changed.
1161      *
1162      * @param minute  the minute of hour to set
1163      * @return a copy of this object with the field set
1164      * @throws IllegalArgumentException if the value is invalid
1165      */
1166     public LocalTime withMinuteOfHour(int minute) {
1167         return withLocalMillis(getChronology().minuteOfHour().set(getLocalMillis(), minute));
1168     }
1169 
1170     /**
1171      * Returns a copy of this time with the second of minute field updated.
1172      * <p>
1173      * LocalTime is immutable, so there are no set methods.
1174      * Instead, this method returns a new instance with the value of
1175      * second of minute changed.
1176      *
1177      * @param second  the second of minute to set
1178      * @return a copy of this object with the field set
1179      * @throws IllegalArgumentException if the value is invalid
1180      */
1181     public LocalTime withSecondOfMinute(int second) {
1182         return withLocalMillis(getChronology().secondOfMinute().set(getLocalMillis(), second));
1183     }
1184 
1185     /**
1186      * Returns a copy of this time with the millis of second field updated.
1187      * <p>
1188      * LocalTime is immutable, so there are no set methods.
1189      * Instead, this method returns a new instance with the value of
1190      * millis of second changed.
1191      *
1192      * @param millis  the millis of second to set
1193      * @return a copy of this object with the field set
1194      * @throws IllegalArgumentException if the value is invalid
1195      */
1196     public LocalTime withMillisOfSecond(int millis) {
1197         return withLocalMillis(getChronology().millisOfSecond().set(getLocalMillis(), millis));
1198     }
1199 
1200     /**
1201      * Returns a copy of this time with the millis of day field updated.
1202      * <p>
1203      * LocalTime is immutable, so there are no set methods.
1204      * Instead, this method returns a new instance with the value of
1205      * millis of day changed.
1206      *
1207      * @param millis  the millis of day to set
1208      * @return a copy of this object with the field set
1209      * @throws IllegalArgumentException if the value is invalid
1210      */
1211     public LocalTime withMillisOfDay(int millis) {
1212         return withLocalMillis(getChronology().millisOfDay().set(getLocalMillis(), millis));
1213     }
1214 
1215     //-----------------------------------------------------------------------
1216     /**
1217      * Get the hour of day field property which provides access to advanced functionality.
1218      * 
1219      * @return the hour of day property
1220      */
1221     public Property hourOfDay() {
1222         return new Property(this, getChronology().hourOfDay());
1223     }
1224 
1225     /**
1226      * Get the minute of hour field property which provides access to advanced functionality.
1227      * 
1228      * @return the minute of hour property
1229      */
1230     public Property minuteOfHour() {
1231         return new Property(this, getChronology().minuteOfHour());
1232     }
1233 
1234     /**
1235      * Get the second of minute field property which provides access to advanced functionality.
1236      * 
1237      * @return the second of minute property
1238      */
1239     public Property secondOfMinute() {
1240         return new Property(this, getChronology().secondOfMinute());
1241     }
1242 
1243     /**
1244      * Get the millis of second property which provides access to advanced functionality.
1245      * 
1246      * @return the millis of second property
1247      */
1248     public Property millisOfSecond() {
1249         return new Property(this, getChronology().millisOfSecond());
1250     }
1251 
1252     /**
1253      * Get the millis of day property which provides access to advanced functionality.
1254      * 
1255      * @return the millis of day property
1256      */
1257     public Property millisOfDay() {
1258         return new Property(this, getChronology().millisOfDay());
1259     }
1260 
1261     //-----------------------------------------------------------------------
1262     /**
1263      * Converts this LocalTime to a full datetime using the default time zone
1264      * setting the time fields from this instance and the date fields from
1265      * the current date.
1266      *
1267      * @return this time as a datetime using todays date
1268      */
1269     public DateTime toDateTimeToday() {
1270         return toDateTimeToday(null);
1271     }
1272 
1273     /**
1274      * Converts this LocalTime to a full datetime using the specified time zone
1275      * setting the time fields from this instance and the date fields from
1276      * the current time.
1277      * <p>
1278      * This method uses the chronology from this instance plus the time zone
1279      * specified.
1280      *
1281      * @param zone  the zone to use, null means default
1282      * @return this time as a datetime using todays date
1283      */
1284     public DateTime toDateTimeToday(DateTimeZone zone) {
1285         Chronology chrono = getChronology().withZone(zone);
1286         long instantMillis = DateTimeUtils.currentTimeMillis();
1287         long resolved = chrono.set(this, instantMillis);
1288         return new DateTime(resolved, chrono);
1289     }
1290 
1291     //-----------------------------------------------------------------------
1292     /**
1293      * Output the time in ISO8601 format (HH:mm:ss.SSS).
1294      * 
1295      * @return ISO8601 time formatted string.
1296      */
1297     @ToString
1298     public String toString() {
1299         return ISODateTimeFormat.time().print(this);
1300     }
1301 
1302     /**
1303      * Output the time using the specified format pattern.
1304      *
1305      * @param pattern  the pattern specification, null means use <code>toString</code>
1306      * @see org.joda.time.format.DateTimeFormat
1307      */
1308     public String toString(String pattern) {
1309         if (pattern == null) {
1310             return toString();
1311         }
1312         return DateTimeFormat.forPattern(pattern).print(this);
1313     }
1314 
1315     /**
1316      * Output the time using the specified format pattern.
1317      *
1318      * @param pattern  the pattern specification, null means use <code>toString</code>
1319      * @param locale  Locale to use, null means default
1320      * @see org.joda.time.format.DateTimeFormat
1321      */
1322     public String toString(String pattern, Locale locale) throws IllegalArgumentException {
1323         if (pattern == null) {
1324             return toString();
1325         }
1326         return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this);
1327     }
1328 
1329     //-----------------------------------------------------------------------
1330     /**
1331      * LocalTime.Property binds a LocalTime to a DateTimeField allowing
1332      * powerful datetime functionality to be easily accessed.
1333      * <p>
1334      * The simplest use of this class is as an alternative get method, here used to
1335      * get the minute '30'.
1336      * <pre>
1337      * LocalTime dt = new LocalTime(12, 30);
1338      * int year = dt.minuteOfHour().get();
1339      * </pre>
1340      * <p>
1341      * Methods are also provided that allow time modification. These return
1342      * new instances of LocalTime - they do not modify the original. The example
1343      * below yields two independent immutable date objects 2 hours apart.
1344      * <pre>
1345      * LocalTime dt1230 = new LocalTime(12, 30);
1346      * LocalTime dt1430 = dt1230.hourOfDay().setCopy(14);
1347      * </pre>
1348      * <p>
1349      * LocalTime.Property itself is thread-safe and immutable, as well as the
1350      * LocalTime being operated on.
1351      *
1352      * @author Stephen Colebourne
1353      * @author Brian S O'Neill
1354      * @since 1.3
1355      */
1356     public static final class Property extends AbstractReadableInstantFieldProperty {
1357         
1358         /** Serialization version */
1359         private static final long serialVersionUID = -325842547277223L;
1360         
1361         /** The instant this property is working against */
1362         private transient LocalTime iInstant;
1363         /** The field this property is working against */
1364         private transient DateTimeField iField;
1365         
1366         /**
1367          * Constructor.
1368          * 
1369          * @param instant  the instant to set
1370          * @param field  the field to use
1371          */
1372         Property(LocalTime instant, DateTimeField field) {
1373             super();
1374             iInstant = instant;
1375             iField = field;
1376         }
1377         
1378         /**
1379          * Writes the property in a safe serialization format.
1380          */
1381         private void writeObject(ObjectOutputStream oos) throws IOException {
1382             oos.writeObject(iInstant);
1383             oos.writeObject(iField.getType());
1384         }
1385         
1386         /**
1387          * Reads the property from a safe serialization format.
1388          */
1389         private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
1390             iInstant = (LocalTime) oos.readObject();
1391             DateTimeFieldType type = (DateTimeFieldType) oos.readObject();
1392             iField = type.getField(iInstant.getChronology());
1393         }
1394         
1395         //-----------------------------------------------------------------------
1396         /**
1397          * Gets the field being used.
1398          * 
1399          * @return the field
1400          */
1401         public DateTimeField getField() {
1402             return iField;
1403         }
1404         
1405         /**
1406          * Gets the milliseconds of the time that this property is linked to.
1407          * 
1408          * @return the milliseconds
1409          */
1410         protected long getMillis() {
1411             return iInstant.getLocalMillis();
1412         }
1413         
1414         /**
1415          * Gets the chronology of the datetime that this property is linked to.
1416          * 
1417          * @return the chronology
1418          * @since 1.4
1419          */
1420         protected Chronology getChronology() {
1421             return iInstant.getChronology();
1422         }
1423         
1424         /**
1425          * Gets the LocalTime object linked to this property.
1426          * 
1427          * @return the linked LocalTime
1428          */
1429         public LocalTime getLocalTime() {
1430             return iInstant;
1431         }
1432         
1433         //-----------------------------------------------------------------------
1434         /**
1435          * Adds to this field in a copy of this LocalTime.
1436          * <p>
1437          * The LocalTime attached to this property is unchanged by this call.
1438          *
1439          * @param value  the value to add to the field in the copy
1440          * @return a copy of the LocalTime with the field value changed
1441          */
1442         public LocalTime addCopy(int value) {
1443             return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value));
1444         }
1445         
1446         /**
1447          * Adds to this field in a copy of this LocalTime.
1448          * If the addition exceeds the maximum value (eg. 23:59) it will
1449          * wrap to the minimum value (eg. 00:00).
1450          * <p>
1451          * The LocalTime attached to this property is unchanged by this call.
1452          *
1453          * @param value  the value to add to the field in the copy
1454          * @return a copy of the LocalTime with the field value changed
1455          */
1456         public LocalTime addCopy(long value) {
1457             return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value));
1458         }
1459         
1460         /**
1461          * Adds to this field in a copy of this LocalTime.
1462          * If the addition exceeds the maximum value (eg. 23:59) then
1463          * an exception will be thrown.
1464          * Contrast this behaviour to {@link #addCopy(int)}.
1465          * <p>
1466          * The LocalTime attached to this property is unchanged by this call.
1467          *
1468          * @param value  the value to add to the field in the copy
1469          * @return a copy of the LocalTime with the field value changed
1470          * @throws IllegalArgumentException if the result is invalid
1471          */
1472         public LocalTime addNoWrapToCopy(int value) {
1473             long millis = iField.add(iInstant.getLocalMillis(), value);
1474             long rounded = iInstant.getChronology().millisOfDay().get(millis);
1475             if (rounded != millis) {
1476                 throw new IllegalArgumentException("The addition exceeded the boundaries of LocalTime");
1477             }
1478             return iInstant.withLocalMillis(millis);
1479         }
1480         
1481         /**
1482          * Adds to this field, possibly wrapped, in a copy of this LocalTime.
1483          * A field wrapped operation only changes this field.
1484          * Thus 10:59 plusWrapField one minute goes to 10:00.
1485          * <p>
1486          * The LocalTime attached to this property is unchanged by this call.
1487          *
1488          * @param value  the value to add to the field in the copy
1489          * @return a copy of the LocalTime with the field value changed
1490          * @throws IllegalArgumentException if the value isn't valid
1491          */
1492         public LocalTime addWrapFieldToCopy(int value) {
1493             return iInstant.withLocalMillis(iField.addWrapField(iInstant.getLocalMillis(), value));
1494         }
1495         
1496         //-----------------------------------------------------------------------
1497         /**
1498          * Sets this field in a copy of the LocalTime.
1499          * <p>
1500          * The LocalTime attached to this property is unchanged by this call.
1501          *
1502          * @param value  the value to set the field in the copy to
1503          * @return a copy of the LocalTime with the field value changed
1504          * @throws IllegalArgumentException if the value isn't valid
1505          */
1506         public LocalTime setCopy(int value) {
1507             return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), value));
1508         }
1509         
1510         /**
1511          * Sets this field in a copy of the LocalTime to a parsed text value.
1512          * <p>
1513          * The LocalTime attached to this property is unchanged by this call.
1514          *
1515          * @param text  the text value to set
1516          * @param locale  optional locale to use for selecting a text symbol
1517          * @return a copy of the LocalTime with the field value changed
1518          * @throws IllegalArgumentException if the text value isn't valid
1519          */
1520         public LocalTime setCopy(String text, Locale locale) {
1521             return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), text, locale));
1522         }
1523         
1524         /**
1525          * Sets this field in a copy of the LocalTime to a parsed text value.
1526          * <p>
1527          * The LocalTime attached to this property is unchanged by this call.
1528          *
1529          * @param text  the text value to set
1530          * @return a copy of the LocalTime with the field value changed
1531          * @throws IllegalArgumentException if the text value isn't valid
1532          */
1533         public LocalTime setCopy(String text) {
1534             return setCopy(text, null);
1535         }
1536         
1537         //-----------------------------------------------------------------------
1538         /**
1539          * Returns a new LocalTime with this field set to the maximum value
1540          * for this field.
1541          * <p>
1542          * The LocalTime attached to this property is unchanged by this call.
1543          *
1544          * @return a copy of the LocalTime with this field set to its maximum
1545          */
1546         public LocalTime withMaximumValue() {
1547             return setCopy(getMaximumValue());
1548         }
1549         
1550         /**
1551          * Returns a new LocalTime with this field set to the minimum value
1552          * for this field.
1553          * <p>
1554          * The LocalTime attached to this property is unchanged by this call.
1555          *
1556          * @return a copy of the LocalTime with this field set to its minimum
1557          */
1558         public LocalTime withMinimumValue() {
1559             return setCopy(getMinimumValue());
1560         }
1561         
1562         //-----------------------------------------------------------------------
1563         /**
1564          * Rounds to the lowest whole unit of this field on a copy of this
1565          * LocalTime.
1566          * <p>
1567          * For example, rounding floor on the hourOfDay field of a LocalTime
1568          * where the time is 10:30 would result in new LocalTime with the
1569          * time of 10:00.
1570          *
1571          * @return a copy of the LocalTime with the field value changed
1572          */
1573         public LocalTime roundFloorCopy() {
1574             return iInstant.withLocalMillis(iField.roundFloor(iInstant.getLocalMillis()));
1575         }
1576         
1577         /**
1578          * Rounds to the highest whole unit of this field on a copy of this
1579          * LocalTime.
1580          * <p>
1581          * For example, rounding floor on the hourOfDay field of a LocalTime
1582          * where the time is 10:30 would result in new LocalTime with the
1583          * time of 11:00.
1584          *
1585          * @return a copy of the LocalTime with the field value changed
1586          */
1587         public LocalTime roundCeilingCopy() {
1588             return iInstant.withLocalMillis(iField.roundCeiling(iInstant.getLocalMillis()));
1589         }
1590         
1591         /**
1592          * Rounds to the nearest whole unit of this field on a copy of this
1593          * LocalTime, favoring the floor if halfway.
1594          *
1595          * @return a copy of the LocalTime with the field value changed
1596          */
1597         public LocalTime roundHalfFloorCopy() {
1598             return iInstant.withLocalMillis(iField.roundHalfFloor(iInstant.getLocalMillis()));
1599         }
1600         
1601         /**
1602          * Rounds to the nearest whole unit of this field on a copy of this
1603          * LocalTime, favoring the ceiling if halfway.
1604          *
1605          * @return a copy of the LocalTime with the field value changed
1606          */
1607         public LocalTime roundHalfCeilingCopy() {
1608             return iInstant.withLocalMillis(iField.roundHalfCeiling(iInstant.getLocalMillis()));
1609         }
1610         
1611         /**
1612          * Rounds to the nearest whole unit of this field on a copy of this
1613          * LocalTime.  If halfway, the ceiling is favored over the floor
1614          * only if it makes this field's value even.
1615          *
1616          * @return a copy of the LocalTime with the field value changed
1617          */
1618         public LocalTime roundHalfEvenCopy() {
1619             return iInstant.withLocalMillis(iField.roundHalfEven(iInstant.getLocalMillis()));
1620         }
1621     }
1622 
1623 }