001/*
002 * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
003 *
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 *
009 *  * Redistributions of source code must retain the above copyright notice,
010 *    this list of conditions and the following disclaimer.
011 *
012 *  * Redistributions in binary form must reproduce the above copyright notice,
013 *    this list of conditions and the following disclaimer in the documentation
014 *    and/or other materials provided with the distribution.
015 *
016 *  * Neither the name of JSR-310 nor the names of its contributors
017 *    may be used to endorse or promote products derived from this software
018 *    without specific prior written permission.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 */
032package org.threeten.bp;
033
034import static org.threeten.bp.LocalTime.NANOS_PER_HOUR;
035import static org.threeten.bp.LocalTime.NANOS_PER_MINUTE;
036import static org.threeten.bp.LocalTime.NANOS_PER_SECOND;
037import static org.threeten.bp.LocalTime.SECONDS_PER_DAY;
038import static org.threeten.bp.temporal.ChronoField.NANO_OF_DAY;
039import static org.threeten.bp.temporal.ChronoField.OFFSET_SECONDS;
040import static org.threeten.bp.temporal.ChronoUnit.NANOS;
041
042import java.io.DataInput;
043import java.io.DataOutput;
044import java.io.IOException;
045import java.io.InvalidObjectException;
046import java.io.ObjectStreamException;
047import java.io.Serializable;
048import java.util.Objects;
049
050import org.threeten.bp.format.DateTimeFormatter;
051import org.threeten.bp.format.DateTimeFormatters;
052import org.threeten.bp.format.DateTimeParseException;
053import org.threeten.bp.jdk8.DefaultInterfaceTemporalAccessor;
054import org.threeten.bp.temporal.ChronoField;
055import org.threeten.bp.temporal.ChronoUnit;
056import org.threeten.bp.temporal.Temporal;
057import org.threeten.bp.temporal.TemporalAccessor;
058import org.threeten.bp.temporal.TemporalAdder;
059import org.threeten.bp.temporal.TemporalAdjuster;
060import org.threeten.bp.temporal.TemporalField;
061import org.threeten.bp.temporal.TemporalQueries;
062import org.threeten.bp.temporal.TemporalQuery;
063import org.threeten.bp.temporal.TemporalSubtractor;
064import org.threeten.bp.temporal.TemporalUnit;
065import org.threeten.bp.temporal.ValueRange;
066import org.threeten.bp.zone.ZoneRules;
067
068/**
069 * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
070 * such as {@code 10:15:30+01:00}.
071 * <p>
072 * {@code OffsetTime} is an immutable date-time object that represents a time, often
073 * viewed as hour-minute-second-offset.
074 * This class stores all time fields, to a precision of nanoseconds,
075 * as well as a zone offset.
076 * For example, the value "13:45.30.123456789+02:00" can be stored
077 * in an {@code OffsetTime}.
078 *
079 * <h3>Specification for implementors</h3>
080 * This class is immutable and thread-safe.
081 */
082public final class OffsetTime
083        extends DefaultInterfaceTemporalAccessor
084        implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable {
085
086    /**
087     * The minimum supported {@code OffsetTime}, '00:00:00+18:00'.
088     * This is the time of midnight at the start of the day in the maximum offset
089     * (larger offsets are earlier on the time-line).
090     * This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}.
091     * This could be used by an application as a "far past" date.
092     */
093    public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX);
094    /**
095     * The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'.
096     * This is the time just before midnight at the end of the day in the minimum offset
097     * (larger negative offsets are later on the time-line).
098     * This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}.
099     * This could be used by an application as a "far future" date.
100     */
101    public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN);
102
103    /**
104     * Serialization version.
105     */
106    private static final long serialVersionUID = 7264499704384272492L;
107
108    /**
109     * The local date-time.
110     */
111    private final LocalTime time;
112    /**
113     * The offset from UTC/Greenwich.
114     */
115    private final ZoneOffset offset;
116
117    //-----------------------------------------------------------------------
118    /**
119     * Obtains the current time from the system clock in the default time-zone.
120     * <p>
121     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
122     * time-zone to obtain the current time.
123     * The offset will be calculated from the time-zone in the clock.
124     * <p>
125     * Using this method will prevent the ability to use an alternate clock for testing
126     * because the clock is hard-coded.
127     *
128     * @return the current time using the system clock, not null
129     */
130    public static OffsetTime now() {
131        return now(Clock.systemDefaultZone());
132    }
133
134    /**
135     * Obtains the current time from the system clock in the specified time-zone.
136     * <p>
137     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
138     * Specifying the time-zone avoids dependence on the default time-zone.
139     * The offset will be calculated from the specified time-zone.
140     * <p>
141     * Using this method will prevent the ability to use an alternate clock for testing
142     * because the clock is hard-coded.
143     *
144     * @param zone  the zone ID to use, not null
145     * @return the current time using the system clock, not null
146     */
147    public static OffsetTime now(ZoneId zone) {
148        return now(Clock.system(zone));
149    }
150
151    /**
152     * Obtains the current time from the specified clock.
153     * <p>
154     * This will query the specified clock to obtain the current time.
155     * The offset will be calculated from the time-zone in the clock.
156     * <p>
157     * Using this method allows the use of an alternate clock for testing.
158     * The alternate clock may be introduced using {@link Clock dependency injection}.
159     *
160     * @param clock  the clock to use, not null
161     * @return the current time, not null
162     */
163    public static OffsetTime now(Clock clock) {
164        Objects.requireNonNull(clock, "clock");
165        final Instant now = clock.instant();  // called once
166        return ofInstant(now, clock.getZone().getRules().getOffset(now));
167    }
168
169    //-----------------------------------------------------------------------
170    /**
171     * Obtains an instance of {@code OffsetTime} from a local time and an offset.
172     *
173     * @param time  the local time, not null
174     * @param offset  the zone offset, not null
175     * @return the offset time, not null
176     */
177    public static OffsetTime of(LocalTime time, ZoneOffset offset) {
178        return new OffsetTime(time, offset);
179    }
180
181    //-----------------------------------------------------------------------
182    /**
183     * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
184     * <p>
185     * This creates an offset time with the same instant as that specified.
186     * Finding the offset from UTC/Greenwich is simple as there is only one valid
187     * offset for each instant.
188     * <p>
189     * The date component of the instant is dropped during the conversion.
190     * This means that the conversion can never fail due to the instant being
191     * out of the valid range of dates.
192     *
193     * @param instant  the instant to create the time from, not null
194     * @param zone  the time-zone, which may be an offset, not null
195     * @return the offset time, not null
196     */
197    public static OffsetTime ofInstant(Instant instant, ZoneId zone) {
198        Objects.requireNonNull(instant, "instant");
199        Objects.requireNonNull(zone, "zone");
200        ZoneRules rules = zone.getRules();
201        ZoneOffset offset = rules.getOffset(instant);
202        long secsOfDay = instant.getEpochSecond() % SECONDS_PER_DAY;
203        secsOfDay = (secsOfDay + offset.getTotalSeconds()) % SECONDS_PER_DAY;
204        if (secsOfDay < 0) {
205            secsOfDay += SECONDS_PER_DAY;
206        }
207        LocalTime time = LocalTime.ofSecondOfDay(secsOfDay, instant.getNano());
208        return new OffsetTime(time, offset);
209    }
210
211    //-----------------------------------------------------------------------
212    /**
213     * Obtains an instance of {@code OffsetTime} from a temporal object.
214     * <p>
215     * A {@code TemporalAccessor} represents some form of date and time information.
216     * This factory converts the arbitrary temporal object to an instance of {@code OffsetTime}.
217     * <p>
218     * The conversion extracts and combines {@code LocalTime} and {@code ZoneOffset}.
219     * <p>
220     * This method matches the signature of the functional interface {@link TemporalQuery}
221     * allowing it to be used in queries via method reference, {@code OffsetTime::from}.
222     *
223     * @param temporal  the temporal object to convert, not null
224     * @return the offset time, not null
225     * @throws DateTimeException if unable to convert to an {@code OffsetTime}
226     */
227    public static OffsetTime from(TemporalAccessor temporal) {
228        if (temporal instanceof OffsetTime) {
229            return (OffsetTime) temporal;
230        }
231        try {
232            LocalTime time = LocalTime.from(temporal);
233            ZoneOffset offset = ZoneOffset.from(temporal);
234            return new OffsetTime(time, offset);
235        } catch (DateTimeException ex) {
236            throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " + temporal.getClass(), ex);
237        }
238    }
239
240    //-----------------------------------------------------------------------
241    /**
242     * Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}.
243     * <p>
244     * The string must represent a valid time and is parsed using
245     * {@link org.threeten.bp.format.DateTimeFormatters#isoOffsetTime()}.
246     *
247     * @param text  the text to parse such as "10:15:30+01:00", not null
248     * @return the parsed local time, not null
249     * @throws DateTimeParseException if the text cannot be parsed
250     */
251    public static OffsetTime parse(CharSequence text) {
252        return parse(text, DateTimeFormatters.isoOffsetTime());
253    }
254
255    /**
256     * Obtains an instance of {@code OffsetTime} from a text string using a specific formatter.
257     * <p>
258     * The text is parsed using the formatter, returning a time.
259     *
260     * @param text  the text to parse, not null
261     * @param formatter  the formatter to use, not null
262     * @return the parsed offset time, not null
263     * @throws DateTimeParseException if the text cannot be parsed
264     */
265    public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) {
266        Objects.requireNonNull(formatter, "formatter");
267        return formatter.parse(text, OffsetTime.class);
268    }
269
270    //-----------------------------------------------------------------------
271    /**
272     * Constructor.
273     *
274     * @param time  the local time, not null
275     * @param offset  the zone offset, not null
276     */
277    private OffsetTime(LocalTime time, ZoneOffset offset) {
278        this.time = Objects.requireNonNull(time, "time");
279        this.offset = Objects.requireNonNull(offset, "offset");
280    }
281
282    /**
283     * Returns a new time based on this one, returning {@code this} where possible.
284     *
285     * @param time  the time to create with, not null
286     * @param offset  the zone offset to create with, not null
287     */
288    private OffsetTime with(LocalTime time, ZoneOffset offset) {
289        if (this.time == time && this.offset.equals(offset)) {
290            return this;
291        }
292        return new OffsetTime(time, offset);
293    }
294
295    //-----------------------------------------------------------------------
296    /**
297     * Checks if the specified field is supported.
298     * <p>
299     * This checks if this time can be queried for the specified field.
300     * If false, then calling the {@link #range(TemporalField) range} and
301     * {@link #get(TemporalField) get} methods will throw an exception.
302     * <p>
303     * If the field is a {@link ChronoField} then the query is implemented here.
304     * The supported fields are:
305     * <ul>
306     * <li>{@code NANO_OF_SECOND}
307     * <li>{@code NANO_OF_DAY}
308     * <li>{@code MICRO_OF_SECOND}
309     * <li>{@code MICRO_OF_DAY}
310     * <li>{@code MILLI_OF_SECOND}
311     * <li>{@code MILLI_OF_DAY}
312     * <li>{@code SECOND_OF_MINUTE}
313     * <li>{@code SECOND_OF_DAY}
314     * <li>{@code MINUTE_OF_HOUR}
315     * <li>{@code MINUTE_OF_DAY}
316     * <li>{@code HOUR_OF_AMPM}
317     * <li>{@code CLOCK_HOUR_OF_AMPM}
318     * <li>{@code HOUR_OF_DAY}
319     * <li>{@code CLOCK_HOUR_OF_DAY}
320     * <li>{@code AMPM_OF_DAY}
321     * <li>{@code OFFSET_SECONDS}
322     * </ul>
323     * All other {@code ChronoField} instances will return false.
324     * <p>
325     * If the field is not a {@code ChronoField}, then the result of this method
326     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
327     * passing {@code this} as the argument.
328     * Whether the field is supported is determined by the field.
329     *
330     * @param field  the field to check, null returns false
331     * @return true if the field is supported on this time, false if not
332     */
333    @Override
334    public boolean isSupported(TemporalField field) {
335        if (field instanceof ChronoField) {
336            return ((ChronoField) field).isTimeField() || field == OFFSET_SECONDS;
337        }
338        return field != null && field.doIsSupported(this);
339    }
340
341    /**
342     * Gets the range of valid values for the specified field.
343     * <p>
344     * The range object expresses the minimum and maximum valid values for a field.
345     * This time is used to enhance the accuracy of the returned range.
346     * If it is not possible to return the range, because the field is not supported
347     * or for some other reason, an exception is thrown.
348     * <p>
349     * If the field is a {@link ChronoField} then the query is implemented here.
350     * The {@link #isSupported(TemporalField) supported fields} will return
351     * appropriate range instances.
352     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
353     * <p>
354     * If the field is not a {@code ChronoField}, then the result of this method
355     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
356     * passing {@code this} as the argument.
357     * Whether the range can be obtained is determined by the field.
358     *
359     * @param field  the field to query the range for, not null
360     * @return the range of valid values for the field, not null
361     * @throws DateTimeException if the range for the field cannot be obtained
362     */
363    @Override
364    public ValueRange range(TemporalField field) {
365        if (field instanceof ChronoField) {
366            if (field == OFFSET_SECONDS) {
367                return field.range();
368            }
369            return time.range(field);
370        }
371        return field.doRange(this);
372    }
373
374    /**
375     * Gets the value of the specified field from this time as an {@code int}.
376     * <p>
377     * This queries this time for the value for the specified field.
378     * The returned value will always be within the valid range of values for the field.
379     * If it is not possible to return the value, because the field is not supported
380     * or for some other reason, an exception is thrown.
381     * <p>
382     * If the field is a {@link ChronoField} then the query is implemented here.
383     * The {@link #isSupported(TemporalField) supported fields} will return valid
384     * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
385     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
386     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
387     * <p>
388     * If the field is not a {@code ChronoField}, then the result of this method
389     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
390     * passing {@code this} as the argument. Whether the value can be obtained,
391     * and what the value represents, is determined by the field.
392     *
393     * @param field  the field to get, not null
394     * @return the value for the field
395     * @throws DateTimeException if a value for the field cannot be obtained
396     * @throws ArithmeticException if numeric overflow occurs
397     */
398    @Override  // override for Javadoc
399    public int get(TemporalField field) {
400        return super.get(field);
401    }
402
403    /**
404     * Gets the value of the specified field from this time as a {@code long}.
405     * <p>
406     * This queries this time for the value for the specified field.
407     * If it is not possible to return the value, because the field is not supported
408     * or for some other reason, an exception is thrown.
409     * <p>
410     * If the field is a {@link ChronoField} then the query is implemented here.
411     * The {@link #isSupported(TemporalField) supported fields} will return valid
412     * values based on this time.
413     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
414     * <p>
415     * If the field is not a {@code ChronoField}, then the result of this method
416     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
417     * passing {@code this} as the argument. Whether the value can be obtained,
418     * and what the value represents, is determined by the field.
419     *
420     * @param field  the field to get, not null
421     * @return the value for the field
422     * @throws DateTimeException if a value for the field cannot be obtained
423     * @throws ArithmeticException if numeric overflow occurs
424     */
425    @Override
426    public long getLong(TemporalField field) {
427        if (field instanceof ChronoField) {
428            if (field == OFFSET_SECONDS) {
429                return getOffset().getTotalSeconds();
430            }
431            return time.getLong(field);
432        }
433        return field.doGet(this);
434    }
435
436    //-----------------------------------------------------------------------
437    /**
438     * Gets the zone offset, such as '+01:00'.
439     * <p>
440     * This is the offset of the local time from UTC/Greenwich.
441     *
442     * @return the zone offset, not null
443     */
444    public ZoneOffset getOffset() {
445        return offset;
446    }
447
448    /**
449     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
450     * that the result has the same local time.
451     * <p>
452     * This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}.
453     * No calculation is needed or performed.
454     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
455     * {@code +03:00}, then this method will return {@code 10:30+03:00}.
456     * <p>
457     * To take into account the difference between the offsets, and adjust the time fields,
458     * use {@link #withOffsetSameInstant}.
459     * <p>
460     * This instance is immutable and unaffected by this method call.
461     *
462     * @param offset  the zone offset to change to, not null
463     * @return an {@code OffsetTime} based on this time with the requested offset, not null
464     */
465    public OffsetTime withOffsetSameLocal(ZoneOffset offset) {
466        return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset);
467    }
468
469    /**
470     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
471     * that the result is at the same instant on an implied day.
472     * <p>
473     * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime}
474     * adjusted by the difference between the two offsets.
475     * This will result in the old and new objects representing the same instant an an implied day.
476     * This is useful for finding the local time in a different offset.
477     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
478     * {@code +03:00}, then this method will return {@code 11:30+03:00}.
479     * <p>
480     * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
481     * <p>
482     * This instance is immutable and unaffected by this method call.
483     *
484     * @param offset  the zone offset to change to, not null
485     * @return an {@code OffsetTime} based on this time with the requested offset, not null
486     */
487    public OffsetTime withOffsetSameInstant(ZoneOffset offset) {
488        if (offset.equals(this.offset)) {
489            return this;
490        }
491        int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
492        LocalTime adjusted = time.plusSeconds(difference);
493        return new OffsetTime(adjusted, offset);
494    }
495
496    //-----------------------------------------------------------------------
497    /**
498     * Gets the {@code LocalTime} part of this date-time.
499     * <p>
500     * This returns a {@code LocalTime} with the same hour, minute, second and
501     * nanosecond as this date-time.
502     *
503     * @return the time part of this date-time, not null
504     */
505    public LocalTime getTime() {
506        return time;
507    }
508
509    //-----------------------------------------------------------------------
510    /**
511     * Gets the hour-of-day field.
512     *
513     * @return the hour-of-day, from 0 to 23
514     */
515    public int getHour() {
516        return time.getHour();
517    }
518
519    /**
520     * Gets the minute-of-hour field.
521     *
522     * @return the minute-of-hour, from 0 to 59
523     */
524    public int getMinute() {
525        return time.getMinute();
526    }
527
528    /**
529     * Gets the second-of-minute field.
530     *
531     * @return the second-of-minute, from 0 to 59
532     */
533    public int getSecond() {
534        return time.getSecond();
535    }
536
537    /**
538     * Gets the nano-of-second field.
539     *
540     * @return the nano-of-second, from 0 to 999,999,999
541     */
542    public int getNano() {
543        return time.getNano();
544    }
545
546    //-----------------------------------------------------------------------
547    /**
548     * Returns an adjusted copy of this time.
549     * <p>
550     * This returns a new {@code OffsetTime}, based on this one, with the time adjusted.
551     * The adjustment takes place using the specified adjuster strategy object.
552     * Read the documentation of the adjuster to understand what adjustment will be made.
553     * <p>
554     * A simple adjuster might simply set the one of the fields, such as the hour field.
555     * A more complex adjuster might set the time to the last hour of the day.
556     * <p>
557     * The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster},
558     * thus this method can be used to change the time or offset:
559     * <pre>
560     *  result = offsetTime.with(time);
561     *  result = offsetTime.with(offset);
562     * </pre>
563     * <p>
564     * The result of this method is obtained by invoking the
565     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
566     * specified adjuster passing {@code this} as the argument.
567     * <p>
568     * This instance is immutable and unaffected by this method call.
569     *
570     * @param adjuster the adjuster to use, not null
571     * @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null
572     * @throws DateTimeException if the adjustment cannot be made
573     * @throws ArithmeticException if numeric overflow occurs
574     */
575    @Override
576    public OffsetTime with(TemporalAdjuster adjuster) {
577        // optimizations
578        if (adjuster instanceof LocalTime) {
579            return with((LocalTime) adjuster, offset);
580        } else if (adjuster instanceof ZoneOffset) {
581            return with(time, (ZoneOffset) adjuster);
582        } else if (adjuster instanceof OffsetTime) {
583            return (OffsetTime) adjuster;
584        }
585        return (OffsetTime) adjuster.adjustInto(this);
586    }
587
588    /**
589     * Returns a copy of this time with the specified field set to a new value.
590     * <p>
591     * This returns a new {@code OffsetTime}, based on this one, with the value
592     * for the specified field changed.
593     * This can be used to change any supported field, such as the hour, minute or second.
594     * If it is not possible to set the value, because the field is not supported or for
595     * some other reason, an exception is thrown.
596     * <p>
597     * If the field is a {@link ChronoField} then the adjustment is implemented here.
598     * <p>
599     * The {@code OFFSET_SECONDS} field will return a time with the specified offset.
600     * The local time is unaltered. If the new offset value is outside the valid range
601     * then a {@code DateTimeException} will be thrown.
602     * <p>
603     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
604     * the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}.
605     * In this case, the offset is not part of the calculation and will be unchanged.
606     * <p>
607     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
608     * <p>
609     * If the field is not a {@code ChronoField}, then the result of this method
610     * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
611     * passing {@code this} as the argument. In this case, the field determines
612     * whether and how to adjust the instant.
613     * <p>
614     * This instance is immutable and unaffected by this method call.
615     *
616     * @param field  the field to set in the result, not null
617     * @param newValue  the new value of the field in the result
618     * @return an {@code OffsetTime} based on {@code this} with the specified field set, not null
619     * @throws DateTimeException if the field cannot be set
620     * @throws ArithmeticException if numeric overflow occurs
621     */
622    @Override
623    public OffsetTime with(TemporalField field, long newValue) {
624        if (field instanceof ChronoField) {
625            if (field == OFFSET_SECONDS) {
626                ChronoField f = (ChronoField) field;
627                return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
628            }
629            return with(time.with(field, newValue), offset);
630        }
631        return field.doWith(this, newValue);
632    }
633
634    //-----------------------------------------------------------------------
635    /**
636     * Returns a copy of this {@code OffsetTime} with the hour-of-day value altered.
637     * <p>
638     * The offset does not affect the calculation and will be the same in the result.
639     * <p>
640     * This instance is immutable and unaffected by this method call.
641     *
642     * @param hour  the hour-of-day to set in the result, from 0 to 23
643     * @return an {@code OffsetTime} based on this time with the requested hour, not null
644     * @throws DateTimeException if the hour value is invalid
645     */
646    public OffsetTime withHour(int hour) {
647        return with(time.withHour(hour), offset);
648    }
649
650    /**
651     * Returns a copy of this {@code OffsetTime} with the minute-of-hour value altered.
652     * <p>
653     * The offset does not affect the calculation and will be the same in the result.
654     * <p>
655     * This instance is immutable and unaffected by this method call.
656     *
657     * @param minute  the minute-of-hour to set in the result, from 0 to 59
658     * @return an {@code OffsetTime} based on this time with the requested minute, not null
659     * @throws DateTimeException if the minute value is invalid
660     */
661    public OffsetTime withMinute(int minute) {
662        return with(time.withMinute(minute), offset);
663    }
664
665    /**
666     * Returns a copy of this {@code OffsetTime} with the second-of-minute value altered.
667     * <p>
668     * The offset does not affect the calculation and will be the same in the result.
669     * <p>
670     * This instance is immutable and unaffected by this method call.
671     *
672     * @param second  the second-of-minute to set in the result, from 0 to 59
673     * @return an {@code OffsetTime} based on this time with the requested second, not null
674     * @throws DateTimeException if the second value is invalid
675     */
676    public OffsetTime withSecond(int second) {
677        return with(time.withSecond(second), offset);
678    }
679
680    /**
681     * Returns a copy of this {@code OffsetTime} with the nano-of-second value altered.
682     * <p>
683     * The offset does not affect the calculation and will be the same in the result.
684     * <p>
685     * This instance is immutable and unaffected by this method call.
686     *
687     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
688     * @return an {@code OffsetTime} based on this time with the requested nanosecond, not null
689     * @throws DateTimeException if the nanos value is invalid
690     */
691    public OffsetTime withNano(int nanoOfSecond) {
692        return with(time.withNano(nanoOfSecond), offset);
693    }
694
695    //-----------------------------------------------------------------------
696    /**
697     * Returns a copy of this {@code OffsetTime} with the time truncated.
698     * <p>
699     * Truncation returns a copy of the original time with fields
700     * smaller than the specified unit set to zero.
701     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
702     * will set the second-of-minute and nano-of-second field to zero.
703     * <p>
704     * Not all units are accepted. The {@link ChronoUnit#DAYS days} unit and time
705     * units with an exact duration can be used, other units throw an exception.
706     * <p>
707     * The offset does not affect the calculation and will be the same in the result.
708     * <p>
709     * This instance is immutable and unaffected by this method call.
710     *
711     * @param unit  the unit to truncate to, not null
712     * @return an {@code OffsetTime} based on this time with the time truncated, not null
713     * @throws DateTimeException if unable to truncate
714     */
715    public OffsetTime truncatedTo(TemporalUnit unit) {
716        return with(time.truncatedTo(unit), offset);
717    }
718
719    //-----------------------------------------------------------------------
720    /**
721     * Returns a copy of this date with the specified period added.
722     * <p>
723     * This method returns a new time based on this time with the specified period added.
724     * The adder is typically {@link Period} but may be any other type implementing
725     * the {@link TemporalAdder} interface.
726     * The calculation is delegated to the specified adjuster, which typically calls
727     * back to {@link #plus(long, TemporalUnit)}.
728     * The offset is not part of the calculation and will be unchanged in the result.
729     * <p>
730     * This instance is immutable and unaffected by this method call.
731     *
732     * @param adder  the adder to use, not null
733     * @return an {@code OffsetTime} based on this time with the addition made, not null
734     * @throws DateTimeException if the addition cannot be made
735     * @throws ArithmeticException if numeric overflow occurs
736     */
737    @Override
738    public OffsetTime plus(TemporalAdder adder) {
739        return (OffsetTime) adder.addTo(this);
740    }
741
742    /**
743     * Returns a copy of this time with the specified period added.
744     * <p>
745     * This method returns a new time based on this time with the specified period added.
746     * This can be used to add any period that is defined by a unit, for example to add hours, minutes or seconds.
747     * The unit is responsible for the details of the calculation, including the resolution
748     * of any edge cases in the calculation.
749     * The offset is not part of the calculation and will be unchanged in the result.
750     * <p>
751     * This instance is immutable and unaffected by this method call.
752     *
753     * @param amountToAdd  the amount of the unit to add to the result, may be negative
754     * @param unit  the unit of the period to add, not null
755     * @return an {@code OffsetTime} based on this time with the specified period added, not null
756     * @throws DateTimeException if the unit cannot be added to this type
757     */
758    @Override
759    public OffsetTime plus(long amountToAdd, TemporalUnit unit) {
760        if (unit instanceof ChronoUnit) {
761            return with(time.plus(amountToAdd, unit), offset);
762        }
763        return unit.doPlus(this, amountToAdd);
764    }
765
766    //-----------------------------------------------------------------------
767    /**
768     * Returns a copy of this {@code OffsetTime} with the specified period in hours added.
769     * <p>
770     * This adds the specified number of hours to this time, returning a new time.
771     * The calculation wraps around midnight.
772     * <p>
773     * This instance is immutable and unaffected by this method call.
774     *
775     * @param hours  the hours to add, may be negative
776     * @return an {@code OffsetTime} based on this time with the hours added, not null
777     */
778    public OffsetTime plusHours(long hours) {
779        return with(time.plusHours(hours), offset);
780    }
781
782    /**
783     * Returns a copy of this {@code OffsetTime} with the specified period in minutes added.
784     * <p>
785     * This adds the specified number of minutes to this time, returning a new time.
786     * The calculation wraps around midnight.
787     * <p>
788     * This instance is immutable and unaffected by this method call.
789     *
790     * @param minutes  the minutes to add, may be negative
791     * @return an {@code OffsetTime} based on this time with the minutes added, not null
792     */
793    public OffsetTime plusMinutes(long minutes) {
794        return with(time.plusMinutes(minutes), offset);
795    }
796
797    /**
798     * Returns a copy of this {@code OffsetTime} with the specified period in seconds added.
799     * <p>
800     * This adds the specified number of seconds to this time, returning a new time.
801     * The calculation wraps around midnight.
802     * <p>
803     * This instance is immutable and unaffected by this method call.
804     *
805     * @param seconds  the seconds to add, may be negative
806     * @return an {@code OffsetTime} based on this time with the seconds added, not null
807     */
808    public OffsetTime plusSeconds(long seconds) {
809        return with(time.plusSeconds(seconds), offset);
810    }
811
812    /**
813     * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds added.
814     * <p>
815     * This adds the specified number of nanoseconds to this time, returning a new time.
816     * The calculation wraps around midnight.
817     * <p>
818     * This instance is immutable and unaffected by this method call.
819     *
820     * @param nanos  the nanos to add, may be negative
821     * @return an {@code OffsetTime} based on this time with the nanoseconds added, not null
822     */
823    public OffsetTime plusNanos(long nanos) {
824        return with(time.plusNanos(nanos), offset);
825    }
826
827    //-----------------------------------------------------------------------
828    /**
829     * Returns a copy of this time with the specified period subtracted.
830     * <p>
831     * This method returns a new time based on this time with the specified period subtracted.
832     * The subtractor is typically {@link Period} but may be any other type implementing
833     * the {@link TemporalSubtractor} interface.
834     * The calculation is delegated to the specified adjuster, which typically calls
835     * back to {@link #minus(long, TemporalUnit)}.
836     * The offset is not part of the calculation and will be unchanged in the result.
837     * <p>
838     * This instance is immutable and unaffected by this method call.
839     *
840     * @param subtractor  the subtractor to use, not null
841     * @return an {@code OffsetTime} based on this time with the subtraction made, not null
842     * @throws DateTimeException if the subtraction cannot be made
843     * @throws ArithmeticException if numeric overflow occurs
844     */
845    @Override
846    public OffsetTime minus(TemporalSubtractor subtractor) {
847        return (OffsetTime) subtractor.subtractFrom(this);
848    }
849
850    /**
851     * Returns a copy of this time with the specified period subtracted.
852     * <p>
853     * This method returns a new time based on this time with the specified period subtracted.
854     * This can be used to subtract any period that is defined by a unit, for example to subtract hours, minutes or seconds.
855     * The unit is responsible for the details of the calculation, including the resolution
856     * of any edge cases in the calculation.
857     * The offset is not part of the calculation and will be unchanged in the result.
858     * <p>
859     * This instance is immutable and unaffected by this method call.
860     *
861     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
862     * @param unit  the unit of the period to subtract, not null
863     * @return an {@code OffsetTime} based on this time with the specified period subtracted, not null
864     * @throws DateTimeException if the unit cannot be added to this type
865     */
866    @Override
867    public OffsetTime minus(long amountToSubtract, TemporalUnit unit) {
868        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
869    }
870
871    //-----------------------------------------------------------------------
872    /**
873     * Returns a copy of this {@code OffsetTime} with the specified period in hours subtracted.
874     * <p>
875     * This subtracts the specified number of hours from this time, returning a new time.
876     * The calculation wraps around midnight.
877     * <p>
878     * This instance is immutable and unaffected by this method call.
879     *
880     * @param hours  the hours to subtract, may be negative
881     * @return an {@code OffsetTime} based on this time with the hours subtracted, not null
882     */
883    public OffsetTime minusHours(long hours) {
884        return with(time.minusHours(hours), offset);
885    }
886
887    /**
888     * Returns a copy of this {@code OffsetTime} with the specified period in minutes subtracted.
889     * <p>
890     * This subtracts the specified number of minutes from this time, returning a new time.
891     * The calculation wraps around midnight.
892     * <p>
893     * This instance is immutable and unaffected by this method call.
894     *
895     * @param minutes  the minutes to subtract, may be negative
896     * @return an {@code OffsetTime} based on this time with the minutes subtracted, not null
897     */
898    public OffsetTime minusMinutes(long minutes) {
899        return with(time.minusMinutes(minutes), offset);
900    }
901
902    /**
903     * Returns a copy of this {@code OffsetTime} with the specified period in seconds subtracted.
904     * <p>
905     * This subtracts the specified number of seconds from this time, returning a new time.
906     * The calculation wraps around midnight.
907     * <p>
908     * This instance is immutable and unaffected by this method call.
909     *
910     * @param seconds  the seconds to subtract, may be negative
911     * @return an {@code OffsetTime} based on this time with the seconds subtracted, not null
912     */
913    public OffsetTime minusSeconds(long seconds) {
914        return with(time.minusSeconds(seconds), offset);
915    }
916
917    /**
918     * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds subtracted.
919     * <p>
920     * This subtracts the specified number of nanoseconds from this time, returning a new time.
921     * The calculation wraps around midnight.
922     * <p>
923     * This instance is immutable and unaffected by this method call.
924     *
925     * @param nanos  the nanos to subtract, may be negative
926     * @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null
927     */
928    public OffsetTime minusNanos(long nanos) {
929        return with(time.minusNanos(nanos), offset);
930    }
931
932    //-----------------------------------------------------------------------
933    /**
934     * Queries this time using the specified query.
935     * <p>
936     * This queries this time using the specified query strategy object.
937     * The {@code TemporalQuery} object defines the logic to be used to
938     * obtain the result. Read the documentation of the query to understand
939     * what the result of this method will be.
940     * <p>
941     * The result of this method is obtained by invoking the
942     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
943     * specified query passing {@code this} as the argument.
944     *
945     * @param <R> the type of the result
946     * @param query  the query to invoke, not null
947     * @return the query result, null may be returned (defined by the query)
948     * @throws DateTimeException if unable to query (defined by the query)
949     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
950     */
951    @SuppressWarnings("unchecked")
952    @Override
953    public <R> R query(TemporalQuery<R> query) {
954        if (query == TemporalQueries.precision()) {
955            return (R) NANOS;
956        } else if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
957            return (R) getOffset();
958        }
959        return super.query(query);
960    }
961
962    /**
963     * Adjusts the specified temporal object to have the same offset and time
964     * as this object.
965     * <p>
966     * This returns a temporal object of the same observable type as the input
967     * with the offset and time changed to be the same as this.
968     * <p>
969     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
970     * twice, passing {@link ChronoField#OFFSET_SECONDS} and
971     * {@link ChronoField#NANO_OF_DAY} as the fields.
972     * <p>
973     * In most cases, it is clearer to reverse the calling pattern by using
974     * {@link Temporal#with(TemporalAdjuster)}:
975     * <pre>
976     *   // these two lines are equivalent, but the second approach is recommended
977     *   temporal = thisOffsetTime.adjustInto(temporal);
978     *   temporal = temporal.with(thisOffsetTime);
979     * </pre>
980     * <p>
981     * This instance is immutable and unaffected by this method call.
982     *
983     * @param temporal  the target object to be adjusted, not null
984     * @return the adjusted object, not null
985     * @throws DateTimeException if unable to make the adjustment
986     * @throws ArithmeticException if numeric overflow occurs
987     */
988    @Override
989    public Temporal adjustInto(Temporal temporal) {
990        return temporal
991                .with(OFFSET_SECONDS, getOffset().getTotalSeconds())
992                .with(NANO_OF_DAY, time.toNanoOfDay());
993    }
994
995    /**
996     * Calculates the period between this time and another time in
997     * terms of the specified unit.
998     * <p>
999     * This calculates the period between two times in terms of a single unit.
1000     * The start and end points are {@code this} and the specified time.
1001     * The result will be negative if the end is before the start.
1002     * For example, the period in hours between two times can be calculated
1003     * using {@code startTime.periodUntil(endTime, HOURS)}.
1004     * <p>
1005     * The {@code Temporal} passed to this method must be an {@code OffsetTime}.
1006     * If the offset differs between the two times, then the specified
1007     * end time is normalized to have the same offset as this time.
1008     * <p>
1009     * The calculation returns a whole number, representing the number of
1010     * complete units between the two times.
1011     * For example, the period in hours between 11:30Z and 13:29Z will only
1012     * be one hour as it is one minute short of two hours.
1013     * <p>
1014     * This method operates in association with {@link TemporalUnit#between}.
1015     * The result of this method is a {@code long} representing the amount of
1016     * the specified unit. By contrast, the result of {@code between} is an
1017     * object that can be used directly in addition/subtraction:
1018     * <pre>
1019     *   long period = start.periodUntil(end, HOURS);   // this method
1020     *   dateTime.plus(HOURS.between(start, end));      // use in plus/minus
1021     * </pre>
1022     * <p>
1023     * The calculation is implemented in this method for {@link ChronoUnit}.
1024     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
1025     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
1026     * Other {@code ChronoUnit} values will throw an exception.
1027     * <p>
1028     * If the unit is not a {@code ChronoUnit}, then the result of this method
1029     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
1030     * passing {@code this} as the first argument and the input temporal as
1031     * the second argument.
1032     * <p>
1033     * This instance is immutable and unaffected by this method call.
1034     *
1035     * @param endTime  the end time, which must be an {@code OffsetTime}, not null
1036     * @param unit  the unit to measure the period in, not null
1037     * @return the amount of the period between this time and the end time
1038     * @throws DateTimeException if the period cannot be calculated
1039     * @throws ArithmeticException if numeric overflow occurs
1040     */
1041    @Override
1042    public long periodUntil(Temporal endTime, TemporalUnit unit) {
1043        if (endTime instanceof OffsetTime == false) {
1044            Objects.requireNonNull(endTime, "endTime");
1045            throw new DateTimeException("Unable to calculate period between objects of two different types");
1046        }
1047        if (unit instanceof ChronoUnit) {
1048            OffsetTime end = (OffsetTime) endTime;
1049            long nanosUntil = end.toEpochNano() - toEpochNano();  // no overflow
1050            switch ((ChronoUnit) unit) {
1051                case NANOS: return nanosUntil;
1052                case MICROS: return nanosUntil / 1000;
1053                case MILLIS: return nanosUntil / 1000_000;
1054                case SECONDS: return nanosUntil / NANOS_PER_SECOND;
1055                case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
1056                case HOURS: return nanosUntil / NANOS_PER_HOUR;
1057                case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
1058            }
1059            throw new DateTimeException("Unsupported unit: " + unit.getName());
1060        }
1061        return unit.between(this, endTime).getAmount();
1062    }
1063
1064    //-----------------------------------------------------------------------
1065    /**
1066     * Returns an offset date-time formed from this time at the specified date.
1067     * <p>
1068     * This combines this time with the specified date to form an {@code OffsetDateTime}.
1069     * All possible combinations of date and time are valid.
1070     * <p>
1071     * This instance is immutable and unaffected by this method call.
1072     *
1073     * @param date  the date to combine with, not null
1074     * @return the offset date-time formed from this time and the specified date, not null
1075     */
1076    public OffsetDateTime atDate(LocalDate date) {
1077        return OffsetDateTime.of(date, time, offset);
1078    }
1079
1080    //-----------------------------------------------------------------------
1081    /**
1082     * Converts this time to epoch nanos based on 1970-01-01Z.
1083     *
1084     * @return the epoch nanos value
1085     */
1086    private long toEpochNano() {
1087        long nod = time.toNanoOfDay();
1088        long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND;
1089        return nod - offsetNanos;
1090    }
1091
1092    //-----------------------------------------------------------------------
1093    /**
1094     * Compares this {@code OffsetTime} to another time.
1095     * <p>
1096     * The comparison is based first on the UTC equivalent instant, then on the local time.
1097     * It is "consistent with equals", as defined by {@link Comparable}.
1098     * <p>
1099     * For example, the following is the comparator order:
1100     * <ol>
1101     * <li>{@code 10:30+01:00}</li>
1102     * <li>{@code 11:00+01:00}</li>
1103     * <li>{@code 12:00+02:00}</li>
1104     * <li>{@code 11:30+01:00}</li>
1105     * <li>{@code 12:00+01:00}</li>
1106     * <li>{@code 12:30+01:00}</li>
1107     * </ol>
1108     * Values #2 and #3 represent the same instant on the time-line.
1109     * When two values represent the same instant, the local time is compared
1110     * to distinguish them. This step is needed to make the ordering
1111     * consistent with {@code equals()}.
1112     * <p>
1113     * To compare the underlying local time of two {@code TemporalAccessor} instances,
1114     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
1115     *
1116     * @param other  the other time to compare to, not null
1117     * @return the comparator value, negative if less, positive if greater
1118     * @throws NullPointerException if {@code other} is null
1119     */
1120    @Override
1121    public int compareTo(OffsetTime other) {
1122        if (offset.equals(other.offset)) {
1123            return time.compareTo(other.time);
1124        }
1125        int compare = Long.compare(toEpochNano(), other.toEpochNano());
1126        if (compare == 0) {
1127            compare = time.compareTo(other.time);
1128        }
1129        return compare;
1130    }
1131
1132    //-----------------------------------------------------------------------
1133    /**
1134     * Checks if the instant of this {@code OffsetTime} is after that of the
1135     * specified time applying both times to a common date.
1136     * <p>
1137     * This method differs from the comparison in {@link #compareTo} in that it
1138     * only compares the instant of the time. This is equivalent to converting both
1139     * times to an instant using the same date and comparing the instants.
1140     *
1141     * @param other  the other time to compare to, not null
1142     * @return true if this is after the instant of the specified time
1143     */
1144    public boolean isAfter(OffsetTime other) {
1145        return toEpochNano() > other.toEpochNano();
1146    }
1147
1148    /**
1149     * Checks if the instant of this {@code OffsetTime} is before that of the
1150     * specified time applying both times to a common date.
1151     * <p>
1152     * This method differs from the comparison in {@link #compareTo} in that it
1153     * only compares the instant of the time. This is equivalent to converting both
1154     * times to an instant using the same date and comparing the instants.
1155     *
1156     * @param other  the other time to compare to, not null
1157     * @return true if this is before the instant of the specified time
1158     */
1159    public boolean isBefore(OffsetTime other) {
1160        return toEpochNano() < other.toEpochNano();
1161    }
1162
1163    /**
1164     * Checks if the instant of this {@code OffsetTime} is equal to that of the
1165     * specified time applying both times to a common date.
1166     * <p>
1167     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
1168     * in that it only compares the instant of the time. This is equivalent to converting both
1169     * times to an instant using the same date and comparing the instants.
1170     *
1171     * @param other  the other time to compare to, not null
1172     * @return true if this is equal to the instant of the specified time
1173     */
1174    public boolean isEqual(OffsetTime other) {
1175        return toEpochNano() == other.toEpochNano();
1176    }
1177
1178    //-----------------------------------------------------------------------
1179    /**
1180     * Checks if this time is equal to another time.
1181     * <p>
1182     * The comparison is based on the local-time and the offset.
1183     * To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}.
1184     * <p>
1185     * Only objects of type {@code OffsetTime} are compared, other types return false.
1186     * To compare the underlying local time of two {@code TemporalAccessor} instances,
1187     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
1188     *
1189     * @param obj  the object to check, null returns false
1190     * @return true if this is equal to the other time
1191     */
1192    @Override
1193    public boolean equals(Object obj) {
1194        if (this == obj) {
1195            return true;
1196        }
1197        if (obj instanceof OffsetTime) {
1198            OffsetTime other = (OffsetTime) obj;
1199            return time.equals(other.time) && offset.equals(other.offset);
1200        }
1201        return false;
1202    }
1203
1204    /**
1205     * A hash code for this time.
1206     *
1207     * @return a suitable hash code
1208     */
1209    @Override
1210    public int hashCode() {
1211        return time.hashCode() ^ offset.hashCode();
1212    }
1213
1214    //-----------------------------------------------------------------------
1215    /**
1216     * Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}.
1217     * <p>
1218     * The output will be one of the following ISO-8601 formats:
1219     * <p><ul>
1220     * <li>{@code HH:mmXXXXX}</li>
1221     * <li>{@code HH:mm:ssXXXXX}</li>
1222     * <li>{@code HH:mm:ss.SSSXXXXX}</li>
1223     * <li>{@code HH:mm:ss.SSSSSSXXXXX}</li>
1224     * <li>{@code HH:mm:ss.SSSSSSSSSXXXXX}</li>
1225     * </ul><p>
1226     * The format used will be the shortest that outputs the full value of
1227     * the time where the omitted parts are implied to be zero.
1228     *
1229     * @return a string representation of this time, not null
1230     */
1231    @Override
1232    public String toString() {
1233        return time.toString() + offset.toString();
1234    }
1235
1236    /**
1237     * Outputs this time as a {@code String} using the formatter.
1238     * <p>
1239     * This time will be passed to the formatter
1240     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
1241     *
1242     * @param formatter  the formatter to use, not null
1243     * @return the formatted time string, not null
1244     * @throws DateTimeException if an error occurs during printing
1245     */
1246    public String toString(DateTimeFormatter formatter) {
1247        Objects.requireNonNull(formatter, "formatter");
1248        return formatter.print(this);
1249    }
1250
1251    // -----------------------------------------------------------------------
1252    private Object writeReplace() {
1253        return new Ser(Ser.OFFSET_TIME_TYPE, this);
1254    }
1255
1256    /**
1257     * Defend against malicious streams.
1258     * @return never
1259     * @throws InvalidObjectException always
1260     */
1261    private Object readResolve() throws ObjectStreamException {
1262        throw new InvalidObjectException("Deserialization via serialization delegate");
1263    }
1264
1265    void writeExternal(DataOutput out) throws IOException {
1266        time.writeExternal(out);
1267        offset.writeExternal(out);
1268    }
1269
1270    static OffsetTime readExternal(DataInput in) throws IOException {
1271        LocalTime time = LocalTime.readExternal(in);
1272        ZoneOffset offset = ZoneOffset.readExternal(in);
1273        return OffsetTime.of(time, offset);
1274    }
1275
1276}