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 */
016package org.joda.time;
017
018import java.io.IOException;
019import java.io.ObjectInputStream;
020import java.io.ObjectOutputStream;
021import java.io.Serializable;
022import java.util.Calendar;
023import java.util.Date;
024import java.util.HashSet;
025import java.util.Locale;
026import java.util.Set;
027
028import org.joda.convert.FromString;
029import org.joda.convert.ToString;
030import org.joda.time.base.BaseLocal;
031import org.joda.time.chrono.ISOChronology;
032import org.joda.time.convert.ConverterManager;
033import org.joda.time.convert.PartialConverter;
034import org.joda.time.field.AbstractReadableInstantFieldProperty;
035import org.joda.time.format.DateTimeFormat;
036import org.joda.time.format.DateTimeFormatter;
037import 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 */
076public 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}