net.time4j.engine.TimeSpan Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2015 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (TimeSpan.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 .
* -----------------------------------------------------------------------
*/
package net.time4j.engine;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.List;
/**
* Represents a common time span with an associated sign and
* a sequence of time units and related amounts.
*
* @param generic type of time unit
* @author Meno Hochschild
*/
/*[deutsch]
* Repräsentiert eine allgemeine vorzeichenbehaftete Zeitspannem
* in mehreren Zeiteinheiten mit deren zugeordneten Beträgen.
*
* @param generic type of time unit
* @author Meno Hochschild
*/
public interface TimeSpan {
//~ Methoden ----------------------------------------------------------
/**
* Yields all containted time span items with amount and unit in
* the order from largest to smallest time units.
*
* @return unmodifiable list sorted by precision of units in ascending
* order where every time unit exists at most once
*/
/*[deutsch]
* Liefert alle enthaltenen Zeitspannenelemente mit Einheit und Betrag
* in der Reihenfolge von den größten zu den kleinsten und
* genauesten Zeiteinheiten.
*
* @return unmodifiable list sorted by precision of units in ascending
* order where every time unit exists at most once
*/
List- > getTotalLength();
/**
*
Queries if given time unit is part of this time span.
*
* By default the implementation uses following expression:
*
*
* for (Item<?> item : getTotalLength()) {
* if (item.getUnit().equals(unit)) {
* return (item.getAmount() > 0);
* }
* }
* return false;
*
*
* @param unit time unit to be asked (optional)
* @return {@code true} if exists else {@code false}
* @see #getPartialAmount(Object) getPartialAmount(U)
*/
/*[deutsch]
* Ist die angegebene Zeiteinheit in dieser Zeitspanne enthalten?
*
* Standardmäßig entspricht die konkrete
* Implementierung folgendem Ausdruck:
*
*
* for (Item<?> item : getTotalLength()) {
* if (item.getUnit().equals(unit)) {
* return (item.getAmount() > 0);
* }
* }
* return false;
*
*
* @param unit time unit to be asked (optional)
* @return {@code true} if exists else {@code false}
* @see #getPartialAmount(Object) getPartialAmount(U)
*/
boolean contains(U unit);
/**
* Yields the partial amount associated with given time unit.
*
* The method returns {@code 0} if this time span does not contain
* given time unit. In order to get the total length/amount of this
* time span users have to evaluate the method {@link #getTotalLength()}
* instead.
*
* @param unit time unit (optional)
* @return amount as part of time span ({@code >= 0})
*/
/*[deutsch]
* Liefert den Teilbetrag zur angegebenen Einheit als Absolutwert.
*
* Die Methode liefert {@code 0}, wenn die Zeiteinheit nicht enthalten
* ist. Um den Gesamtwert der Zeitspanne zu bekommen, ist in der Regel
* nicht diese Methode, sondern {@link #getTotalLength()} auszuwerten.
*
* @param unit time unit (optional)
* @return amount as part of time span ({@code >= 0})
*/
long getPartialAmount(U unit);
/**
* Queries if this time span is negative.
*
* A negative time span relates to the subtraction of two time
* points where first one is after second one. The partial amounts
* of every time span are never negative. Hence this attribute is not
* associated with the partial amounts but only with the time span
* itself.
*
* Note: An empty time span itself is never negative in agreement
* with the mathematical relation {@code (-1) * 0 = 0}.
*
* @return {@code true} if negative and not empty else {@code false}
*/
/*[deutsch]
* Ist diese Zeitspanne negativ?
*
* Der Begriff der negativen Zeitspanne bezieht sich auf die Subtraktion
* zweier Zeitpunkte, von denen der erste vor dem zweiten liegt. Die
* einzelnen Beträge der Zeitspanne sind nie negativ. Dieses Attribut
* ist daher nicht mit den einzelnen Beträgen assoziiert, sondern
* bezieht sich nur auf die Zeitspanne insgesamt.
*
* Notiz: Eine leere Zeitspanne ist selbst niemals negativ in
* Übereinstimmung mit der mathematischen Relation
* {@code (-1) * 0 = 0}.
*
* @return {@code true} if negative and not empty else {@code false}
*/
boolean isNegative();
/**
* Queries if this time span is positive.
*
* A time span is positive if it is neither empty nor negative.
*
* @return {@code true} if positive and not empty else {@code false}
* @see #isEmpty()
* @see #isNegative()
*/
/*[deutsch]
* Ist diese Zeitspanne positiv?
*
* Eine Zeitspanne ist genau dann positiv, wenn sie weder leer noch
* negativ ist.
*
* @return {@code true} if positive and not empty else {@code false}
* @see #isEmpty()
* @see #isNegative()
*/
boolean isPositive();
/**
* Queries if this time span is empty.
*
* Per definition an empty time span has no items with a partial
* amount different from {@code 0}.
*
* @return {@code true} if empty else {@code false}
*/
/*[deutsch]
* Liegt eine leere Zeitspanne vor?
*
* Per Definition hat eine leere Zeitspanne keine Elemente mit
* einem von {@code 0} verschiedenen Teilbetrag.
*
* @return {@code true} if empty else {@code false}
*/
boolean isEmpty();
/**
* Adds this time span to given time point.
*
* Is equivalent to the expression {@link TimePoint#plus(TimeSpan)
* time.plus(this)}. Due to better readability usage of the
* {@code TimePoint}-method is recommended. Implementations are
* required to document the used algorithm in detailed manner.
*
* @param generic type of time point
* @param time reference time point to add this time span to
* @return new time point as result of addition
* @see #subtractFrom(TimePoint)
*/
/*[deutsch]
* Addiert diese Zeitspanne zum angegebenen Zeitpunkt.
*
* Entspricht dem Ausdruck {@link TimePoint#plus(TimeSpan)
* time.plus(this)}. Aus Gründen des besseren Lesestils empfiehlt
* sich jedoch meistens die Verwendung der {@code TimePoint}-Methode.
* Implementierungen müssen den verwendeten Algorithmus genau
* dokumentieren.
*
* @param generic type of time point
* @param time reference time point to add this time span to
* @return new time point as result of addition
* @see #subtractFrom(TimePoint)
*/
> T addTo(T time);
/**
* Subtracts this time span from given time point.
*
* Is equivalent to the expression {@link TimePoint#minus(TimeSpan)
* time.minus(this)}. Due to better readability usage of the
* {@code TimePoint}-method is recommended. Implementations are
* required to document the used algorithm in detailed manner.
*
* @param generic type of time point
* @param time reference time point to subtract this time span from
* @return new time point as result of subtraction
* @see #addTo(TimePoint)
*/
/*[deutsch]
* Subtrahiert diese Zeitspanne vom angegebenen Zeitpunkt.
*
* Entspricht dem Ausdruck {@link TimePoint#minus(TimeSpan)
* time.minus(this)}. Aus Gründen des besseren Lesestils empfiehlt
* sich jedoch meistens die Verwendung der {@code TimePoint}-Methode.
* Implementierungen müssen den verwendeten Algorithmus genau
* dokumentieren.
*
* @param generic type of time point
* @param time reference time point to subtract this time span from
* @return new time point as result of subtraction
* @see #addTo(TimePoint)
*/
> T subtractFrom(T time);
//~ Innere Klassen ----------------------------------------------------
/**
* Represents a single item of a time span which is based on only one
* time unit and has a non-negative amount.
*
* @param type of time unit
* @doctags.concurrency
*/
/*[deutsch]
* Repräsentiert ein atomares Element einer Zeitspanne, das auf nur
* einer Zeiteinheit beruht und einen nicht-negativen Betrag hat.
*
* @param type of time unit
* @doctags.concurrency
*/
public static final class Item
implements Serializable {
//~ Statische Felder/Initialisierungen ----------------------------
private static final long serialVersionUID = 1564804888291509484L;
//~ Instanzvariablen ----------------------------------------------
/**
* @serial time unit
*/
/*[deutsch]
* @serial Zeiteinheit
*/
private final U unit;
/**
* @serial amount associated with a time unit {@code > 0}
*/
/*[deutsch]
* @serial mit der Zeiteinheit assoziierter Betrag {@code > 0}
*/
private final long amount;
//~ Konstruktoren -------------------------------------------------
private Item(
long amount,
U unit
) {
super();
if (unit == null) {
throw new NullPointerException("Missing chronological unit.");
} else if (amount < 0) {
throw new IllegalArgumentException(
"Temporal amount must be positive or zero: " + amount);
}
this.amount = amount;
this.unit = unit;
}
//~ Methoden ------------------------------------------------------
/**
* Creates a new time span item.
*
* @param type of time unit
* @param amount amount in units {@code >= 0}
* @param unit time unit
* @return new time span item
* @throws IllegalArgumentException if amount is negative
*/
/*[deutsch]
* Konstruiert ein neues Zeitspannenelement.
*
* @param type of time unit
* @param amount amount in units {@code >= 0}
* @param unit time unit
* @return new time span item
* @throws IllegalArgumentException if amount is negative
*/
public static Item of(
long amount,
U unit
) {
return new Item(amount, unit);
}
/**
* Yields the non-negative amount.
*
* @return amount in units ({@code >= 0})
*/
/*[deutsch]
* Liefert den nicht-negativen Betrag.
*
* @return amount in units ({@code >= 0})
*/
public long getAmount() {
return this.amount;
}
/**
* Yields the time unit.
*
* @return time unit
*/
/*[deutsch]
* Liefert die Zeiteinheit.
*
* @return time unit
*/
public U getUnit() {
return this.unit;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof Item) {
Item> that = Item.class.cast(obj);
return (
(this.amount == that.amount)
&& this.unit.equals(that.unit)
);
} else {
return false;
}
}
@Override
public int hashCode() {
int hash = this.unit.hashCode();
hash = 29 * hash + (int) (this.amount ^ (this.amount >>> 32));
return hash;
}
/**
* Provides a canonical representation in the format
* 'P' amount '{' unit '}', for example "P4{YEARS}".
*
* @return String
*/
/*[deutsch]
* Liefert eine kanonische Darstellung im Format
* 'P' amount '{' unit '}', zum Beispiel "P4{YEARS}".
*
* @return String
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('P');
sb.append(this.amount);
sb.append('{');
sb.append(this.unit);
sb.append('}');
return sb.toString();
}
/**
* @serialData Checks the consistency.
* @param in object input stream
* @throws InvalidObjectException if the state is inconsistent
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
if (
(this.unit == null)
|| (this.amount < 0)
) {
throw new InvalidObjectException("Inconsistent state.");
}
}
}
}