All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.time4j.engine.TimePoint Maven / Gradle / Ivy

There is a newer version: 4.38
Show newest version
/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2015 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (TimePoint.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 net.time4j.base.MathUtils;

import java.io.Serializable;


/**
 * 

Represents an immutable time point along a time axis which is directed * into the future.

* *

Display and change chronological element values

* *

The time point consists of chronological elements. This base class * delegates the time arithmetic to the associated time axis respective to * the underlying rules of elements and units. However, any concrete subclass * is required to define the state and reflect it in all {@code get()}-methods * and also to specify the serialization behaviour.

* *

Element values can only be changed by creating a new immutable copy * of the original instance. This is done via all {@code with()}-methods.

* *

Time axis

* *

If the referenced time axis is the UTC-timeline (that is a time point * is defined relative to the start of UTC epoch - see * package summary) then any implementation * must also implement the interface {@link net.time4j.scale.UniversalTime}. * In every other case we have a local time axis. All time units are to be * defined referencing the time axis. For example, second units are interpreted * as local UT1-seconds on a local timestamp but on a {@code UniversalTime} * before 1972 as global UT1-seconds and after 1972 as atomic SI-seconds. * Hence Time4J has even defined different second units in the main package. * Applications should therefore take much care if they transform a duration * from one time axis to another one.

* *

Sorting

* *

Unless explicitly stated otherwise sorting of time points is always * in strict temporal order and consistent with {@code equals()}. In case * of doubt the documentation of the subclass is leading. Alternatively, * subclasses are free to implement the interface {@code Temporal} to * enable a temporal order.

* *

Addition (or subtraction) of a time span to a time point

* *

These operations are performed by all {@code plus()}- and {@code minus()}- * methods. A time span can either be a single time unit, or it consists of * several time units.

* *

If given time unit does not have a fixed length (for example months) * then the result of an addition can deviate from the expected element * value to be considered. In case of multiple additions care is required. * In case of doubt the original value should be saved for a later addition. * Example with additions of months in one or two steps (pseudo-code):

* *
    *
  • [2011-08-31] + [P1M] = [2011-09-30]
  • *
  • [2011-09-30] + [P1M] = [2011-10-30]
  • *
  • [2011-08-31] + [P2M] = [2011-10-31]
  • *
* *

Difference of time points

* *

The difference of time points results in a time span. The result can * either be expressed in one time unit only, or in multiple units which * represent the base unit of associated chronological element. In latter * case users have to define a metric, too.

* *

Implementation notes

* *
    *
  • All subclasses must be final und immutable.
  • *
  • Documentation of supported and registered elements is required.
  • *
  • For a suitable choice of the type U of time units it should be * noted that the time units must correspond to the internal state of * a time point because otherwise the calculation of a time span between * two time points cannot be complete. For example it would be a mistake * to allow milliseconds for a time point which even has nanoseconds.
  • *
  • The natural order should be consistent with {@code equals()}.
  • *
* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @author Meno Hochschild * @serial exclude * @see Chronology * @see TimeAxis * @see Temporal */ /*[deutsch] *

Repräsentiert einen unveränderlichen Zeitpunkt auf einer in * die Zukunft gerichteten Zeitachse.

* *

Chronologische Elementwerte anzeigen und ändern

* *

Der Zeitwert setzt sich aus chronologischen Elementen zusammen. Diese * abstrakte Basisklasse delegiert die Zeitrechnung immer an die zugehörige * Zeitachse bzw. genauer an die ihr zugeordneten Regeln der Elemente und * Zeiteinheiten, muß aber selbst den Zustand definieren, in den * {@code get()}-Methoden den Zustand reflektieren und auch das * Serialisierungsverhalten festlegen.

* *

Da alle konkreten Implementierungen immutable sind und sein * müssen, sind Elementwerte nur dadurch änderbar, daß jeweils * eine neue Instanz mit geänderten Elementwerten erzeugt wird. Das wird * unter anderem von allen {@code with()}-Methoden geleistet.

* *

Zeitstrahl

* *

Ist die referenzierte Zeitachse die UTC-Weltzeitlinie, wenn also * ein Zeitpunkt dann relativ zum Beginn der UTC-Epoche liegt (siehe * Paketbeschreibung), dann muß eine * Implementierung auch das Interface {@link net.time4j.scale.UniversalTime} * implementieren. Sonst liegt eine lokale Zeitachse vor. Alle Zeiteinheiten * sind bezüglich der Zeitachse zu interpretieren. Zum Beispiel gelten * Sekundenzeiteinheiten auf einem lokalen Zeitstempel als lokale UT1-Sekunden * mit externem Zeitzonenkontext, auf einem {@code UniversalTime}-Objekt * vor 1972 als globale UT1-Sekunden und nach 1972 als atomare SI-Sekunden. * Deshalb sollten Anwendungen besondere Vorsicht walten lassen, wenn eine * Dauer von einer Zeitachse auf eine andere Zeitachse übertragen wird.

* *

Sortierung

* *

Wenn nicht ausdrücklich anders dokumentiert, wird die Sortierung * von Zeitpunkten immer rein zeitlich definiert und konsistent mit * {@code equals()} sein. Im Zweifelsfall ist die Dokumentation der * konkreten Subklasse maßgeblich. Alternativ können Subklassen * auch das Interface {@code Temporal} implementieren, um eine rein * zeitliche Ordnung zu ermöglichen.

* *

Addition (oder Subtraktion) einer Zeitspanne zu einem Zeitpunkt

* *

Diese Operationen werden von allen {@code plus()}- und {@code minus()}- * Methoden geleistet. Eine Zeitspanne kann entweder nur eine einzelne * Zeiteinheit sein oder ist aus mehreren Zeiteinheiten zusammengesetzt.

* *

Wenn die angegebene Zeiteinheit bzw. Genauigkeit keine konstante * Länge definiert (zum Beispiel haben Monate in Tagen ausgedrückt * im allgemeinen unterschiedliche Längen), dann kann das Ergebnis * einer Addition im Hinblick auf den erwarteten Elementwert abweichen. Bei * mehrfachen Additionen hintereinander ist Vorsicht angebracht, im * Zweifelsfall sollte der Originalwert für eine spätere Addition * gespeichert werden. Beispiel mit Additionen von Monaten in einem oder in * zwei Schritten (Pseudo-Code):

* *
    *
  • [2011-08-31] + [P1M] = [2011-09-30]
  • *
  • [2011-09-30] + [P1M] = [2011-10-30]
  • *
  • [2011-08-31] + [P2M] = [2011-10-31]
  • *
* *

Differenz von Zeitpunkten

* *

Die Differenz von Zeitpunkten resultiert jeweils in einer Zeitspanne. * Das Ergebnis kann entweder in nur einer Zeiteinheit ausgedrückt werden, * oder in mehreren Zeiteinheiten, die jede die Basiseinheit des entsprechenden * chronologischen Elements repräsentieren. In letzterem Fall ist auch * eine Metrik anzugeben.

* *

Implementierungshinweise

* *
    *
  • Alle Subklassen müssen final und immutable * sein.
  • *
  • Es muß dokumentiert werden, welche chronologischen Elemente * unterstützt werden bzw. registriert sind.
  • *
  • Zur Wahl des Zeiteinheitstyps U ist zu beachten, daß die * Zeiteinheiten mit dem internen Zeitwertzustand zusammenpassen müssen, * weil sonst die Berechnung der Zeitspanne zwischen zwei Zeitpunkten nicht * vollständig möglich sein kann. Zum Beispiel wäre es ein * Fehler, wenn die Zeiteinheiten maximal in Millisekunden genau sind, aber * die konkreten Zeitpunkte sogar Nanosekunden enthalten.
  • *
  • Die natürliche Ordnung sollte konsistent mit {@code equals()} * sein.
  • *
* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @author Meno Hochschild * @serial exclude * @see Chronology * @see TimeAxis * @see Temporal */ public abstract class TimePoint> extends ChronoEntity implements Comparable, Serializable { //~ Methoden ---------------------------------------------------------- /** *

Compares two time points preferably by their temporal positions * on the common time axis.

* *

Implementation note: In order to make the natural order consistent * with {@code equals()} the whole state must be taken into account, * with preference for those attributes which define the temporal * position on the time axis.

* * @see #equals(Object) */ /*[deutsch] *

Vergleicht zwei Zeitpunkte bevorzugt nach ihrer Position auf der * gemeinsamen Zeitachse.

* *

Implementierungshinweis: Damit die natürliche Ordnung konsistent * mit {@code equals()} ist, müssen zum Vergleich alle internen * Zustandsattribute herangezogen werden, bevorzugt aber die Attribute, * die die zeitliche Position festlegen.

* * @see #equals(Object) */ @Override public abstract int compareTo(T timePoint); /** *

Adds the given time span to this time point and yields * the result of the addition.

* *

Delegates to {@link TimeSpan#addTo(TimePoint)}.

* * @param timeSpan time span to be added to this instance * @return result of addition as changed copy, this * instance remains unaffected * @throws RuleNotFoundException if any time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #minus(TimeSpan) */ /*[deutsch] *

Addiert die angegebene Zeitspanne zur Bezugszeit und liefert das * Additionsergebnis zurück.

* *

Delegiert an {@link TimeSpan#addTo(TimePoint)}.

* * @param timeSpan time span to be added to this instance * @return result of addition as changed copy, this * instance remains unaffected * @throws RuleNotFoundException if any time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #minus(TimeSpan) */ public T plus(TimeSpan timeSpan) { try { return timeSpan.addTo(this.getContext()); } catch (IllegalArgumentException iae) { ArithmeticException ex = new ArithmeticException( "Result beyond boundaries of time axis."); ex.initCause(iae); throw ex; } } /** *

Subtracts given time span from this time point and yields * the result of subtraction.

* *

Delegiert an {@link TimeSpan#subtractFrom(TimePoint)}.

* * @param timeSpan time span to be subtracted from this instance * @return result of subtraction as changed copy, this * instance remains unaffected * @throws RuleNotFoundException if any time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(TimeSpan) */ /*[deutsch] *

Subtrahiert die angegebene Zeitspanne von der Bezugszeit und * liefert das Subtraktionsergebnis zurück.

* *

Delegiert an {@link TimeSpan#subtractFrom(TimePoint)}.

* * @param timeSpan time span to be subtracted from this instance * @return result of subtraction as changed copy, this * instance remains unaffected * @throws RuleNotFoundException if any time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(TimeSpan) */ public T minus(TimeSpan timeSpan) { try { return timeSpan.subtractFrom(this.getContext()); } catch (IllegalArgumentException iae) { ArithmeticException ex = new ArithmeticException( "Result beyond boundaries of time axis."); ex.initCause(iae); throw ex; } } /** *

Adds given amount in units to this time point and yields the * result of addition.

* *

Similar to {@link #plus(TimeSpan)} but with the difference * that the timespan is only given in one single time unit. Example * in pseudo-code:

* *
    *
  • [2011-05-31].plus(1, <MONTHS>) = [2011-06-30]
  • *
  • [2011-05-31].plus(4, <DAYS>) = [2011-06-04]
  • *
  • [2011-06-04].plus(-4, <DAYS>) = [2011-05-31]
  • *
  • [2010-04-29].plus(397, <DAYS>) = [2011-05-31]
  • *
  • [2010-04-29].plus(13, <MONTHS>) = [2011-05-29]
  • *
  • [2010-04-29].plus(-2, <MONTHS>) = [2010-02-28]
  • *
  • [2010-04-29].plus(1, <YEARS>) = [2011-04-29]
  • *
* * @param amount amount to be added (maybe negative) * @param unit time unit * @return result of addition as changed copy, this instance * remains unaffected * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(TimeSpan) */ /*[deutsch] *

Addiert den angegebenen Betrag der entsprechenden Zeiteinheit * zu dieser Bezugszeit und liefert das Additionsergebnis zurück.

* *

Ähnlich wie {@link #plus(TimeSpan)}, aber mit dem Unterschied, * daß die Zeitspanne in nur einer Zeiteinheit angegeben wird. * Beispiel in Pseudo-Code:

* *
    *
  • [2011-05-31].plus(1, <MONTHS>) = [2011-06-30]
  • *
  • [2011-05-31].plus(4, <DAYS>) = [2011-06-04]
  • *
  • [2011-06-04].plus(-4, <DAYS>) = [2011-05-31]
  • *
  • [2010-04-29].plus(397, <DAYS>) = [2011-05-31]
  • *
  • [2010-04-29].plus(13, <MONTHS>) = [2011-05-29]
  • *
  • [2010-04-29].plus(-2, <MONTHS>) = [2010-02-28]
  • *
  • [2010-04-29].plus(1, <YEARS>) = [2011-04-29]
  • *
* * @param amount amount to be added (maybe negative) * @param unit time unit * @return result of addition as changed copy, this instance * remains unaffected * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(TimeSpan) */ public T plus( long amount, U unit ) { if (amount == 0) { return this.getContext(); } try { return this.getRule(unit).addTo(this.getContext(), amount); } catch (IllegalArgumentException iae) { ArithmeticException ex = new ArithmeticException( "Result beyond boundaries of time axis."); ex.initCause(iae); throw ex; } } /** *

Subtracts given amount in units from this time point and * yields the result of subtraction.

* * @param amount amount to be subtracted (maybe negative) * @param unit time unit * @return result of subtraction as changed copy, this instance * remains unaffected * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, U) */ /*[deutsch] *

Subtrahiert den angegebenen Betrag der entsprechenden Zeiteinheit * von dieser Bezugszeit und liefert das Ergebnis zurück.

* * @param amount amount to be subtracted (maybe negative) * @param unit time unit * @return result of subtraction as changed copy, this instance * remains unaffected * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #plus(long, Object) plus(long, U) */ public T minus( long amount, U unit ) { return this.plus(MathUtils.safeNegate(amount), unit); } /** *

Calculates the (most normalized) time span between this time point * and given end time point using the given metric.

* * @param

generic type of time span result * @param end end time point * @param metric temporal distance metric * @return difference between this and given end time point * expressed as time span * @throws ArithmeticException in case of numerical overflow */ /*[deutsch] *

Ermittelt die (meist normalisierte) Zeitspanne zwischen dieser * Bezugszeit und dem Endzeitpunkt in der angegebenen Metrik.

* * @param

generic type of time span result * @param end end time point * @param metric temporal distance metric * @return difference between this and given end time point * expressed as time span * @throws ArithmeticException in case of numerical overflow */ public

P until( T end, TimeMetric metric ) { return metric.between(this.getContext(), end); } /** *

Calculates the temporal distance between this time point and * given end time point in only one time unit.

* *

Similar to {@link #until(TimePoint, TimeMetric)} but with the * difference that the time span is onyl calculated in one time unit * as long-primitive. In many cases a remainder of subtraction will * be left if given unit is not the smallest possible unit. Time points * whose element values differ less than one base unit will be * considered as equal. Examples in pseudo-code:

* *
    *
  • [2011-05-31].until([2011-06-04], <MONTHS>) = 0
  • *
  • [2011-05-31].until([2011-06-04], <DAYS>) = 4
  • *
  • [2011-06-04].until([2011-05-31], <DAYS>) = -4
  • *
  • [2010-04-29].until([2011-05-31], <DAYS>) = 397
  • *
  • [2010-04-29].until([2011-05-31], <MONTHS>) = 13
  • *
  • [2010-04-29].until([2011-05-31], <YEARS>) = 1
  • *
  • [2010-05-31].until([2011-05-31], <YEARS>) = 1
  • *
  • [2010-06-01].until([2011-05-31], <YEARS>) = 0
  • *
* * @param end end time point * @param unit time unit * @return difference between this and given end time point * as count of given time unit * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #until(TimePoint, TimeMetric) */ /*[deutsch] *

Ermittelt den zeitlichen Abstand zwischen dieser Bezugszeit und dem * angegebenen Zeitpunkt nur in einer Zeiteinheit zurück.

* *

Ähnlich wie {@link #until(TimePoint, TimeMetric)}, aber mit * dem Unterschied, daß die Zeitspanne nur in einer Zeiteinheit als * long-Primitive ermittelt wird. Es wird meist ein Subtraktionsrest * verbleiben, wenn es sich nicht um die kleinstmögliche bzw. genaueste * Zeiteinheit handelt. Zeitpunkte, deren Elementwerte sich um weniger als * eine Einheit unterscheiden, gelten als gleich. Beispiele in * Pseudo-Code:

* *
    *
  • [2011-05-31].until([2011-06-04], <MONTHS>) = 0
  • *
  • [2011-05-31].until([2011-06-04], <DAYS>) = 4
  • *
  • [2011-06-04].until([2011-05-31], <DAYS>) = -4
  • *
  • [2010-04-29].until([2011-05-31], <DAYS>) = 397
  • *
  • [2010-04-29].until([2011-05-31], <MONTHS>) = 13
  • *
  • [2010-04-29].until([2011-05-31], <YEARS>) = 1
  • *
  • [2010-05-31].until([2011-05-31], <YEARS>) = 1
  • *
  • [2010-06-01].until([2011-05-31], <YEARS>) = 0
  • *
* * @param end end time point * @param unit time unit * @return difference between this and given end time point * as count of given time unit * @throws RuleNotFoundException if given time unit is not registered * and does also not implement {@link BasicUnit} to yield * a suitable unit rule for the underlying time axis * @throws ArithmeticException in case of numerical overflow * @see #until(TimePoint, TimeMetric) */ public long until( T end, U unit ) { return this.getRule(unit).between(this.getContext(), end); } /** *

Determines the minimum of both time points.

* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @param t1 first time point * @param t2 second time point * @return minimum of t1 and t2 */ /*[deutsch] *

Bestimmt das Minimum der beiden Zeitpunkte.

* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @param t1 first time point * @param t2 second time point * @return minimum of t1 and t2 */ public static > T min( T t1, T t2 ) { return (t1.compareTo(t2) > 0) ? t2 : t1; } /** *

Determines the maximum of both time points.

* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @param t1 first time point * @param t2 second time point * @return maximum of t1 and t2 */ /*[deutsch] *

Bestimmt das Maximum der beiden Zeitpunkte.

* * @param generic type of time units compatible to {@link ChronoUnit} * @param generic type of self reference * @param t1 first time point * @param t2 second time point * @return maximum of t1 and t2 */ public static > T max( T t1, T t2 ) { return (t1.compareTo(t2) > 0) ? t1 : t2; } /** *

Compares the whole state of this instance with given object.

* *

Implementations will usually define their state only * based on the temporal position on the time axis because this * is the most intuitive approach. Exceptions from this rule should * be explicitly documented and reasoned.

* * @see #compareTo(TimePoint) */ /*[deutsch] *

Vergleicht den gesamten Zustand dieser Instanz mit dem des * angegebenen Objekts.

* *

Implementierungen werden üblicherweise ihren Zustand nur * auf Basis der zeitlichen Position definieren, da dies am ehesten * der Erwartungshaltung der Anwender entspricht. Ausnahmen sind * explizit zu dokumentieren und zu begründen.

* * @see #compareTo(TimePoint) */ @Override public abstract boolean equals(Object obj); /** *

Subclasses must redefine this method corresponding to the * behaviour of {@code equals()}.

*/ /*[deutsch] *

Subklassen müssen diese Methode passend zum Verhalten * von {@code equals()} redefinieren.

*/ @Override public abstract int hashCode(); /** *

Provides a complete textual representation of the state of * this time point.

* *

The textual description often follows the conventions of ISO-8601. * Usually the description starts with the chronological informations * which are coarse-grained and ends with those ones which are * fine-grained (for example the ISO-notation YYYY-MM-DD).

*/ /*[deutsch] *

Liefert eine vollständige Beschreibung des Zustands dieses * Zeitpunkts.

* *

Die textuelle Beschreibung folgt oft den Konventionen des * ISO-8601-Standards, indem zuerst die groben und dann die feineren * chronologischen Informationen mit höherer Detailgenauigkeit folgen * (zum Beispiel die ISO-Notation YYYY-MM-DD).

*/ @Override public abstract String toString(); /** *

Returns the assigned time axis which contains all necessary * chronological rules.

* *

Concrete subclasses must create in a static initializer a * time axis by help of {@code TimeAxis.Builder}, keep it as static * constant and make it available here. Using the procedure guarantees * that a basic set of registered elements, units and rules will be * installed.

* * @return chronological system as time axis (never {@code null}) * @see TimeAxis.Builder */ /*[deutsch] *

Liefert die zugehörige Zeitachse, die alle notwendigen * chronologischen Regeln enthält.

* *

Konkrete Subklassen müssen in einem static initializer * mit Hilfe von {@code TimeAxis.Builder} eine Zeitachse bauen, in * einer eigenen Konstanten halten und hier verfügbar machen. * Über dieses Verfahren wird zugleich ein Basissatz von Elementen, * Zeiteinheiten und chronologischen Regeln vorinstalliert.

* * @return chronological system as time axis (never {@code null}) * @see TimeAxis.Builder */ @Override protected abstract TimeAxis getChronology(); // Einheitsregel private UnitRule getRule(U unit) { return this.getChronology().getRule(unit); } }