001    /*
002     *  Copyright 2001-2011 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.io.IOException;
019    import java.io.ObjectInputStream;
020    import java.io.ObjectOutputStream;
021    import java.io.Serializable;
022    import java.util.Calendar;
023    import java.util.Date;
024    import java.util.HashSet;
025    import java.util.Locale;
026    import java.util.Set;
027    
028    import org.joda.convert.FromString;
029    import org.joda.convert.ToString;
030    import org.joda.time.base.BaseLocal;
031    import org.joda.time.chrono.ISOChronology;
032    import org.joda.time.convert.ConverterManager;
033    import org.joda.time.convert.PartialConverter;
034    import org.joda.time.field.AbstractReadableInstantFieldProperty;
035    import org.joda.time.format.DateTimeFormat;
036    import org.joda.time.format.DateTimeFormatter;
037    import org.joda.time.format.ISODateTimeFormat;
038    
039    /**
040     * LocalTime is an immutable time class representing a time
041     * without a time zone.
042     * <p>
043     * LocalTime implements the {@link ReadablePartial} interface.
044     * To do this, the interface methods focus on the key fields -
045     * HourOfDay, MinuteOfHour, SecondOfMinute and MillisOfSecond.
046     * However, <b>all</b> time fields may in fact be queried.
047     * <p>
048     * Calculations on LocalTime are performed using a {@link Chronology}.
049     * This chronology will be set internally to be in the UTC time zone
050     * for all calculations.
051     *
052     * <p>Each individual field can be queried in two ways:
053     * <ul>
054     * <li><code>getHourOfDay()</code>
055     * <li><code>hourOfDay().get()</code>
056     * </ul>
057     * The second technique also provides access to other useful methods on the
058     * field:
059     * <ul>
060     * <li>numeric value
061     * <li>text value
062     * <li>short text value
063     * <li>maximum/minimum values
064     * <li>add/subtract
065     * <li>set
066     * <li>rounding
067     * </ul>
068     *
069     * <p>
070     * LocalTime is thread-safe and immutable, provided that the Chronology is as well.
071     * All standard Chronology classes supplied are thread-safe and immutable.
072     *
073     * @author Stephen Colebourne
074     * @since 1.3
075     */
076    public final class LocalTime
077            extends BaseLocal
078            implements ReadablePartial, Serializable {
079    
080        /** Serialization lock */
081        private static final long serialVersionUID = -12873158713873L;
082    
083        /** Constant for midnight. */
084        public static final LocalTime MIDNIGHT = new LocalTime(0, 0, 0, 0);
085    
086        /** The index of the hourOfDay field in the field array */
087        private static final int HOUR_OF_DAY = 0;
088        /** The index of the minuteOfHour field in the field array */
089        private static final int MINUTE_OF_HOUR = 1;
090        /** The index of the secondOfMinute field in the field array */
091        private static final int SECOND_OF_MINUTE = 2;
092        /** The index of the millisOfSecond field in the field array */
093        private static final int MILLIS_OF_SECOND = 3;
094        /** Set of known duration types. */
095        private static final Set<DurationFieldType> TIME_DURATION_TYPES = new HashSet<DurationFieldType>();
096        static {
097            TIME_DURATION_TYPES.add(DurationFieldType.millis());
098            TIME_DURATION_TYPES.add(DurationFieldType.seconds());
099            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    }