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
445         * @param minuteOfHour  the minute of the hour
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
458         * @param minuteOfHour  the minute of the hour
459         * @param secondOfMinute  the second of the minute
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
473         * @param minuteOfHour  the minute of the hour
474         * @param secondOfMinute  the second of the minute
475         * @param millisOfSecond  the millisecond of the second
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
493         * @param minuteOfHour  the minute of the hour
494         * @param secondOfMinute  the second of the minute
495         * @param millisOfSecond  the millisecond of the second
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 (DateTimeZone.UTC.equals(iChronology.getZone()) == false) {
518                return new LocalTime(iLocalMillis, iChronology.withUTC());
519            }
520            return this;
521        }
522    
523        //-----------------------------------------------------------------------
524        /**
525         * Gets the number of fields in this partial, which is four.
526         * The supported fields are HourOfDay, MinuteOfHour, SecondOfMinute
527         * and MillisOfSecond.
528         *
529         * @return the field count, four
530         */
531        public int size() {
532            return 4;
533        }
534    
535        /**
536         * Gets the field for a specific index in the chronology specified.
537         * <p>
538         * This method must not use any instance variables.
539         *
540         * @param index  the index to retrieve
541         * @param chrono  the chronology to use
542         * @return the field
543         */
544        protected DateTimeField getField(int index, Chronology chrono) {
545            switch (index) {
546                case HOUR_OF_DAY:
547                    return chrono.hourOfDay();
548                case MINUTE_OF_HOUR:
549                    return chrono.minuteOfHour();
550                case SECOND_OF_MINUTE:
551                    return chrono.secondOfMinute();
552                case MILLIS_OF_SECOND:
553                    return chrono.millisOfSecond();
554                default:
555                    throw new IndexOutOfBoundsException("Invalid index: " + index);
556            }
557        }
558    
559        /**
560         * Gets the value of the field at the specifed index.
561         * <p>
562         * This method is required to support the <code>ReadablePartial</code>
563         * interface. The supported fields are HourOfDay, MinuteOfHour,
564         * SecondOfMinute and MillisOfSecond.
565         *
566         * @param index  the index, zero to three
567         * @return the value
568         * @throws IndexOutOfBoundsException if the index is invalid
569         */
570        public int getValue(int index) {
571            switch (index) {
572                case HOUR_OF_DAY:
573                    return getChronology().hourOfDay().get(getLocalMillis());
574                case MINUTE_OF_HOUR:
575                    return getChronology().minuteOfHour().get(getLocalMillis());
576                case SECOND_OF_MINUTE:
577                    return getChronology().secondOfMinute().get(getLocalMillis());
578                case MILLIS_OF_SECOND:
579                    return getChronology().millisOfSecond().get(getLocalMillis());
580                default:
581                    throw new IndexOutOfBoundsException("Invalid index: " + index);
582            }
583        }
584    
585        //-----------------------------------------------------------------------
586        /**
587         * Get the value of one of the fields of time.
588         * <p>
589         * This method gets the value of the specified field.
590         * For example:
591         * <pre>
592         * DateTime dt = new DateTime();
593         * int hourOfDay = dt.get(DateTimeFieldType.hourOfDay());
594         * </pre>
595         *
596         * @param fieldType  a field type, usually obtained from DateTimeFieldType, not null
597         * @return the value of that field
598         * @throws IllegalArgumentException if the field type is null
599         */
600        public int get(DateTimeFieldType fieldType) {
601            if (fieldType == null) {
602                throw new IllegalArgumentException("The DateTimeFieldType must not be null");
603            }
604            if (isSupported(fieldType) == false) {
605                throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
606            }
607            return fieldType.getField(getChronology()).get(getLocalMillis());
608        }
609    
610        /**
611         * Checks if the field type specified is supported by this
612         * local time and chronology.
613         * This can be used to avoid exceptions in {@link #get(DateTimeFieldType)}.
614         *
615         * @param type  a field type, usually obtained from DateTimeFieldType
616         * @return true if the field type is supported
617         */
618        public boolean isSupported(DateTimeFieldType type) {
619            if (type == null) {
620                return false;
621            }
622            if (isSupported(type.getDurationType()) == false) {
623                return false;
624            }
625            DurationFieldType range = type.getRangeDurationType();
626            return (isSupported(range) || range == DurationFieldType.days());
627        }
628    
629        /**
630         * Checks if the duration type specified is supported by this
631         * local time and chronology.
632         *
633         * @param type  a duration type, usually obtained from DurationFieldType
634         * @return true if the field type is supported
635         */
636        public boolean isSupported(DurationFieldType type) {
637            if (type == null) {
638                return false;
639            }
640            DurationField field = type.getField(getChronology());
641            if (TIME_DURATION_TYPES.contains(type) ||
642                field.getUnitMillis() < getChronology().days().getUnitMillis()) {
643                return field.isSupported();
644            }
645            return false;
646        }
647    
648        //-----------------------------------------------------------------------
649        /**
650         * Gets the local milliseconds from the Java epoch
651         * of 1970-01-01T00:00:00 (not fixed to any specific time zone).
652         * 
653         * @return the number of milliseconds since 1970-01-01T00:00:00
654         * @since 1.5 (previously private)
655         */
656        protected long getLocalMillis() {
657            return iLocalMillis;
658        }
659    
660        /**
661         * Gets the chronology of the time.
662         * 
663         * @return the Chronology that the time is using
664         */
665        public Chronology getChronology() {
666            return iChronology;
667        }
668    
669        //-----------------------------------------------------------------------
670        /**
671         * Compares this ReadablePartial with another returning true if the chronology,
672         * field types and values are equal.
673         *
674         * @param partial  an object to check against
675         * @return true if fields and values are equal
676         */
677        public boolean equals(Object partial) {
678            // override to perform faster
679            if (this == partial) {
680                return true;
681            }
682            if (partial instanceof LocalTime) {
683                LocalTime other = (LocalTime) partial;
684                if (iChronology.equals(other.iChronology)) {
685                    return iLocalMillis == other.iLocalMillis;
686                }
687            }
688            return super.equals(partial);
689        }
690    
691        /**
692         * Compares this partial with another returning an integer
693         * indicating the order.
694         * <p>
695         * The fields are compared in order, from largest to smallest.
696         * The first field that is non-equal is used to determine the result.
697         * <p>
698         * The specified object must be a partial instance whose field types
699         * match those of this partial.
700         *
701         * @param partial  an object to check against
702         * @return negative if this is less, zero if equal, positive if greater
703         * @throws ClassCastException if the partial is the wrong class
704         *  or if it has field types that don't match
705         * @throws NullPointerException if the partial is null
706         */
707        public int compareTo(ReadablePartial partial) {
708            // override to perform faster
709            if (this == partial) {
710                return 0;
711            }
712            if (partial instanceof LocalTime) {
713                LocalTime other = (LocalTime) partial;
714                if (iChronology.equals(other.iChronology)) {
715                    return (iLocalMillis < other.iLocalMillis ? -1 :
716                                (iLocalMillis == other.iLocalMillis ? 0 : 1));
717    
718                }
719            }
720            return super.compareTo(partial);
721        }
722    
723        //-----------------------------------------------------------------------
724        /**
725         * Returns a copy of this time with different local millis.
726         * <p>
727         * The returned object will be a new instance of the same type.
728         * Only the millis will change, the chronology is kept.
729         * The returned object will be either be a new instance or <code>this</code>.
730         *
731         * @param newMillis  the new millis, from 1970-01-01T00:00:00
732         * @return a copy of this time with different millis
733         */
734        LocalTime withLocalMillis(long newMillis) {
735            return (newMillis == getLocalMillis() ? this : new LocalTime(newMillis, getChronology()));
736        }
737    
738        //-----------------------------------------------------------------------
739        /**
740         * Returns a copy of this time with the partial set of fields replacing
741         * those from this instance.
742         * <p>
743         * For example, if the partial contains an hour and minute then those two
744         * fields will be changed in the returned instance.
745         * Unsupported fields are ignored.
746         * If the partial is null, then <code>this</code> is returned.
747         *
748         * @param partial  the partial set of fields to apply to this time, null ignored
749         * @return a copy of this time with a different set of fields
750         * @throws IllegalArgumentException if any value is invalid
751         */
752        public LocalTime withFields(ReadablePartial partial) {
753            if (partial == null) {
754                return this;
755            }
756            return withLocalMillis(getChronology().set(partial, getLocalMillis()));
757        }
758    
759        /**
760         * Returns a copy of this time with the specified field set
761         * to a new value.
762         * <p>
763         * For example, if the field type is <code>hourOfDay</code> then the hour of day
764         * field would be changed in the returned instance.
765         * If the field type is null, then <code>this</code> is returned.
766         * <p>
767         * These lines are equivalent:
768         * <pre>
769         * LocalTime updated = dt.withHourOfDay(6);
770         * LocalTime updated = dt.withField(DateTimeFieldType.hourOfDay(), 6);
771         * </pre>
772         *
773         * @param fieldType  the field type to set, not null
774         * @param value  the value to set
775         * @return a copy of this time with the field set
776         * @throws IllegalArgumentException if the value is null or invalid
777         */
778        public LocalTime withField(DateTimeFieldType fieldType, int value) {
779            if (fieldType == null) {
780                throw new IllegalArgumentException("Field must not be null");
781            }
782            if (isSupported(fieldType) == false) {
783                throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
784            }
785            long instant = fieldType.getField(getChronology()).set(getLocalMillis(), value);
786            return withLocalMillis(instant);
787        }
788    
789        /**
790         * Returns a copy of this time with the value of the specified
791         * field increased.
792         * <p>
793         * If the addition is zero or the field is null, then <code>this</code>
794         * is returned.
795         * <p>
796         * If the addition causes the maximum value of the field to be exceeded,
797         * then the value will wrap. Thus 23:59 plus two minutes yields 00:01.
798         * <p>
799         * These lines are equivalent:
800         * <pre>
801         * LocalTime added = dt.plusHours(6);
802         * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
803         * </pre>
804         *
805         * @param fieldType  the field type to add to, not null
806         * @param amount  the amount to add
807         * @return a copy of this time with the field updated
808         * @throws IllegalArgumentException if the value is null or invalid
809         * @throws ArithmeticException if the result exceeds the internal capacity
810         */
811        public LocalTime withFieldAdded(DurationFieldType fieldType, int amount) {
812            if (fieldType == null) {
813                throw new IllegalArgumentException("Field must not be null");
814            }
815            if (isSupported(fieldType) == false) {
816                throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
817            }
818            if (amount == 0) {
819                return this;
820            }
821            long instant = fieldType.getField(getChronology()).add(getLocalMillis(), amount);
822            return withLocalMillis(instant);
823        }
824    
825        //-----------------------------------------------------------------------
826        /**
827         * Returns a copy of this time with the specified period added.
828         * <p>
829         * If the addition is zero, then <code>this</code> is returned.
830         * <p>
831         * This method is typically used to add multiple copies of complex
832         * period instances. Adding one field is best achieved using methods
833         * like {@link #withFieldAdded(DurationFieldType, int)}
834         * or {@link #plusHours(int)}.
835         *
836         * @param period  the period to add to this one, null means zero
837         * @param scalar  the amount of times to add, such as -1 to subtract once
838         * @return a copy of this time with the period added
839         * @throws ArithmeticException if the result exceeds the internal capacity
840         */
841        public LocalTime withPeriodAdded(ReadablePeriod period, int scalar) {
842            if (period == null || scalar == 0) {
843                return this;
844            }
845            long instant = getChronology().add(period, getLocalMillis(), scalar);
846            return withLocalMillis(instant);
847        }
848    
849        //-----------------------------------------------------------------------
850        /**
851         * Returns a copy of this time with the specified period added.
852         * <p>
853         * If the amount is zero or null, then <code>this</code> is returned.
854         * <p>
855         * This method is typically used to add complex period instances.
856         * Adding one field is best achieved using methods
857         * like {@link #plusHours(int)}.
858         * 
859         * @param period  the period to add to this one, null means zero
860         * @return a copy of this time with the period added
861         * @throws ArithmeticException if the result exceeds the internal capacity
862         */
863        public LocalTime plus(ReadablePeriod period) {
864            return withPeriodAdded(period, 1);
865        }
866    
867        //-----------------------------------------------------------------------
868        /**
869         * Returns a copy of this time plus the specified number of hours.
870         * <p>
871         * This LocalTime instance is immutable and unaffected by this method call.
872         * <p>
873         * The following three lines are identical in effect:
874         * <pre>
875         * LocalTime added = dt.plusHours(6);
876         * LocalTime added = dt.plus(Period.hours(6));
877         * LocalTime added = dt.withFieldAdded(DurationFieldType.hours(), 6);
878         * </pre>
879         *
880         * @param hours  the amount of hours to add, may be negative
881         * @return the new LocalTime plus the increased hours
882         */
883        public LocalTime plusHours(int hours) {
884            if (hours == 0) {
885                return this;
886            }
887            long instant = getChronology().hours().add(getLocalMillis(), hours);
888            return withLocalMillis(instant);
889        }
890    
891        /**
892         * Returns a copy of this time plus the specified number of minutes.
893         * <p>
894         * This LocalTime instance is immutable and unaffected by this method call.
895         * <p>
896         * The following three lines are identical in effect:
897         * <pre>
898         * LocalTime added = dt.plusMinutes(6);
899         * LocalTime added = dt.plus(Period.minutes(6));
900         * LocalTime added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
901         * </pre>
902         *
903         * @param minutes  the amount of minutes to add, may be negative
904         * @return the new LocalTime plus the increased minutes
905         */
906        public LocalTime plusMinutes(int minutes) {
907            if (minutes == 0) {
908                return this;
909            }
910            long instant = getChronology().minutes().add(getLocalMillis(), minutes);
911            return withLocalMillis(instant);
912        }
913    
914        /**
915         * Returns a copy of this time plus the specified number of seconds.
916         * <p>
917         * This LocalTime instance is immutable and unaffected by this method call.
918         * <p>
919         * The following three lines are identical in effect:
920         * <pre>
921         * LocalTime added = dt.plusSeconds(6);
922         * LocalTime added = dt.plus(Period.seconds(6));
923         * LocalTime added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
924         * </pre>
925         *
926         * @param seconds  the amount of seconds to add, may be negative
927         * @return the new LocalTime plus the increased seconds
928         */
929        public LocalTime plusSeconds(int seconds) {
930            if (seconds == 0) {
931                return this;
932            }
933            long instant = getChronology().seconds().add(getLocalMillis(), seconds);
934            return withLocalMillis(instant);
935        }
936    
937        /**
938         * Returns a copy of this time plus the specified number of millis.
939         * <p>
940         * This LocalTime instance is immutable and unaffected by this method call.
941         * <p>
942         * The following three lines are identical in effect:
943         * <pre>
944         * LocalTime added = dt.plusMillis(6);
945         * LocalTime added = dt.plus(Period.millis(6));
946         * LocalTime added = dt.withFieldAdded(DurationFieldType.millis(), 6);
947         * </pre>
948         *
949         * @param millis  the amount of millis to add, may be negative
950         * @return the new LocalTime plus the increased millis
951         */
952        public LocalTime plusMillis(int millis) {
953            if (millis == 0) {
954                return this;
955            }
956            long instant = getChronology().millis().add(getLocalMillis(), millis);
957            return withLocalMillis(instant);
958        }
959    
960        //-----------------------------------------------------------------------
961        /**
962         * Returns a copy of this time with the specified period taken away.
963         * <p>
964         * If the amount is zero or null, then <code>this</code> is returned.
965         * <p>
966         * This method is typically used to subtract complex period instances.
967         * Subtracting one field is best achieved using methods
968         * like {@link #minusHours(int)}.
969         * 
970         * @param period  the period to reduce this instant by
971         * @return a copy of this time with the period taken away
972         * @throws ArithmeticException if the result exceeds the internal capacity
973         */
974        public LocalTime minus(ReadablePeriod period) {
975            return withPeriodAdded(period, -1);
976        }
977    
978        //-----------------------------------------------------------------------
979        /**
980         * Returns a copy of this time minus the specified number of hours.
981         * <p>
982         * This LocalTime instance is immutable and unaffected by this method call.
983         * <p>
984         * The following three lines are identical in effect:
985         * <pre>
986         * LocalTime subtracted = dt.minusHours(6);
987         * LocalTime subtracted = dt.minus(Period.hours(6));
988         * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
989         * </pre>
990         *
991         * @param hours  the amount of hours to subtract, may be negative
992         * @return the new LocalTime minus the increased hours
993         */
994        public LocalTime minusHours(int hours) {
995            if (hours == 0) {
996                return this;
997            }
998            long instant = getChronology().hours().subtract(getLocalMillis(), hours);
999            return withLocalMillis(instant);
1000        }
1001    
1002        /**
1003         * Returns a copy of this time minus the specified number of minutes.
1004         * <p>
1005         * This LocalTime instance is immutable and unaffected by this method call.
1006         * <p>
1007         * The following three lines are identical in effect:
1008         * <pre>
1009         * LocalTime subtracted = dt.minusMinutes(6);
1010         * LocalTime subtracted = dt.minus(Period.minutes(6));
1011         * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
1012         * </pre>
1013         *
1014         * @param minutes  the amount of minutes to subtract, may be negative
1015         * @return the new LocalTime minus the increased minutes
1016         */
1017        public LocalTime minusMinutes(int minutes) {
1018            if (minutes == 0) {
1019                return this;
1020            }
1021            long instant = getChronology().minutes().subtract(getLocalMillis(), minutes);
1022            return withLocalMillis(instant);
1023        }
1024    
1025        /**
1026         * Returns a copy of this time minus the specified number of seconds.
1027         * <p>
1028         * This LocalTime instance is immutable and unaffected by this method call.
1029         * <p>
1030         * The following three lines are identical in effect:
1031         * <pre>
1032         * LocalTime subtracted = dt.minusSeconds(6);
1033         * LocalTime subtracted = dt.minus(Period.seconds(6));
1034         * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
1035         * </pre>
1036         *
1037         * @param seconds  the amount of seconds to subtract, may be negative
1038         * @return the new LocalTime minus the increased seconds
1039         */
1040        public LocalTime minusSeconds(int seconds) {
1041            if (seconds == 0) {
1042                return this;
1043            }
1044            long instant = getChronology().seconds().subtract(getLocalMillis(), seconds);
1045            return withLocalMillis(instant);
1046        }
1047    
1048        /**
1049         * Returns a copy of this time minus the specified number of millis.
1050         * <p>
1051         * This LocalTime instance is immutable and unaffected by this method call.
1052         * <p>
1053         * The following three lines are identical in effect:
1054         * <pre>
1055         * LocalTime subtracted = dt.minusMillis(6);
1056         * LocalTime subtracted = dt.minus(Period.millis(6));
1057         * LocalTime subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
1058         * </pre>
1059         *
1060         * @param millis  the amount of millis to subtract, may be negative
1061         * @return the new LocalTime minus the increased millis
1062         */
1063        public LocalTime minusMillis(int millis) {
1064            if (millis == 0) {
1065                return this;
1066            }
1067            long instant = getChronology().millis().subtract(getLocalMillis(), millis);
1068            return withLocalMillis(instant);
1069        }
1070    
1071        //-----------------------------------------------------------------------
1072        /**
1073         * Gets the property object for the specified type, which contains
1074         * many useful methods.
1075         *
1076         * @param fieldType  the field type to get the chronology for
1077         * @return the property object
1078         * @throws IllegalArgumentException if the field is null or unsupported
1079         */
1080        public Property property(DateTimeFieldType fieldType) {
1081            if (fieldType == null) {
1082                throw new IllegalArgumentException("The DateTimeFieldType must not be null");
1083            }
1084            if (isSupported(fieldType) == false) {
1085                throw new IllegalArgumentException("Field '" + fieldType + "' is not supported");
1086            }
1087            return new Property(this, fieldType.getField(getChronology()));
1088        }
1089    
1090        //-----------------------------------------------------------------------
1091        /**
1092         * Get the hour of day field value.
1093         *
1094         * @return the hour of day
1095         */
1096        public int getHourOfDay() {
1097            return getChronology().hourOfDay().get(getLocalMillis());
1098        }
1099    
1100        /**
1101         * Get the minute of hour field value.
1102         *
1103         * @return the minute of hour
1104         */
1105        public int getMinuteOfHour() {
1106            return getChronology().minuteOfHour().get(getLocalMillis());
1107        }
1108    
1109        /**
1110         * Get the second of minute field value.
1111         *
1112         * @return the second of minute
1113         */
1114        public int getSecondOfMinute() {
1115            return getChronology().secondOfMinute().get(getLocalMillis());
1116        }
1117    
1118        /**
1119         * Get the millis of second field value.
1120         *
1121         * @return the millis of second
1122         */
1123        public int getMillisOfSecond() {
1124            return getChronology().millisOfSecond().get(getLocalMillis());
1125        }
1126    
1127        /**
1128         * Get the millis of day field value.
1129         *
1130         * @return the millis of day
1131         */
1132        public int getMillisOfDay() {
1133            return getChronology().millisOfDay().get(getLocalMillis());
1134        }
1135    
1136        //-----------------------------------------------------------------------
1137        /**
1138         * Returns a copy of this time with the hour of day field updated.
1139         * <p>
1140         * LocalTime is immutable, so there are no set methods.
1141         * Instead, this method returns a new instance with the value of
1142         * hour of day changed.
1143         *
1144         * @param hour  the hour of day to set
1145         * @return a copy of this object with the field set
1146         * @throws IllegalArgumentException if the value is invalid
1147         */
1148        public LocalTime withHourOfDay(int hour) {
1149            return withLocalMillis(getChronology().hourOfDay().set(getLocalMillis(), hour));
1150        }
1151    
1152        /**
1153         * Returns a copy of this time with the minute of hour field updated.
1154         * <p>
1155         * LocalTime is immutable, so there are no set methods.
1156         * Instead, this method returns a new instance with the value of
1157         * minute of hour changed.
1158         *
1159         * @param minute  the minute of hour to set
1160         * @return a copy of this object with the field set
1161         * @throws IllegalArgumentException if the value is invalid
1162         */
1163        public LocalTime withMinuteOfHour(int minute) {
1164            return withLocalMillis(getChronology().minuteOfHour().set(getLocalMillis(), minute));
1165        }
1166    
1167        /**
1168         * Returns a copy of this time with the second of minute field updated.
1169         * <p>
1170         * LocalTime is immutable, so there are no set methods.
1171         * Instead, this method returns a new instance with the value of
1172         * second of minute changed.
1173         *
1174         * @param second  the second of minute to set
1175         * @return a copy of this object with the field set
1176         * @throws IllegalArgumentException if the value is invalid
1177         */
1178        public LocalTime withSecondOfMinute(int second) {
1179            return withLocalMillis(getChronology().secondOfMinute().set(getLocalMillis(), second));
1180        }
1181    
1182        /**
1183         * Returns a copy of this time with the millis of second field updated.
1184         * <p>
1185         * LocalTime is immutable, so there are no set methods.
1186         * Instead, this method returns a new instance with the value of
1187         * millis of second changed.
1188         *
1189         * @param millis  the millis of second to set
1190         * @return a copy of this object with the field set
1191         * @throws IllegalArgumentException if the value is invalid
1192         */
1193        public LocalTime withMillisOfSecond(int millis) {
1194            return withLocalMillis(getChronology().millisOfSecond().set(getLocalMillis(), millis));
1195        }
1196    
1197        /**
1198         * Returns a copy of this time with the millis of day field updated.
1199         * <p>
1200         * LocalTime is immutable, so there are no set methods.
1201         * Instead, this method returns a new instance with the value of
1202         * millis of day changed.
1203         *
1204         * @param millis  the millis of day to set
1205         * @return a copy of this object with the field set
1206         * @throws IllegalArgumentException if the value is invalid
1207         */
1208        public LocalTime withMillisOfDay(int millis) {
1209            return withLocalMillis(getChronology().millisOfDay().set(getLocalMillis(), millis));
1210        }
1211    
1212        //-----------------------------------------------------------------------
1213        /**
1214         * Get the hour of day field property which provides access to advanced functionality.
1215         * 
1216         * @return the hour of day property
1217         */
1218        public Property hourOfDay() {
1219            return new Property(this, getChronology().hourOfDay());
1220        }
1221    
1222        /**
1223         * Get the minute of hour field property which provides access to advanced functionality.
1224         * 
1225         * @return the minute of hour property
1226         */
1227        public Property minuteOfHour() {
1228            return new Property(this, getChronology().minuteOfHour());
1229        }
1230    
1231        /**
1232         * Get the second of minute field property which provides access to advanced functionality.
1233         * 
1234         * @return the second of minute property
1235         */
1236        public Property secondOfMinute() {
1237            return new Property(this, getChronology().secondOfMinute());
1238        }
1239    
1240        /**
1241         * Get the millis of second property which provides access to advanced functionality.
1242         * 
1243         * @return the millis of second property
1244         */
1245        public Property millisOfSecond() {
1246            return new Property(this, getChronology().millisOfSecond());
1247        }
1248    
1249        /**
1250         * Get the millis of day property which provides access to advanced functionality.
1251         * 
1252         * @return the millis of day property
1253         */
1254        public Property millisOfDay() {
1255            return new Property(this, getChronology().millisOfDay());
1256        }
1257    
1258        //-----------------------------------------------------------------------
1259        /**
1260         * Converts this LocalTime to a full datetime using the default time zone
1261         * setting the time fields from this instance and the date fields from
1262         * the current date.
1263         *
1264         * @return this time as a datetime using todays date
1265         */
1266        public DateTime toDateTimeToday() {
1267            return toDateTimeToday(null);
1268        }
1269    
1270        /**
1271         * Converts this LocalTime to a full datetime using the specified time zone
1272         * setting the time fields from this instance and the date fields from
1273         * the current time.
1274         * <p>
1275         * This method uses the chronology from this instance plus the time zone
1276         * specified.
1277         *
1278         * @param zone  the zone to use, null means default
1279         * @return this time as a datetime using todays date
1280         */
1281        public DateTime toDateTimeToday(DateTimeZone zone) {
1282            Chronology chrono = getChronology().withZone(zone);
1283            long instantMillis = DateTimeUtils.currentTimeMillis();
1284            long resolved = chrono.set(this, instantMillis);
1285            return new DateTime(resolved, chrono);
1286        }
1287    
1288        //-----------------------------------------------------------------------
1289        /**
1290         * Output the time in ISO8601 format (HH:mm:ss.SSSZZ).
1291         * 
1292         * @return ISO8601 time formatted string.
1293         */
1294        @ToString
1295        public String toString() {
1296            return ISODateTimeFormat.time().print(this);
1297        }
1298    
1299        /**
1300         * Output the time using the specified format pattern.
1301         *
1302         * @param pattern  the pattern specification, null means use <code>toString</code>
1303         * @see org.joda.time.format.DateTimeFormat
1304         */
1305        public String toString(String pattern) {
1306            if (pattern == null) {
1307                return toString();
1308            }
1309            return DateTimeFormat.forPattern(pattern).print(this);
1310        }
1311    
1312        /**
1313         * Output the time using the specified format pattern.
1314         *
1315         * @param pattern  the pattern specification, null means use <code>toString</code>
1316         * @param locale  Locale to use, null means default
1317         * @see org.joda.time.format.DateTimeFormat
1318         */
1319        public String toString(String pattern, Locale locale) throws IllegalArgumentException {
1320            if (pattern == null) {
1321                return toString();
1322            }
1323            return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this);
1324        }
1325    
1326        //-----------------------------------------------------------------------
1327        /**
1328         * LocalTime.Property binds a LocalTime to a DateTimeField allowing
1329         * powerful datetime functionality to be easily accessed.
1330         * <p>
1331         * The simplest use of this class is as an alternative get method, here used to
1332         * get the minute '30'.
1333         * <pre>
1334         * LocalTime dt = new LocalTime(12, 30);
1335         * int year = dt.minuteOfHour().get();
1336         * </pre>
1337         * <p>
1338         * Methods are also provided that allow time modification. These return
1339         * new instances of LocalTime - they do not modify the original. The example
1340         * below yields two independent immutable date objects 2 hours apart.
1341         * <pre>
1342         * LocalTime dt1230 = new LocalTime(12, 30);
1343         * LocalTime dt1430 = dt1230.hourOfDay().setCopy(14);
1344         * </pre>
1345         * <p>
1346         * LocalTime.Property itself is thread-safe and immutable, as well as the
1347         * LocalTime being operated on.
1348         *
1349         * @author Stephen Colebourne
1350         * @author Brian S O'Neill
1351         * @since 1.3
1352         */
1353        public static final class Property extends AbstractReadableInstantFieldProperty {
1354            
1355            /** Serialization version */
1356            private static final long serialVersionUID = -325842547277223L;
1357            
1358            /** The instant this property is working against */
1359            private transient LocalTime iInstant;
1360            /** The field this property is working against */
1361            private transient DateTimeField iField;
1362            
1363            /**
1364             * Constructor.
1365             * 
1366             * @param instant  the instant to set
1367             * @param field  the field to use
1368             */
1369            Property(LocalTime instant, DateTimeField field) {
1370                super();
1371                iInstant = instant;
1372                iField = field;
1373            }
1374            
1375            /**
1376             * Writes the property in a safe serialization format.
1377             */
1378            private void writeObject(ObjectOutputStream oos) throws IOException {
1379                oos.writeObject(iInstant);
1380                oos.writeObject(iField.getType());
1381            }
1382            
1383            /**
1384             * Reads the property from a safe serialization format.
1385             */
1386            private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException {
1387                iInstant = (LocalTime) oos.readObject();
1388                DateTimeFieldType type = (DateTimeFieldType) oos.readObject();
1389                iField = type.getField(iInstant.getChronology());
1390            }
1391            
1392            //-----------------------------------------------------------------------
1393            /**
1394             * Gets the field being used.
1395             * 
1396             * @return the field
1397             */
1398            public DateTimeField getField() {
1399                return iField;
1400            }
1401            
1402            /**
1403             * Gets the milliseconds of the time that this property is linked to.
1404             * 
1405             * @return the milliseconds
1406             */
1407            protected long getMillis() {
1408                return iInstant.getLocalMillis();
1409            }
1410            
1411            /**
1412             * Gets the chronology of the datetime that this property is linked to.
1413             * 
1414             * @return the chronology
1415             * @since 1.4
1416             */
1417            protected Chronology getChronology() {
1418                return iInstant.getChronology();
1419            }
1420            
1421            /**
1422             * Gets the LocalTime object linked to this property.
1423             * 
1424             * @return the linked LocalTime
1425             */
1426            public LocalTime getLocalTime() {
1427                return iInstant;
1428            }
1429            
1430            //-----------------------------------------------------------------------
1431            /**
1432             * Adds to this field in a copy of this LocalTime.
1433             * <p>
1434             * The LocalTime attached to this property is unchanged by this call.
1435             *
1436             * @param value  the value to add to the field in the copy
1437             * @return a copy of the LocalTime with the field value changed
1438             */
1439            public LocalTime addCopy(int value) {
1440                return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value));
1441            }
1442            
1443            /**
1444             * Adds to this field in a copy of this LocalTime.
1445             * If the addition exceeds the maximum value (eg. 23:59) it will
1446             * wrap to the minimum value (eg. 00:00).
1447             * <p>
1448             * The LocalTime attached to this property is unchanged by this call.
1449             *
1450             * @param value  the value to add to the field in the copy
1451             * @return a copy of the LocalTime with the field value changed
1452             */
1453            public LocalTime addCopy(long value) {
1454                return iInstant.withLocalMillis(iField.add(iInstant.getLocalMillis(), value));
1455            }
1456            
1457            /**
1458             * Adds to this field in a copy of this LocalTime.
1459             * If the addition exceeds the maximum value (eg. 23:59) then
1460             * an exception will be thrown.
1461             * Contrast this behaviour to {@link #addCopy(int)}.
1462             * <p>
1463             * The LocalTime attached to this property is unchanged by this call.
1464             *
1465             * @param value  the value to add to the field in the copy
1466             * @return a copy of the LocalTime with the field value changed
1467             * @throws IllegalArgumentException if the result is invalid
1468             */
1469            public LocalTime addNoWrapToCopy(int value) {
1470                long millis = iField.add(iInstant.getLocalMillis(), value);
1471                long rounded = iInstant.getChronology().millisOfDay().get(millis);
1472                if (rounded != millis) {
1473                    throw new IllegalArgumentException("The addition exceeded the boundaries of LocalTime");
1474                }
1475                return iInstant.withLocalMillis(millis);
1476            }
1477            
1478            /**
1479             * Adds to this field, possibly wrapped, in a copy of this LocalTime.
1480             * A field wrapped operation only changes this field.
1481             * Thus 10:59 plusWrapField one minute goes to 10:00.
1482             * <p>
1483             * The LocalTime attached to this property is unchanged by this call.
1484             *
1485             * @param value  the value to add to the field in the copy
1486             * @return a copy of the LocalTime with the field value changed
1487             * @throws IllegalArgumentException if the value isn't valid
1488             */
1489            public LocalTime addWrapFieldToCopy(int value) {
1490                return iInstant.withLocalMillis(iField.addWrapField(iInstant.getLocalMillis(), value));
1491            }
1492            
1493            //-----------------------------------------------------------------------
1494            /**
1495             * Sets this field in a copy of the LocalTime.
1496             * <p>
1497             * The LocalTime attached to this property is unchanged by this call.
1498             *
1499             * @param value  the value to set the field in the copy to
1500             * @return a copy of the LocalTime with the field value changed
1501             * @throws IllegalArgumentException if the value isn't valid
1502             */
1503            public LocalTime setCopy(int value) {
1504                return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), value));
1505            }
1506            
1507            /**
1508             * Sets this field in a copy of the LocalTime to a parsed text value.
1509             * <p>
1510             * The LocalTime attached to this property is unchanged by this call.
1511             *
1512             * @param text  the text value to set
1513             * @param locale  optional locale to use for selecting a text symbol
1514             * @return a copy of the LocalTime with the field value changed
1515             * @throws IllegalArgumentException if the text value isn't valid
1516             */
1517            public LocalTime setCopy(String text, Locale locale) {
1518                return iInstant.withLocalMillis(iField.set(iInstant.getLocalMillis(), text, locale));
1519            }
1520            
1521            /**
1522             * Sets this field in a copy of the LocalTime to a parsed text value.
1523             * <p>
1524             * The LocalTime attached to this property is unchanged by this call.
1525             *
1526             * @param text  the text value to set
1527             * @return a copy of the LocalTime with the field value changed
1528             * @throws IllegalArgumentException if the text value isn't valid
1529             */
1530            public LocalTime setCopy(String text) {
1531                return setCopy(text, null);
1532            }
1533            
1534            //-----------------------------------------------------------------------
1535            /**
1536             * Returns a new LocalTime with this field set to the maximum value
1537             * for this field.
1538             * <p>
1539             * The LocalTime attached to this property is unchanged by this call.
1540             *
1541             * @return a copy of the LocalTime with this field set to its maximum
1542             */
1543            public LocalTime withMaximumValue() {
1544                return setCopy(getMaximumValue());
1545            }
1546            
1547            /**
1548             * Returns a new LocalTime with this field set to the minimum value
1549             * for this field.
1550             * <p>
1551             * The LocalTime attached to this property is unchanged by this call.
1552             *
1553             * @return a copy of the LocalTime with this field set to its minimum
1554             */
1555            public LocalTime withMinimumValue() {
1556                return setCopy(getMinimumValue());
1557            }
1558            
1559            //-----------------------------------------------------------------------
1560            /**
1561             * Rounds to the lowest whole unit of this field on a copy of this
1562             * LocalTime.
1563             * <p>
1564             * For example, rounding floor on the hourOfDay field of a LocalTime
1565             * where the time is 10:30 would result in new LocalTime with the
1566             * time of 10:00.
1567             *
1568             * @return a copy of the LocalTime with the field value changed
1569             */
1570            public LocalTime roundFloorCopy() {
1571                return iInstant.withLocalMillis(iField.roundFloor(iInstant.getLocalMillis()));
1572            }
1573            
1574            /**
1575             * Rounds to the highest whole unit of this field on a copy of this
1576             * LocalTime.
1577             * <p>
1578             * For example, rounding floor on the hourOfDay field of a LocalTime
1579             * where the time is 10:30 would result in new LocalTime with the
1580             * time of 11:00.
1581             *
1582             * @return a copy of the LocalTime with the field value changed
1583             */
1584            public LocalTime roundCeilingCopy() {
1585                return iInstant.withLocalMillis(iField.roundCeiling(iInstant.getLocalMillis()));
1586            }
1587            
1588            /**
1589             * Rounds to the nearest whole unit of this field on a copy of this
1590             * LocalTime, favoring the floor if halfway.
1591             *
1592             * @return a copy of the LocalTime with the field value changed
1593             */
1594            public LocalTime roundHalfFloorCopy() {
1595                return iInstant.withLocalMillis(iField.roundHalfFloor(iInstant.getLocalMillis()));
1596            }
1597            
1598            /**
1599             * Rounds to the nearest whole unit of this field on a copy of this
1600             * LocalTime, favoring the ceiling if halfway.
1601             *
1602             * @return a copy of the LocalTime with the field value changed
1603             */
1604            public LocalTime roundHalfCeilingCopy() {
1605                return iInstant.withLocalMillis(iField.roundHalfCeiling(iInstant.getLocalMillis()));
1606            }
1607            
1608            /**
1609             * Rounds to the nearest whole unit of this field on a copy of this
1610             * LocalTime.  If halfway, the ceiling is favored over the floor
1611             * only if it makes this field's value even.
1612             *
1613             * @return a copy of the LocalTime with the field value changed
1614             */
1615            public LocalTime roundHalfEvenCopy() {
1616                return iInstant.withLocalMillis(iField.roundHalfEven(iInstant.getLocalMillis()));
1617            }
1618        }
1619    
1620    }