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.jdk8;
033
034import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY;
035import static org.threeten.bp.temporal.ChronoField.NANO_OF_DAY;
036import static org.threeten.bp.temporal.ChronoUnit.NANOS;
037
038import java.util.Objects;
039
040import org.threeten.bp.Instant;
041import org.threeten.bp.ZoneOffset;
042import org.threeten.bp.format.DateTimeFormatter;
043import org.threeten.bp.temporal.Chrono;
044import org.threeten.bp.temporal.ChronoLocalDateTime;
045import org.threeten.bp.temporal.Temporal;
046import org.threeten.bp.temporal.TemporalAdder;
047import org.threeten.bp.temporal.TemporalAdjuster;
048import org.threeten.bp.temporal.TemporalQueries;
049import org.threeten.bp.temporal.TemporalQuery;
050import org.threeten.bp.temporal.TemporalSubtractor;
051import org.threeten.bp.temporal.TemporalUnit;
052
053/**
054 * A temporary class providing implementations that will become default interface
055 * methods once integrated into JDK 8.
056 *
057 * @param <C> the chronology of this date-time
058 */
059public abstract class DefaultInterfaceChronoLocalDateTime<C extends Chrono<C>>
060        extends DefaultInterfaceTemporal
061        implements ChronoLocalDateTime<C> {
062
063    @Override
064    public ChronoLocalDateTime<C> with(TemporalAdjuster adjuster) {
065        return getDate().getChrono().ensureChronoLocalDateTime(super.with(adjuster));
066    }
067
068    @Override
069    public ChronoLocalDateTime<C> plus(TemporalAdder adjuster) {
070        return getDate().getChrono().ensureChronoLocalDateTime(super.plus(adjuster));
071    }
072
073    @Override
074    public ChronoLocalDateTime<C> minus(TemporalSubtractor adjuster) {
075        return getDate().getChrono().ensureChronoLocalDateTime(super.minus(adjuster));
076    }
077
078    @Override
079    public ChronoLocalDateTime<C> minus(long amountToSubtract, TemporalUnit unit) {
080        return getDate().getChrono().ensureChronoLocalDateTime(super.minus(amountToSubtract, unit));
081    }
082
083    //-------------------------------------------------------------------------
084    @Override
085    public Temporal adjustInto(Temporal temporal) {
086        return temporal
087                .with(EPOCH_DAY, getDate().toEpochDay())
088                .with(NANO_OF_DAY, getTime().toNanoOfDay());
089    }
090
091    @SuppressWarnings("unchecked")
092    @Override
093    public <R> R query(TemporalQuery<R> query) {
094        if (query == TemporalQueries.chrono()) {
095            return (R) getDate().getChrono();
096        } else if (query == TemporalQueries.precision()) {
097            return (R) NANOS;
098        }
099        return super.query(query);
100    }
101
102    //-----------------------------------------------------------------------
103    @Override
104    public Instant toInstant(ZoneOffset offset) {
105        return Instant.ofEpochSecond(toEpochSecond(offset), getTime().getNano());
106    }
107
108    @Override
109    public long toEpochSecond(ZoneOffset offset) {
110        Objects.requireNonNull(offset, "offset");
111        long epochDay = getDate().toEpochDay();
112        long secs = epochDay * 86400 + getTime().toSecondOfDay();
113        secs -= offset.getTotalSeconds();
114        return secs;
115    }
116
117    //-----------------------------------------------------------------------
118    @Override
119    public int compareTo(ChronoLocalDateTime<?> other) {
120        int cmp = getDate().compareTo(other.getDate());
121        if (cmp == 0) {
122            cmp = getTime().compareTo(other.getTime());
123            if (cmp == 0) {
124                cmp = getDate().getChrono().compareTo(other.getDate().getChrono());
125            }
126        }
127        return cmp;
128    }
129
130    @Override
131    public boolean isAfter(ChronoLocalDateTime<?> other) {
132        long thisEpDay = this.getDate().toEpochDay();
133        long otherEpDay = other.getDate().toEpochDay();
134        return thisEpDay > otherEpDay ||
135            (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() > other.getTime().toNanoOfDay());
136    }
137
138    @Override
139    public boolean isBefore(ChronoLocalDateTime<?> other) {
140        long thisEpDay = this.getDate().toEpochDay();
141        long otherEpDay = other.getDate().toEpochDay();
142        return thisEpDay < otherEpDay ||
143            (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() < other.getTime().toNanoOfDay());
144    }
145
146    @Override
147    public boolean isEqual(ChronoLocalDateTime<?> other) {
148        // Do the time check first, it is cheaper than computing EPOCH day.
149        return this.getTime().toNanoOfDay() == other.getTime().toNanoOfDay() &&
150               this.getDate().toEpochDay() == other.getDate().toEpochDay();
151    }
152
153    //-------------------------------------------------------------------------
154    @Override
155    public boolean equals(Object obj) {
156        if (this == obj) {
157            return true;
158        }
159        if (obj instanceof ChronoLocalDateTime) {
160            return compareTo((ChronoLocalDateTime<?>) obj) == 0;
161        }
162        return false;
163    }
164
165    @Override
166    public int hashCode() {
167        return getDate().hashCode() ^ getTime().hashCode();
168    }
169
170    //-------------------------------------------------------------------------
171    @Override
172    public String toString() {
173        return getDate().toString() + 'T' + getTime().toString();
174    }
175
176    @Override
177    public String toString(DateTimeFormatter formatter) {
178        Objects.requireNonNull(formatter, "formatter");
179        return formatter.print(this);
180    }
181
182}