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.SECONDS_PER_DAY;
035import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY;
036import static org.threeten.bp.temporal.ChronoField.OFFSET_SECONDS;
037import static org.threeten.bp.temporal.ChronoUnit.DAYS;
038
039import java.io.DataInput;
040import java.io.DataOutput;
041import java.io.IOException;
042import java.io.InvalidObjectException;
043import java.io.ObjectStreamException;
044import java.io.Serializable;
045import java.util.Objects;
046
047import org.threeten.bp.format.DateTimeFormatter;
048import org.threeten.bp.format.DateTimeFormatters;
049import org.threeten.bp.format.DateTimeParseException;
050import org.threeten.bp.jdk8.DefaultInterfaceTemporalAccessor;
051import org.threeten.bp.jdk8.Jdk8Methods;
052import org.threeten.bp.temporal.ChronoField;
053import org.threeten.bp.temporal.ChronoUnit;
054import org.threeten.bp.temporal.ISOChrono;
055import org.threeten.bp.temporal.Temporal;
056import org.threeten.bp.temporal.TemporalAccessor;
057import org.threeten.bp.temporal.TemporalAdder;
058import org.threeten.bp.temporal.TemporalAdjuster;
059import org.threeten.bp.temporal.TemporalAdjusters;
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 date with an offset from UTC/Greenwich in the ISO-8601 calendar system,
070 * such as {@code 2007-12-03+01:00}.
071 * <p>
072 * {@code OffsetDate} is an immutable date-time object that represents a date, often viewed
073 * as year-month-day-offset. This object can also access other date fields such as
074 * day-of-year, day-of-week and week-of-year.
075 * <p>
076 * This class does not store or represent a time.
077 * For example, the value "2nd October 2007 +02:00" can be stored
078 * in an {@code OffsetDate}.
079 *
080 * <h3>Specification for implementors</h3>
081 * This class is immutable and thread-safe.
082 */
083public final class OffsetDate
084        extends DefaultInterfaceTemporalAccessor
085        implements Temporal, TemporalAdjuster, Comparable<OffsetDate>, Serializable {
086
087    /**
088     * The minimum supported {@code OffsetDate}, '-999999999-01-01+18:00'.
089     * This is the minimum local date in the maximum offset
090     * (larger offsets are earlier on the time-line).
091     * This combines {@link LocalDate#MIN} and {@link ZoneOffset#MAX}.
092     * This could be used by an application as a "far past" date.
093     */
094    public static final OffsetDate MIN = LocalDate.MIN.atOffset(ZoneOffset.MAX);
095    /**
096     * The maximum supported {@code OffsetDate}, '+999999999-12-31-18:00'.
097     * This is the maximum local date in the minimum offset
098     * (larger negative offsets are later on the time-line).
099     * This combines {@link LocalDate#MAX} and {@link ZoneOffset#MIN}.
100     * This could be used by an application as a "far future" date.
101     */
102    public static final OffsetDate MAX = LocalDate.MAX.atOffset(ZoneOffset.MIN);
103
104    /**
105     * Serialization version.
106     */
107    private static final long serialVersionUID = -4382054179074397774L;
108
109    /**
110     * The local date.
111     */
112    private final LocalDate date;
113    /**
114     * The offset from UTC/Greenwich.
115     */
116    private final ZoneOffset offset;
117
118    //-----------------------------------------------------------------------
119    /**
120     * Obtains the current date from the system clock in the default time-zone.
121     * <p>
122     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
123     * time-zone to obtain the current date.
124     * The offset will be calculated from the time-zone in the clock.
125     * <p>
126     * Using this method will prevent the ability to use an alternate clock for testing
127     * because the clock is hard-coded.
128     *
129     * @return the current date using the system clock, not null
130     */
131    public static OffsetDate now() {
132        return now(Clock.systemDefaultZone());
133    }
134
135    /**
136     * Obtains the current date from the system clock in the specified time-zone.
137     * <p>
138     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
139     * Specifying the time-zone avoids dependence on the default time-zone.
140     * The offset will be calculated from the specified time-zone.
141     * <p>
142     * Using this method will prevent the ability to use an alternate clock for testing
143     * because the clock is hard-coded.
144     *
145     * @param zone  the zone ID to use, not null
146     * @return the current date using the system clock, not null
147     */
148    public static OffsetDate now(ZoneId zone) {
149        return now(Clock.system(zone));
150    }
151
152    /**
153     * Obtains the current date from the specified clock.
154     * <p>
155     * This will query the specified clock to obtain the current date - today.
156     * The offset will be calculated from the time-zone in the clock.
157     * <p>
158     * Using this method allows the use of an alternate clock for testing.
159     * The alternate clock may be introduced using {@link Clock dependency injection}.
160     *
161     * @param clock  the clock to use, not null
162     * @return the current date, not null
163     */
164    public static OffsetDate now(Clock clock) {
165        Objects.requireNonNull(clock, "clock");
166        final Instant now = clock.instant();  // called once
167        return ofInstant(now, clock.getZone().getRules().getOffset(now));
168    }
169
170    //-----------------------------------------------------------------------
171    /**
172     * Obtains an instance of {@code OffsetDate} from a local date and an offset.
173     *
174     * @param date  the local date, not null
175     * @param offset  the zone offset, not null
176     * @return the offset date, not null
177     */
178    public static OffsetDate of(LocalDate date, ZoneOffset offset) {
179        return new OffsetDate(date, offset);
180    }
181
182    //-----------------------------------------------------------------------
183    /**
184     * Obtains an instance of {@code OffsetDate} from an {@code Instant} and zone ID.
185     * <p>
186     * This creates an offset date with the same instant as midnight at the
187     * start of day of the instant specified.
188     * Finding the offset from UTC/Greenwich is simple as there is only one valid
189     * offset for each instant.
190     *
191     * @param instant  the instant to create the time from, not null
192     * @param zone  the time-zone, which may be an offset, not null
193     * @return the offset time, not null
194     */
195    public static OffsetDate ofInstant(Instant instant, ZoneId zone) {
196        Objects.requireNonNull(instant, "instant");
197        Objects.requireNonNull(zone, "zone");
198        ZoneRules rules = zone.getRules();
199        ZoneOffset offset = rules.getOffset(instant);
200        long epochSec = instant.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
201        long epochDay = Jdk8Methods.floorDiv(epochSec, SECONDS_PER_DAY);
202        LocalDate date = LocalDate.ofEpochDay(epochDay);
203        return new OffsetDate(date, offset);
204    }
205
206    //-----------------------------------------------------------------------
207    /**
208     * Obtains an instance of {@code OffsetDate} from a temporal object.
209     * <p>
210     * A {@code TemporalAccessor} represents some form of date and time information.
211     * This factory converts the arbitrary temporal object to an instance of {@code OffsetDate}.
212     * <p>
213     * The conversion extracts and combines {@code LocalDate} and {@code ZoneOffset}.
214     * <p>
215     * This method matches the signature of the functional interface {@link TemporalQuery}
216     * allowing it to be used in queries via method reference, {@code OffsetDate::from}.
217     *
218     * @param temporal  the temporal object to convert, not null
219     * @return the offset date, not null
220     * @throws DateTimeException if unable to convert to an {@code OffsetDate}
221     */
222    public static OffsetDate from(TemporalAccessor temporal) {
223        if (temporal instanceof OffsetDate) {
224            return (OffsetDate) temporal;
225        }
226        try {
227            LocalDate date = LocalDate.from(temporal);
228            ZoneOffset offset = ZoneOffset.from(temporal);
229            return new OffsetDate(date, offset);
230        } catch (DateTimeException ex) {
231            throw new DateTimeException("Unable to obtain OffsetDate from TemporalAccessor: " + temporal.getClass(), ex);
232        }
233    }
234
235    //-----------------------------------------------------------------------
236    /**
237     * Obtains an instance of {@code OffsetDate} from a text string such as {@code 2007-12-03+01:00}.
238     * <p>
239     * The string must represent a valid date and is parsed using
240     * {@link org.threeten.bp.format.DateTimeFormatters#isoOffsetDate()}.
241     *
242     * @param text  the text to parse such as "2007-12-03+01:00", not null
243     * @return the parsed offset date, not null
244     * @throws DateTimeParseException if the text cannot be parsed
245     */
246    public static OffsetDate parse(CharSequence text) {
247        return parse(text, DateTimeFormatters.isoOffsetDate());
248    }
249
250    /**
251     * Obtains an instance of {@code OffsetDate} from a text string using a specific formatter.
252     * <p>
253     * The text is parsed using the formatter, returning a date.
254     *
255     * @param text  the text to parse, not null
256     * @param formatter  the formatter to use, not null
257     * @return the parsed offset date, not null
258     * @throws DateTimeParseException if the text cannot be parsed
259     */
260    public static OffsetDate parse(CharSequence text, DateTimeFormatter formatter) {
261        Objects.requireNonNull(formatter, "formatter");
262        return formatter.parse(text, OffsetDate.class);
263    }
264
265    //-----------------------------------------------------------------------
266    /**
267     * Constructor.
268     *
269     * @param date  the local date, not null
270     * @param offset  the zone offset, not null
271     */
272    private OffsetDate(LocalDate date, ZoneOffset offset) {
273        this.date = Objects.requireNonNull(date, "date");
274        this.offset = Objects.requireNonNull(offset, "offset");
275    }
276
277    /**
278     * Returns a new date based on this one, returning {@code this} where possible.
279     *
280     * @param date  the date to create with, not null
281     * @param offset  the zone offset to create with, not null
282     */
283    private OffsetDate with(LocalDate date, ZoneOffset offset) {
284        if (this.date == date && this.offset.equals(offset)) {
285            return this;
286        }
287        return new OffsetDate(date, offset);
288    }
289
290    //-----------------------------------------------------------------------
291    /**
292     * Checks if the specified field is supported.
293     * <p>
294     * This checks if this date can be queried for the specified field.
295     * If false, then calling the {@link #range(TemporalField) range} and
296     * {@link #get(TemporalField) get} methods will throw an exception.
297     * <p>
298     * If the field is a {@link ChronoField} then the query is implemented here.
299     * The {@link #isSupported(TemporalField) supported fields} will return valid
300     * values based on this date-time.
301     * The supported fields are:
302     * <ul>
303     * <li>{@code DAY_OF_WEEK}
304     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
305     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
306     * <li>{@code DAY_OF_MONTH}
307     * <li>{@code DAY_OF_YEAR}
308     * <li>{@code EPOCH_DAY}
309     * <li>{@code ALIGNED_WEEK_OF_MONTH}
310     * <li>{@code ALIGNED_WEEK_OF_YEAR}
311     * <li>{@code MONTH_OF_YEAR}
312     * <li>{@code EPOCH_MONTH}
313     * <li>{@code YEAR_OF_ERA}
314     * <li>{@code YEAR}
315     * <li>{@code ERA}
316     * <li>{@code OFFSET_SECONDS}
317     * </ul>
318     * All other {@code ChronoField} instances will return false.
319     * <p>
320     * If the field is not a {@code ChronoField}, then the result of this method
321     * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
322     * passing {@code this} as the argument.
323     * Whether the field is supported is determined by the field.
324     *
325     * @param field  the field to check, null returns false
326     * @return true if the field is supported on this date, false if not
327     */
328    @Override
329    public boolean isSupported(TemporalField field) {
330        if (field instanceof ChronoField) {
331            return ((ChronoField) field).isDateField() || field == OFFSET_SECONDS;
332        }
333        return field != null && field.doIsSupported(this);
334    }
335
336    /**
337     * Gets the range of valid values for the specified field.
338     * <p>
339     * The range object expresses the minimum and maximum valid values for a field.
340     * This date is used to enhance the accuracy of the returned range.
341     * If it is not possible to return the range, because the field is not supported
342     * or for some other reason, an exception is thrown.
343     * <p>
344     * If the field is a {@link ChronoField} then the query is implemented here.
345     * The {@link #isSupported(TemporalField) supported fields} will return
346     * appropriate range instances.
347     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
348     * <p>
349     * If the field is not a {@code ChronoField}, then the result of this method
350     * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
351     * passing {@code this} as the argument.
352     * Whether the range can be obtained is determined by the field.
353     *
354     * @param field  the field to query the range for, not null
355     * @return the range of valid values for the field, not null
356     * @throws DateTimeException if the range for the field cannot be obtained
357     */
358    @Override
359    public ValueRange range(TemporalField field) {
360        if (field instanceof ChronoField) {
361            if (field == OFFSET_SECONDS) {
362                return field.range();
363            }
364            return date.range(field);
365        }
366        return field.doRange(this);
367    }
368
369    /**
370     * Gets the value of the specified field from this date as an {@code int}.
371     * <p>
372     * This queries this date for the value for the specified field.
373     * The returned value will always be within the valid range of values for the field.
374     * If it is not possible to return the value, because the field is not supported
375     * or for some other reason, an exception is thrown.
376     * <p>
377     * If the field is a {@link ChronoField} then the query is implemented here.
378     * The {@link #isSupported(TemporalField) supported fields} will return valid
379     * values based on this date, except {@code EPOCH_DAY} and {@code EPOCH_MONTH}
380     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
381     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
382     * <p>
383     * If the field is not a {@code ChronoField}, then the result of this method
384     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
385     * passing {@code this} as the argument. Whether the value can be obtained,
386     * and what the value represents, is determined by the field.
387     *
388     * @param field  the field to get, not null
389     * @return the value for the field
390     * @throws DateTimeException if a value for the field cannot be obtained
391     * @throws ArithmeticException if numeric overflow occurs
392     */
393    @Override  // override for Javadoc
394    public int get(TemporalField field) {
395        return super.get(field);
396    }
397
398    /**
399     * Gets the value of the specified field from this date as a {@code long}.
400     * <p>
401     * This queries this date for the value for the specified field.
402     * If it is not possible to return the value, because the field is not supported
403     * or for some other reason, an exception is thrown.
404     * <p>
405     * If the field is a {@link ChronoField} then the query is implemented here.
406     * The {@link #isSupported(TemporalField) supported fields} will return valid
407     * values based on this date.
408     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
409     * <p>
410     * If the field is not a {@code ChronoField}, then the result of this method
411     * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
412     * passing {@code this} as the argument. Whether the value can be obtained,
413     * and what the value represents, is determined by the field.
414     *
415     * @param field  the field to get, not null
416     * @return the value for the field
417     * @throws DateTimeException if a value for the field cannot be obtained
418     * @throws ArithmeticException if numeric overflow occurs
419     */
420    @Override
421    public long getLong(TemporalField field) {
422        if (field instanceof ChronoField) {
423            if (field == OFFSET_SECONDS) {
424                return getOffset().getTotalSeconds();
425            }
426            return date.getLong(field);
427        }
428        return field.doGet(this);
429    }
430
431    //-----------------------------------------------------------------------
432    /**
433     * Gets the zone offset, such as '+01:00'.
434     * <p>
435     * This is the offset of the local date from UTC/Greenwich.
436     *
437     * @return the zone offset, not null
438     */
439    public ZoneOffset getOffset() {
440        return offset;
441    }
442
443    /**
444     * Returns a copy of this {@code OffsetDate} with the specified offset.
445     * <p>
446     * This method returns an object with the same {@code LocalDate} and the specified {@code ZoneOffset}.
447     * No calculation is needed or performed.
448     * For example, if this time represents {@code 2007-12-03+02:00} and the offset specified is
449     * {@code +03:00}, then this method will return {@code 2007-12-03+03:00}.
450     * <p>
451     * This instance is immutable and unaffected by this method call.
452     *
453     * @param offset  the zone offset to change to, not null
454     * @return an {@code OffsetDate} based on this date with the requested offset, not null
455     */
456    public OffsetDate withOffset(ZoneOffset offset) {
457        Objects.requireNonNull(offset, "offset");
458        return with(date, offset);
459    }
460
461    //-----------------------------------------------------------------------
462    /**
463     * Gets the {@code LocalDate} part of this date-time.
464     * <p>
465     * This returns a {@code LocalDate} with the same year, month and day
466     * as this date-time.
467     *
468     * @return the date part of this date-time, not null
469     */
470    public LocalDate getDate() {
471        return date;
472    }
473
474    //-----------------------------------------------------------------------
475    /**
476     * Gets the year field.
477     * <p>
478     * This method returns the primitive {@code int} value for the year.
479     * <p>
480     * The year returned by this method is proleptic as per {@code get(YEAR)}.
481     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA}.
482     *
483     * @return the year, from MIN_YEAR to MAX_YEAR
484     */
485    public int getYear() {
486        return date.getYear();
487    }
488
489    /**
490     * Gets the month-of-year field from 1 to 12.
491     * <p>
492     * This method returns the month as an {@code int} from 1 to 12.
493     * Application code is frequently clearer if the enum {@link Month}
494     * is used by calling {@link #getMonth()}.
495     *
496     * @return the month-of-year, from 1 to 12
497     * @see #getMonth()
498     */
499    public int getMonthValue() {
500        return date.getMonthValue();
501    }
502
503    /**
504     * Gets the month-of-year field using the {@code Month} enum.
505     * <p>
506     * This method returns the enum {@link Month} for the month.
507     * This avoids confusion as to what {@code int} values mean.
508     * If you need access to the primitive {@code int} value then the enum
509     * provides the {@link Month#getValue() int value}.
510     *
511     * @return the month-of-year, not null
512     * @see #getMonthValue()
513     */
514    public Month getMonth() {
515        return date.getMonth();
516    }
517
518    /**
519     * Gets the day-of-month field.
520     * <p>
521     * This method returns the primitive {@code int} value for the day-of-month.
522     *
523     * @return the day-of-month, from 1 to 31
524     */
525    public int getDayOfMonth() {
526        return date.getDayOfMonth();
527    }
528
529    /**
530     * Gets the day-of-year field.
531     * <p>
532     * This method returns the primitive {@code int} value for the day-of-year.
533     *
534     * @return the day-of-year, from 1 to 365, or 366 in a leap year
535     */
536    public int getDayOfYear() {
537        return date.getDayOfYear();
538    }
539
540    /**
541     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
542     * <p>
543     * This method returns the enum {@link DayOfWeek} for the day-of-week.
544     * This avoids confusion as to what {@code int} values mean.
545     * If you need access to the primitive {@code int} value then the enum
546     * provides the {@link DayOfWeek#getValue() int value}.
547     * <p>
548     * Additional information can be obtained from the {@code DayOfWeek}.
549     * This includes textual names of the values.
550     *
551     * @return the day-of-week, not null
552     */
553    public DayOfWeek getDayOfWeek() {
554        return date.getDayOfWeek();
555    }
556
557    //-----------------------------------------------------------------------
558    /**
559     * Returns an adjusted copy of this date.
560     * <p>
561     * This returns a new {@code OffsetDate}, based on this one, with the date adjusted.
562     * The adjustment takes place using the specified adjuster strategy object.
563     * Read the documentation of the adjuster to understand what adjustment will be made.
564     * <p>
565     * A simple adjuster might simply set the one of the fields, such as the year field.
566     * A more complex adjuster might set the date to the last day of the month.
567     * A selection of common adjustments is provided in {@link TemporalAdjusters}.
568     * These include finding the "last day of the month" and "next Wednesday".
569     * Key date-time classes also implement the {@code TemporalAdjuster} interface,
570     * such as {@link Month} and {@link MonthDay MonthDay}.
571     * The adjuster is responsible for handling special cases, such as the varying
572     * lengths of month and leap years.
573     * <p>
574     * For example this code returns a date on the last day of July:
575     * <pre>
576     *  import static org.threeten.bp.Month.*;
577     *  import static org.threeten.bp.temporal.Adjusters.*;
578     *
579     *  result = offsetDate.with(JULY).with(lastDayOfMonth());
580     * </pre>
581     * <p>
582     * The classes {@link LocalDate} and {@link ZoneOffset} implement {@code TemporalAdjuster},
583     * thus this method can be used to change the date or offset:
584     * <pre>
585     *  result = offsetDate.with(date);
586     *  result = offsetDate.with(offset);
587     * </pre>
588     * <p>
589     * The result of this method is obtained by invoking the
590     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
591     * specified adjuster passing {@code this} as the argument.
592     * <p>
593     * This instance is immutable and unaffected by this method call.
594     *
595     * @param adjuster the adjuster to use, not null
596     * @return an {@code OffsetDate} based on {@code this} with the adjustment made, not null
597     * @throws DateTimeException if the adjustment cannot be made
598     * @throws ArithmeticException if numeric overflow occurs
599     */
600    @Override
601    public OffsetDate with(TemporalAdjuster adjuster) {
602        // optimizations
603        if (adjuster instanceof LocalDate) {
604            return with((LocalDate) adjuster, offset);
605        } else if (adjuster instanceof ZoneOffset) {
606            return with(date, (ZoneOffset) adjuster);
607        } else if (adjuster instanceof OffsetDate) {
608            return (OffsetDate) adjuster;
609        }
610        return (OffsetDate) adjuster.adjustInto(this);
611    }
612
613    /**
614     * Returns a copy of this date with the specified field set to a new value.
615     * <p>
616     * This returns a new {@code OffsetDate}, based on this one, with the value
617     * for the specified field changed.
618     * This can be used to change any supported field, such as the year, month or day-of-month.
619     * If it is not possible to set the value, because the field is not supported or for
620     * some other reason, an exception is thrown.
621     * <p>
622     * In some cases, changing the specified field can cause the resulting date to become invalid,
623     * such as changing the month from 31st January to February would make the day-of-month invalid.
624     * In cases like this, the field is responsible for resolving the date. Typically it will choose
625     * the previous valid date, which would be the last valid day of February in this example.
626     * <p>
627     * If the field is a {@link ChronoField} then the adjustment is implemented here.
628     * <p>
629     * The {@code OFFSET_SECONDS} field will return a date with the specified offset.
630     * The local date is unaltered. If the new offset value is outside the valid range
631     * then a {@code DateTimeException} will be thrown.
632     * <p>
633     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
634     * the matching method on {@link LocalDate#with(TemporalField, long)} LocalDate}.
635     * In this case, the offset is not part of the calculation and will be unchanged.
636     * <p>
637     * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
638     * <p>
639     * If the field is not a {@code ChronoField}, then the result of this method
640     * is obtained by invoking {@code TemporalField.doWith(Temporal, long)}
641     * passing {@code this} as the argument. In this case, the field determines
642     * whether and how to adjust the instant.
643     * <p>
644     * This instance is immutable and unaffected by this method call.
645     *
646     * @param field  the field to set in the result, not null
647     * @param newValue  the new value of the field in the result
648     * @return an {@code OffsetDate} based on {@code this} with the specified field set, not null
649     * @throws DateTimeException if the field cannot be set
650     * @throws ArithmeticException if numeric overflow occurs
651     */
652    @Override
653    public OffsetDate with(TemporalField field, long newValue) {
654        if (field instanceof ChronoField) {
655            if (field == OFFSET_SECONDS) {
656                ChronoField f = (ChronoField) field;
657                return with(date, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
658            }
659            return with(date.with(field, newValue), offset);
660        }
661        return field.doWith(this, newValue);
662    }
663
664    //-----------------------------------------------------------------------
665    /**
666     * Returns a copy of this {@code OffsetDate} with the year altered.
667     * The offset does not affect the calculation and will be the same in the result.
668     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
669     * <p>
670     * This instance is immutable and unaffected by this method call.
671     *
672     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
673     * @return an {@code OffsetDate} based on this date with the requested year, not null
674     * @throws DateTimeException if the year value is invalid
675     */
676    public OffsetDate withYear(int year) {
677        return with(date.withYear(year), offset);
678    }
679
680    /**
681     * Returns a copy of this {@code OffsetDate} with the month-of-year altered.
682     * The offset does not affect the calculation and will be the same in the result.
683     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
684     * <p>
685     * This instance is immutable and unaffected by this method call.
686     *
687     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
688     * @return an {@code OffsetDate} based on this date with the requested month, not null
689     * @throws DateTimeException if the month-of-year value is invalid
690     */
691    public OffsetDate withMonth(int month) {
692        return with(date.withMonth(month), offset);
693    }
694
695    /**
696     * Returns a copy of this {@code OffsetDate} with the day-of-month altered.
697     * If the resulting date is invalid, an exception is thrown.
698     * The offset does not affect the calculation and will be the same in the result.
699     * <p>
700     * This instance is immutable and unaffected by this method call.
701     *
702     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
703     * @return an {@code OffsetDate} based on this date with the requested day, not null
704     * @throws DateTimeException if the day-of-month value is invalid
705     * @throws DateTimeException if the day-of-month is invalid for the month-year
706     */
707    public OffsetDate withDayOfMonth(int dayOfMonth) {
708        return with(date.withDayOfMonth(dayOfMonth), offset);
709    }
710
711    /**
712     * Returns a copy of this {@code OffsetDate} with the day-of-year altered.
713     * If the resulting date is invalid, an exception is thrown.
714     * <p>
715     * This instance is immutable and unaffected by this method call.
716     *
717     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
718     * @return an {@code OffsetDate} based on this date with the requested day, not null
719     * @throws DateTimeException if the day-of-year value is invalid
720     * @throws DateTimeException if the day-of-year is invalid for the year
721     */
722    public OffsetDate withDayOfYear(int dayOfYear) {
723        return with(date.withDayOfYear(dayOfYear), offset);
724    }
725
726    //-----------------------------------------------------------------------
727    /**
728     * Returns a copy of this date with the specified period added.
729     * <p>
730     * This method returns a new date based on this date with the specified period added.
731     * The adder is typically {@link Period} but may be any other type implementing
732     * the {@link TemporalAdder} interface.
733     * The calculation is delegated to the specified adjuster, which typically calls
734     * back to {@link #plus(long, TemporalUnit)}.
735     * The offset is not part of the calculation and will be unchanged in the result.
736     * <p>
737     * This instance is immutable and unaffected by this method call.
738     *
739     * @param adder  the adder to use, not null
740     * @return an {@code OffsetDate} based on this date with the addition made, not null
741     * @throws DateTimeException if the addition cannot be made
742     * @throws ArithmeticException if numeric overflow occurs
743     */
744    @Override
745    public OffsetDate plus(TemporalAdder adder) {
746        return (OffsetDate) adder.addTo(this);
747    }
748
749    /**
750     * Returns a copy of this date with the specified period added.
751     * <p>
752     * This method returns a new date based on this date with the specified period added.
753     * This can be used to add any period that is defined by a unit, for example to add years, months or days.
754     * The unit is responsible for the details of the calculation, including the resolution
755     * of any edge cases in the calculation.
756     * The offset is not part of the calculation and will be unchanged in the result.
757     * <p>
758     * This instance is immutable and unaffected by this method call.
759     *
760     * @param amountToAdd  the amount of the unit to add to the result, may be negative
761     * @param unit  the unit of the period to add, not null
762     * @return an {@code OffsetDate} based on this date with the specified period added, not null
763     * @throws DateTimeException if the unit cannot be added to this type
764     */
765    @Override
766    public OffsetDate plus(long amountToAdd, TemporalUnit unit) {
767        if (unit instanceof ChronoUnit) {
768            return with(date.plus(amountToAdd, unit), offset);
769        }
770        return unit.doPlus(this, amountToAdd);
771    }
772
773    //-----------------------------------------------------------------------
774    /**
775     * Returns a copy of this {@code OffsetDate} with the specified period in years added.
776     * <p>
777     * This method adds the specified amount to the years field in three steps:
778     * <ol>
779     * <li>Add the input years to the year field</li>
780     * <li>Check if the resulting date would be invalid</li>
781     * <li>Adjust the day-of-month to the last valid day if necessary</li>
782     * </ol>
783     * <p>
784     * For example, 2008-02-29 (leap year) plus one year would result in the
785     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
786     * result, the last valid day of the month, 2009-02-28, is selected instead.
787     * <p>
788     * This instance is immutable and unaffected by this method call.
789     *
790     * @param years  the years to add, may be negative
791     * @return an {@code OffsetDate} based on this date with the years added, not null
792     * @throws DateTimeException if the result exceeds the supported date range
793     */
794    public OffsetDate plusYears(long years) {
795        return with(date.plusYears(years), offset);
796    }
797
798    /**
799     * Returns a copy of this {@code OffsetDate} with the specified period in months added.
800     * <p>
801     * This method adds the specified amount to the months field in three steps:
802     * <ol>
803     * <li>Add the input months to the month-of-year field</li>
804     * <li>Check if the resulting date would be invalid</li>
805     * <li>Adjust the day-of-month to the last valid day if necessary</li>
806     * </ol>
807     * <p>
808     * For example, 2007-03-31 plus one month would result in the invalid date
809     * 2007-04-31. Instead of returning an invalid result, the last valid day
810     * of the month, 2007-04-30, is selected instead.
811     * <p>
812     * This instance is immutable and unaffected by this method call.
813     *
814     * @param months  the months to add, may be negative
815     * @return an {@code OffsetDate} based on this date with the months added, not null
816     * @throws DateTimeException if the result exceeds the supported date range
817     */
818    public OffsetDate plusMonths(long months) {
819        return with(date.plusMonths(months), offset);
820    }
821
822    /**
823     * Returns a copy of this {@code OffsetDate} with the specified period in weeks added.
824     * <p>
825     * This method adds the specified amount in weeks to the days field incrementing
826     * the month and year fields as necessary to ensure the result remains valid.
827     * The result is only invalid if the maximum/minimum year is exceeded.
828     * <p>
829     * For example, 2008-12-31 plus one week would result in 2009-01-07.
830     * <p>
831     * This instance is immutable and unaffected by this method call.
832     *
833     * @param weeks  the weeks to add, may be negative
834     * @return an {@code OffsetDate} based on this date with the weeks added, not null
835     * @throws DateTimeException if the result exceeds the supported date range
836     */
837    public OffsetDate plusWeeks(long weeks) {
838        return with(date.plusWeeks(weeks), offset);
839    }
840
841    /**
842     * Returns a copy of this {@code OffsetDate} with the specified period in days added.
843     * <p>
844     * This method adds the specified amount to the days field incrementing the
845     * month and year fields as necessary to ensure the result remains valid.
846     * The result is only invalid if the maximum/minimum year is exceeded.
847     * <p>
848     * For example, 2008-12-31 plus one day would result in 2009-01-01.
849     * <p>
850     * This instance is immutable and unaffected by this method call.
851     *
852     * @param days  the days to add, may be negative
853     * @return an {@code OffsetDate} based on this date with the days added, not null
854     * @throws DateTimeException if the result exceeds the supported date range
855     */
856    public OffsetDate plusDays(long days) {
857        return with(date.plusDays(days), offset);
858    }
859
860    //-----------------------------------------------------------------------
861    /**
862     * Returns a copy of this date with the specified period subtracted.
863     * <p>
864     * This method returns a new date based on this date with the specified period subtracted.
865     * The subtractor is typically {@link Period} but may be any other type implementing
866     * the {@link TemporalSubtractor} interface.
867     * The calculation is delegated to the specified adjuster, which typically calls
868     * back to {@link #minus(long, TemporalUnit)}.
869     * The offset is not part of the calculation and will be unchanged in the result.
870     * <p>
871     * This instance is immutable and unaffected by this method call.
872     *
873     * @param subtractor  the subtractor to use, not null
874     * @return an {@code OffsetDate} based on this date with the subtraction made, not null
875     * @throws DateTimeException if the subtraction cannot be made
876     * @throws ArithmeticException if numeric overflow occurs
877     */
878    @Override
879    public OffsetDate minus(TemporalSubtractor subtractor) {
880        return (OffsetDate) subtractor.subtractFrom(this);
881    }
882
883    /**
884     * Returns a copy of this date with the specified period subtracted.
885     * <p>
886     * This method returns a new date based on this date with the specified period subtracted.
887     * This can be used to subtract any period that is defined by a unit, for example to subtract years, months or days.
888     * The unit is responsible for the details of the calculation, including the resolution
889     * of any edge cases in the calculation.
890     * The offset is not part of the calculation and will be unchanged in the result.
891     * <p>
892     * This instance is immutable and unaffected by this method call.
893     *
894     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
895     * @param unit  the unit of the period to subtract, not null
896     * @return an {@code OffsetDate} based on this date with the specified period subtracted, not null
897     * @throws DateTimeException if the unit cannot be added to this type
898     */
899    @Override
900    public OffsetDate minus(long amountToSubtract, TemporalUnit unit) {
901        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
902    }
903
904    //-----------------------------------------------------------------------
905    /**
906     * Returns a copy of this {@code OffsetDate} with the specified period in years subtracted.
907     * <p>
908     * This method subtracts the specified amount from the years field in three steps:
909     * <ol>
910     * <li>Subtract the input years to the year field</li>
911     * <li>Check if the resulting date would be invalid</li>
912     * <li>Adjust the day-of-month to the last valid day if necessary</li>
913     * </ol>
914     * <p>
915     * For example, 2008-02-29 (leap year) minus one year would result in the
916     * invalid date 2007-02-29 (standard year). Instead of returning an invalid
917     * result, the last valid day of the month, 2007-02-28, is selected instead.
918     * <p>
919     * This instance is immutable and unaffected by this method call.
920     *
921     * @param years  the years to subtract, may be negative
922     * @return an {@code OffsetDate} based on this date with the years subtracted, not null
923     * @throws DateTimeException if the result exceeds the supported date range
924     */
925    public OffsetDate minusYears(long years) {
926        return with(date.minusYears(years), offset);
927    }
928
929    /**
930     * Returns a copy of this {@code OffsetDate} with the specified period in months subtracted.
931     * <p>
932     * This method subtracts the specified amount from the months field in three steps:
933     * <ol>
934     * <li>Subtract the input months to the month-of-year field</li>
935     * <li>Check if the resulting date would be invalid</li>
936     * <li>Adjust the day-of-month to the last valid day if necessary</li>
937     * </ol>
938     * <p>
939     * For example, 2007-03-31 minus one month would result in the invalid date
940     * 2007-02-31. Instead of returning an invalid result, the last valid day
941     * of the month, 2007-02-28, is selected instead.
942     * <p>
943     * This instance is immutable and unaffected by this method call.
944     *
945     * @param months  the months to subtract, may be negative
946     * @return an {@code OffsetDate} based on this date with the months subtracted, not null
947     * @throws DateTimeException if the result exceeds the supported date range
948     */
949    public OffsetDate minusMonths(long months) {
950        return with(date.minusMonths(months), offset);
951    }
952
953    /**
954     * Returns a copy of this {@code OffsetDate} with the specified period in weeks subtracted.
955     * <p>
956     * This method subtracts the specified amount in weeks from the days field decrementing
957     * the month and year fields as necessary to ensure the result remains valid.
958     * The result is only invalid if the maximum/minimum year is exceeded.
959     * <p>
960     * For example, 2009-01-07 minus one week would result in 2008-12-31.
961     * <p>
962     * This instance is immutable and unaffected by this method call.
963     *
964     * @param weeks  the weeks to subtract, may be negative
965     * @return an {@code OffsetDate} based on this date with the weeks subtracted, not null
966     * @throws DateTimeException if the result exceeds the supported date range
967     */
968    public OffsetDate minusWeeks(long weeks) {
969        return with(date.minusWeeks(weeks), offset);
970    }
971
972    /**
973     * Returns a copy of this {@code OffsetDate} with the specified number of days subtracted.
974     * <p>
975     * This method subtracts the specified amount from the days field decrementing the
976     * month and year fields as necessary to ensure the result remains valid.
977     * The result is only invalid if the maximum/minimum year is exceeded.
978     * <p>
979     * For example, 2009-01-01 minus one day would result in 2008-12-31.
980     * <p>
981     * This instance is immutable and unaffected by this method call.
982     *
983     * @param days  the days to subtract, may be negative
984     * @return an {@code OffsetDate} based on this date with the days subtracted, not null
985     * @throws DateTimeException if the result exceeds the supported date range
986     */
987    public OffsetDate minusDays(long days) {
988        return with(date.minusDays(days), offset);
989    }
990
991    //-----------------------------------------------------------------------
992    /**
993     * Queries this date using the specified query.
994     * <p>
995     * This queries this date using the specified query strategy object.
996     * The {@code TemporalQuery} object defines the logic to be used to
997     * obtain the result. Read the documentation of the query to understand
998     * what the result of this method will be.
999     * <p>
1000     * The result of this method is obtained by invoking the
1001     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
1002     * specified query passing {@code this} as the argument.
1003     *
1004     * @param <R> the type of the result
1005     * @param query  the query to invoke, not null
1006     * @return the query result, null may be returned (defined by the query)
1007     * @throws DateTimeException if unable to query (defined by the query)
1008     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
1009     */
1010    @SuppressWarnings("unchecked")
1011    @Override
1012    public <R> R query(TemporalQuery<R> query) {
1013        if (query == TemporalQueries.chrono()) {
1014            return (R) ISOChrono.INSTANCE;
1015        } else if (query == TemporalQueries.precision()) {
1016            return (R) DAYS;
1017        } else if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
1018            return (R) getOffset();
1019        }
1020        return super.query(query);
1021    }
1022
1023    /**
1024     * Adjusts the specified temporal object to have the same offset and date
1025     * as this object.
1026     * <p>
1027     * This returns a temporal object of the same observable type as the input
1028     * with the offset and date changed to be the same as this.
1029     * <p>
1030     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
1031     * twice, passing {@link ChronoField#OFFSET_SECONDS} and
1032     * {@link ChronoField#EPOCH_DAY} as the fields.
1033     * <p>
1034     * In most cases, it is clearer to reverse the calling pattern by using
1035     * {@link Temporal#with(TemporalAdjuster)}:
1036     * <pre>
1037     *   // these two lines are equivalent, but the second approach is recommended
1038     *   temporal = thisOffsetDate.adjustInto(temporal);
1039     *   temporal = temporal.with(thisOffsetDate);
1040     * </pre>
1041     * <p>
1042     * This instance is immutable and unaffected by this method call.
1043     *
1044     * @param temporal  the target object to be adjusted, not null
1045     * @return the adjusted object, not null
1046     * @throws DateTimeException if unable to make the adjustment
1047     * @throws ArithmeticException if numeric overflow occurs
1048     */
1049    @Override
1050    public Temporal adjustInto(Temporal temporal) {
1051        return temporal
1052                .with(OFFSET_SECONDS, getOffset().getTotalSeconds())
1053                .with(EPOCH_DAY, getDate().toEpochDay());
1054    }
1055
1056    /**
1057     * Calculates the period between this date and another date in
1058     * terms of the specified unit.
1059     * <p>
1060     * This calculates the period between two dates in terms of a single unit.
1061     * The start and end points are {@code this} and the specified date.
1062     * The result will be negative if the end is before the start.
1063     * For example, the period in days between two dates can be calculated
1064     * using {@code startDate.periodUntil(endDate, DAYS)}.
1065     * <p>
1066     * The {@code Temporal} passed to this method must be an {@code OffsetDate}.
1067     * If the offset differs between the two times, then the specified
1068     * end time is normalized to have the same offset as this time.
1069     * <p>
1070     * The calculation returns a whole number, representing the number of
1071     * complete units between the two dates.
1072     * For example, the period in months between 2012-06-15Z and 2012-08-14Z
1073     * will only be one month as it is one day short of two months.
1074     * <p>
1075     * This method operates in association with {@link TemporalUnit#between}.
1076     * The result of this method is a {@code long} representing the amount of
1077     * the specified unit. By contrast, the result of {@code between} is an
1078     * object that can be used directly in addition/subtraction:
1079     * <pre>
1080     *   long period = start.periodUntil(end, MONTHS);   // this method
1081     *   dateTime.plus(MONTHS.between(start, end));      // use in plus/minus
1082     * </pre>
1083     * <p>
1084     * The calculation is implemented in this method for {@link ChronoUnit}.
1085     * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
1086     * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
1087     * are supported. Other {@code ChronoUnit} values will throw an exception.
1088     * <p>
1089     * If the unit is not a {@code ChronoUnit}, then the result of this method
1090     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
1091     * passing {@code this} as the first argument and the input temporal as
1092     * the second argument.
1093     * <p>
1094     * This instance is immutable and unaffected by this method call.
1095     *
1096     * @param endDate  the end date, which must be an {@code OffsetDate}, not null
1097     * @param unit  the unit to measure the period in, not null
1098     * @return the amount of the period between this date and the end date
1099     * @throws DateTimeException if the period cannot be calculated
1100     * @throws ArithmeticException if numeric overflow occurs
1101     */
1102    @Override
1103    public long periodUntil(Temporal endDate, TemporalUnit unit) {
1104        if (endDate instanceof OffsetDate == false) {
1105            Objects.requireNonNull(endDate, "endDate");
1106            throw new DateTimeException("Unable to calculate period between objects of two different types");
1107        }
1108        if (unit instanceof ChronoUnit) {
1109            OffsetDate end = (OffsetDate) endDate;
1110            long offsetDiff = end.offset.getTotalSeconds() - offset.getTotalSeconds();
1111            LocalDate endLocal = end.date.plusDays(Jdk8Methods.floorDiv(-offsetDiff, SECONDS_PER_DAY));
1112            return date.periodUntil(endLocal, unit);
1113        }
1114        return unit.between(this, endDate).getAmount();
1115    }
1116
1117    //-----------------------------------------------------------------------
1118    /**
1119     * Returns an offset date-time formed from this date at the specified time.
1120     * <p>
1121     * This combines this date with the specified time to form an {@code OffsetDateTime}.
1122     * All possible combinations of date and time are valid.
1123     * <p>
1124     * This instance is immutable and unaffected by this method call.
1125     *
1126     * @param time  the time to combine with, not null
1127     * @return the offset date-time formed from this date and the specified time, not null
1128     */
1129    public OffsetDateTime atTime(LocalTime time) {
1130        return OffsetDateTime.of(date, time, offset);
1131    }
1132
1133    //-----------------------------------------------------------------------
1134    /**
1135     * Converts this date to midnight at the start of day in epoch seconds.
1136     *
1137     * @return the epoch seconds value
1138     */
1139    private long toEpochSecond() {
1140        long epochDay = date.toEpochDay();
1141        long secs = epochDay * SECONDS_PER_DAY;
1142        return secs - offset.getTotalSeconds();
1143    }
1144
1145    //-----------------------------------------------------------------------
1146    /**
1147     * Compares this {@code OffsetDate} to another date.
1148     * <p>
1149     * The comparison is based first on the UTC equivalent instant, then on the local date.
1150     * It is "consistent with equals", as defined by {@link Comparable}.
1151     * <p>
1152     * For example, the following is the comparator order:
1153     * <ol>
1154     * <li>2008-06-29-11:00</li>
1155     * <li>2008-06-29-12:00</li>
1156     * <li>2008-06-30+12:00</li>
1157     * <li>2008-06-29-13:00</li>
1158     * </ol>
1159     * Values #2 and #3 represent the same instant on the time-line.
1160     * When two values represent the same instant, the local date is compared
1161     * to distinguish them. This step is needed to make the ordering
1162     * consistent with {@code equals()}.
1163     * <p>
1164     * To compare the underlying local date of two {@code TemporalAccessor} instances,
1165     * use {@link ChronoField#EPOCH_DAY} as a comparator.
1166     *
1167     * @param other  the other date to compare to, not null
1168     * @return the comparator value, negative if less, positive if greater
1169     */
1170    @Override
1171    public int compareTo(OffsetDate other) {
1172        if (offset.equals(other.offset)) {
1173            return date.compareTo(other.date);
1174        }
1175        int compare = Long.compare(toEpochSecond(), other.toEpochSecond());
1176        if (compare == 0) {
1177            compare = date.compareTo(other.date);
1178        }
1179        return compare;
1180    }
1181
1182    //-----------------------------------------------------------------------
1183    /**
1184     * Checks if the instant of midnight at the start of this {@code OffsetDate}
1185     * is after midnight at the start of the specified date.
1186     * <p>
1187     * This method differs from the comparison in {@link #compareTo} in that it
1188     * only compares the instant of the date. This is equivalent to using
1189     * {@code date1.toEpochSecond().isAfter(date2.toEpochSecond())}.
1190     *
1191     * @param other  the other date to compare to, not null
1192     * @return true if this is after the instant of the specified date
1193     */
1194    public boolean isAfter(OffsetDate other) {
1195        return toEpochSecond() > other.toEpochSecond();
1196    }
1197
1198    /**
1199     * Checks if the instant of midnight at the start of this {@code OffsetDate}
1200     * is before midnight at the start of the specified date.
1201     * <p>
1202     * This method differs from the comparison in {@link #compareTo} in that it
1203     * only compares the instant of the date. This is equivalent to using
1204     * {@code date1.toEpochSecond().isBefore(date2.toEpochSecond())}.
1205     *
1206     * @param other  the other date to compare to, not null
1207     * @return true if this is before the instant of the specified date
1208     */
1209    public boolean isBefore(OffsetDate other) {
1210        return toEpochSecond() < other.toEpochSecond();
1211    }
1212
1213    /**
1214     * Checks if the instant of midnight at the start of this {@code OffsetDate}
1215     * equals midnight at the start of the specified date.
1216     * <p>
1217     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
1218     * in that it only compares the instant of the date. This is equivalent to using
1219     * {@code date1.toEpochSecond().equals(date2.toEpochSecond())}.
1220     *
1221     * @param other  the other date to compare to, not null
1222     * @return true if the instant equals the instant of the specified date
1223     */
1224    public boolean isEqual(OffsetDate other) {
1225        return toEpochSecond() == other.toEpochSecond();
1226    }
1227
1228    //-----------------------------------------------------------------------
1229    /**
1230     * Checks if this date is equal to another date.
1231     * <p>
1232     * The comparison is based on the local-date and the offset.
1233     * To compare for the same instant on the time-line, use {@link #isEqual(OffsetDate)}.
1234     * <p>
1235     * Only objects of type {@code OffsetDate} are compared, other types return false.
1236     * To compare the underlying local date of two {@code TemporalAccessor} instances,
1237     * use {@link ChronoField#EPOCH_DAY} as a comparator.
1238     *
1239     * @param obj  the object to check, null returns false
1240     * @return true if this is equal to the other date
1241     */
1242    @Override
1243    public boolean equals(Object obj) {
1244        if (this == obj) {
1245            return true;
1246        }
1247        if (obj instanceof OffsetDate) {
1248            OffsetDate other = (OffsetDate) obj;
1249            return date.equals(other.date) && offset.equals(other.offset);
1250        }
1251        return false;
1252    }
1253
1254    /**
1255     * A hash code for this date.
1256     *
1257     * @return a suitable hash code
1258     */
1259    @Override
1260    public int hashCode() {
1261        return date.hashCode() ^ offset.hashCode();
1262    }
1263
1264    //-----------------------------------------------------------------------
1265    /**
1266     * Outputs this date as a {@code String}, such as {@code 2007-12-03+01:00}.
1267     * <p>
1268     * The output will be in the ISO-8601 format {@code yyyy-MM-ddXXXXX}.
1269     *
1270     * @return a string representation of this date, not null
1271     */
1272    @Override
1273    public String toString() {
1274        return date.toString() + offset.toString();
1275    }
1276
1277    /**
1278     * Outputs this date as a {@code String} using the formatter.
1279     * <p>
1280     * This date will be passed to the formatter
1281     * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
1282     *
1283     * @param formatter  the formatter to use, not null
1284     * @return the formatted date string, not null
1285     * @throws DateTimeException if an error occurs during printing
1286     */
1287    public String toString(DateTimeFormatter formatter) {
1288        Objects.requireNonNull(formatter, "formatter");
1289        return formatter.print(this);
1290    }
1291
1292    //-----------------------------------------------------------------------
1293    private Object writeReplace() {
1294        return new Ser(Ser.OFFSET_DATE_TYPE, this);
1295    }
1296
1297    /**
1298     * Defend against malicious streams.
1299     * @return never
1300     * @throws InvalidObjectException always
1301     */
1302    private Object readResolve() throws ObjectStreamException {
1303        throw new InvalidObjectException("Deserialization via serialization delegate");
1304    }
1305
1306    void writeExternal(DataOutput out) throws IOException {
1307        date.writeExternal(out);
1308        offset.writeExternal(out);
1309    }
1310
1311    static OffsetDate readExternal(DataInput in) throws IOException {
1312        LocalDate date = LocalDate.readExternal(in);
1313        ZoneOffset offset = ZoneOffset.readExternal(in);
1314        return OffsetDate.of(date, offset);
1315    }
1316
1317}