/* * ----------------------------------------------------------------------- * Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/> * ----------------------------------------------------------------------- * This file (FixedCalendarInterval.java) is part of project Time4J. * * Time4J is free software: You can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * Time4J is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Time4J. If not, see <http://www.gnu.org/licenses/>. * ----------------------------------------------------------------------- */ package net.time4j.range; import net.time4j.CalendarUnit; import net.time4j.PlainDate; import net.time4j.engine.ChronoEntity; import java.io.Serializable; /** * <p>Represents a fixed calendar interval. </p> * * @author Meno Hochschild * @since 3.21/4.17 */ /*[deutsch] * <p>Repräsentiert ein festes Kalenderintervall. </p> * * @author Meno Hochschild * @since 3.21/4.17 */ public abstract class FixedCalendarInterval<T extends FixedCalendarInterval<T>> extends ChronoEntity<T> implements Comparable<T>, ChronoInterval<PlainDate>, Iterable<PlainDate>, Serializable { //~ Konstruktoren ----------------------------------------------------- // only for Time4J-subclasses FixedCalendarInterval() { super(); } //~ Methoden ---------------------------------------------------------- /** * <p>A calendar interval is always finite. </p> * * @return {@code true} */ /*[deutsch] * <p>Ein Kalenderintervall ist immer endlich. </p> * * @return {@code true} */ @Override public final boolean isFinite() { return true; } /** * <p>A calendar interval is never empty. </p> * * @return {@code false} */ /*[deutsch] * <p>Ein Kalenderintervall ist niemals leer. </p> * * @return {@code false} */ @Override public final boolean isEmpty() { return false; } @Override public boolean contains(ChronoInterval<PlainDate> other) { if (!other.isFinite()) { return false; } PlainDate startA = this.getStart().getTemporal(); PlainDate startB = other.getStart().getTemporal(); if (other.getStart().isOpen()) { if (startB.equals(PlainDate.axis().getMaximum())) { return false; } startB = startB.plus(1, CalendarUnit.DAYS); } if (startA.isAfter(startB)) { return false; } PlainDate endA = this.getEnd().getTemporal(); PlainDate endB = other.getEnd().getTemporal(); if (other.getEnd().isOpen()) { if (startB.isSimultaneous(endB)) { return !startB.isAfter(endA); } else if (endB.equals(PlainDate.axis().getMinimum())) { return false; } endB = endB.minus(1, CalendarUnit.DAYS); } return !endA.isBefore(endB); } @Override public boolean isBefore(ChronoInterval<PlainDate> other) { if (other.getStart().isInfinite()) { return false; } PlainDate endA = this.getEnd().getTemporal(); PlainDate startB = other.getStart().getTemporal(); if (other.getStart().isOpen()) { if (startB.equals(PlainDate.axis().getMaximum())) { return true; } startB = startB.plus(1, CalendarUnit.DAYS); } return endA.isBefore(startB); } @Override public boolean abuts(ChronoInterval<PlainDate> other) { if (other.isEmpty()) { return false; } PlainDate startA = this.getStart().getTemporal(); PlainDate startB = other.getStart().getTemporal(); if ((startB != null) && other.getStart().isOpen()) { startB = startB.plus(1, CalendarUnit.DAYS); } PlainDate endA = this.getEnd().getTemporal(); PlainDate endB = other.getEnd().getTemporal(); try { endA = endA.plus(1, CalendarUnit.DAYS); } catch (ArithmeticException ex) { return ((endB != null) && startA.isSimultaneous(endB)); } try { if (endB == null) { return ((startB != null) && endA.isSimultaneous(startB)); } else if (other.getEnd().isClosed()) { endB = endB.plus(1, CalendarUnit.DAYS); } } catch (ArithmeticException ex) { return ((startB != null) && endA.isSimultaneous(startB)); } if (startB == null) { return startA.isSimultaneous(endB); } else if (endB == null) { return endA.isSimultaneous(startB); } return (endA.isSimultaneous(startB) ^ startA.isSimultaneous(endB)); } /** * <p>Queries if this object and given object have the same position * on the time axis. </p> * * @param other object this instance is compared to * @return {@code true} if this instance is temporally equal to {@code other} else {@code false} */ /*[deutsch] * <p>Sind dieses Objekt und das angegebene Argument zeitlich gleich? </p> * * @param other object this instance is compared to * @return {@code true} if this instance is temporally equal to {@code other} else {@code false} */ public boolean isSimultaneous(T other) { return (this.compareTo(other) == 0); } /** * <p>Converts this fixed interval to a date interval with flexible boundaries which can participate in * any kind of interval boundary manipulations. </p> * * @return DateInterval */ /*[deutsch] * <p>Konvertiert dieses feste Intervall zu einem Intervall mit flexiblen Grenzen, die * Gegenstand von beliebigen Manipulationen sein können. </p> * * @return DateInterval */ public DateInterval toFlexInterval() { return new DateInterval(this.getStart(), this.getEnd()); } // helper method for toString() in subclasses static void formatYear( StringBuilder sb, int year ) { int value = year; if (value < 0) { sb.append('-'); value = Math.negateExact(year); } if (value >= 10000) { if (year > 0) { sb.append('+'); } } else if (value < 1000) { sb.append('0'); if (value < 100) { sb.append('0'); if (value < 10) { sb.append('0'); } } } sb.append(value); } }