/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild, <http://www.menodata.de/>
* -----------------------------------------------------------------------
* This file (TransitionHistory.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.tz;
import net.time4j.base.GregorianDate;
import net.time4j.base.UnixTime;
import net.time4j.base.WallTime;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
/**
* <p>Keeps all offset transitions and rules of a timezone. </p>
*
* <p>Note: This interface can be considered as stable since version v2.2.
* Preliminary experimental versions of this interface existed since v1.0
* but there was originally not any useable implementation. </p>
*
* @author Meno Hochschild
* @doctags.spec All implementations must be immutable, thread-safe and serializable.
*/
/*[deutsch]
* <p>Hält alle Übergänge und Regeln einer Zeitzone. </p>
*
* <p>Hinweis: Dieses Interface kann als stabil seit Version 2.2 gelten.
* Davor existierten experimentelle Versionen des Interface schon seit v1.0,
* aber es gab ursprünglich keine nutzbare Implementierung. </p>
*
* @author Meno Hochschild
* @doctags.spec All implementations must be immutable, thread-safe and serializable.
*/
public interface TransitionHistory {
//~ Methoden ----------------------------------------------------------
/**
* <p>Return the initial offset no matter if there are any
* transitions defined or not. </p>
*
* <p>If any transition is defined then the initial offset
* is identical to the shift {@code getPreviousOffset()} of
* the first defined transition in history. </p>
*
* @return fixed initial shift in full seconds
*/
/*[deutsch]
* <p>Ermittelt die initiale Verschiebung unabhängig davon, ob es
* Übergänge gibt oder nicht. </p>
*
* <p>Falls es Übergänge gibt, muß die initiale
* Verschiebung mit der Verschiebung {@code getPreviousOffset()}
* des ersten definierten Übergangs identisch sein. </p>
*
* @return fixed initial shift in full seconds
*/
ZonalOffset getInitialOffset();
/**
* <p>Queries the last transition which defines the offset
* for given global timestamp. </p>
*
* <p>For standard use cases, users can use the alternative method
* {@code findStartTransition()} unless performance considerations prohibit
* the usage of class {@code Optional}. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition} or {@code null} if given reference time is before first defined transition
* @see #findStartTransition(UnixTime)
*/
/*[deutsch]
* <p>Ermittelt den letzten Übergang, der die zur angegebenen
* Referenzzeit zugehörige Verschiebung definiert. </p>
*
* <p>Für Standardfälle können Anwender die alternative Methode
* {@code findStartTransition()} verwenden, es sei denn, Performance-Aspekte
* verbieten den Gebrauch der Klasse {@code Optional}. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition} or {@code null} if given reference time is before first defined transition
* @see #findStartTransition(UnixTime)
*/
ZonalTransition getStartTransition(UnixTime ut);
/**
* <p>Returns the conflict transition where given local timestamp
* falls either in a gap or in an overlap on the local timeline. </p>
*
* <p>Note that only the expression {@code localDate.getYear()} is used
* to determine the daylight saving rules to be applied in calculation.
* This is particularly important if there is a wall time of 24:00. Here
* only the date before merging to next day matters, not the date of the
* whole timestamp. </p>
*
* <p>For standard use cases, users can use the alternative method
* {@code findConflictTransition()} unless performance considerations prohibit
* the usage of class {@code Optional}. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return conflict transition on the local time axis for gaps or overlaps else {@code null}
* @see #getValidOffsets(GregorianDate,WallTime)
* @see #findConflictTransition(GregorianDate, WallTime)
*/
/*[deutsch]
* <p>Bestimmt den passenden Übergang, wenn die angegebene lokale
* Zeit in eine Lücke oder eine Überlappung auf dem lokalen
* Zeitstrahl fällt. </p>
*
* <p>Zu beachten: Nur der Ausdruck {@code localDate.getYear()} wird
* in der Ermittlung der passenden DST-Regeln benutzt. Das ist insbesondere
* von Bedeutung, wenn die Uhrzeit 24:00 vorliegt. Hier zählt nur
* das Jahr des angegebenen Datums, nicht das des Zeitstempels, der
* wegen der Uhrzeit evtl. im Folgejahr liegt. </p>
*
* <p>Für Standardfälle können Anwender die alternative Methode
* {@code findConflictTransition()} verwenden, es sei denn, Performance-Aspekte
* verbieten den Gebrauch der Klasse {@code Optional}. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return conflict transition on the local time axis for gaps or overlaps else {@code null}
* @see #getValidOffsets(GregorianDate,WallTime)
* @see #findConflictTransition(GregorianDate, WallTime)
*/
ZonalTransition getConflictTransition(
GregorianDate localDate,
WallTime localTime
);
/**
* <p>Queries the next transition after given global timestamp. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition} or {@code null} if given reference time
* is after any defined transition
* @deprecated Use the equivalent {@link #findNextTransition(UnixTime)}
*/
/*[deutsch]
* <p>Ermittelt den nächsten Übergang nach der angegebenen
* Referenzzeit. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition} or {@code null} if given reference time
* is after any defined transition
* @deprecated Use the equivalent {@link #findNextTransition(UnixTime)}
*/
@Deprecated
ZonalTransition getNextTransition(UnixTime ut);
/**
* <p>Determines the suitable offsets at given local timestamp.. </p>
*
* <p>The offset list is empty if the local timestamp falls in a gap
* on the local timeline. The list has exactly two offsets sorted by size
* if the local timestamp belongs to two different timepoints on the
* POSIX timescale due to an overlap. Otherwise the offset list
* will contain exactly one suitable offset. </p>
*
* <p>Note that only the expression {@code localDate.getYear()} is used
* to determine the daylight saving rules to be applied in calculation.
* This is particularly important if there is a wall time of 24:00. Here
* only the date before merging to next day matters, not the date of the
* whole timestamp. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return unmodifiable list of shifts in full seconds which fits the
* given local time
* @see #findConflictTransition(GregorianDate,WallTime)
*/
/*[deutsch]
* <p>Bestimmt die zur angegebenen lokalen Zeit passenden
* zonalen Verschiebungen. </p>
*
* <p>Die Liste ist leer, wenn die lokale Zeit in eine Lücke auf
* dem lokalen Zeitstrahl fällt. Die Liste hat genau zwei nach
* Größe sortierte Verschiebungen, wenn die lokale Zeit wegen
* einer Überlappung zu zwei verschiedenen Zeitpunkten auf der
* POSIX-Zeitskala gehört. Ansonsten wird die Liste genau eine
* passende Verschiebung enthalten. </p>
*
* <p>Zu beachten: Nur der Ausdruck {@code localDate.getYear()} wird
* in der Ermittlung der passenden DST-Regeln benutzt. Das ist insbesondere
* von Bedeutung, wenn die Uhrzeit 24:00 vorliegt. Hier zählt nur
* das Jahr des angegebenen Datums, nicht das des Zeitstempels, der
* wegen der Uhrzeit evtl. im Folgejahr liegt. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return unmodifiable list of shifts in full seconds which fits the
* given local time
* @see #findConflictTransition(GregorianDate,WallTime)
*/
List<ZonalOffset> getValidOffsets(
GregorianDate localDate,
WallTime localTime
);
/**
* <p>Return the offset transitions from UNIX epoch [1970-01-01T00:00Z]
* until about one year after the current timestamp. </p>
*
* <p>Indeed, a potentially bigger interval is obtainable by
* {@link #getTransitions(UnixTime,UnixTime)}, but earlier or
* later timepoints are usually not reliable. For example the
* wide-spread IANA/Olson-repository is only designed for times
* since UNIX epoch and offers some selected older data to the
* best of our knowledge. Users must be aware that even older
* data can be changed as side effect of data corrections. Generally
* the timezone concept was invented in 19th century. And future
* transitions are even less reliable due to political arbitrariness. </p>
*
* @return unmodifiable list of standard transitions (after 1970-01-01)
* maybe empty
*/
/*[deutsch]
* <p>Bestimmt alle vorhandenen zonalen Übergänge ab der
* UNIX-Epoche [1970-01-01T00:00Z] bis zirka ein Jahr nach dem aktuellen
* heutigen Zeitpunkt. </p>
*
* <p>Zwar kann mittels {@link #getTransitions(UnixTime,UnixTime)}
* auch ein potentiell größeres Intervall abgefragt werden,
* jedoch sind frühere oder spätere Zeitpunkte in aller Regel
* mit großen Unsicherheiten verknüpft. Zum Beispiel ist die
* weithin verwendete IANA/Olson-Zeitzonendatenbank nur für Zeiten
* ab der UNIX-Epoche gedacht und bietet ausgewählte ältere
* Zeitzonendaten lediglich nach bestem Wissen und Gewissen an. Anwender
* müssen beachten, daß sich sogar historische alte Daten
* nachträglich ändern können. Generell existiert das
* Zeitzonenkonzept erst ab ca. dem 19. Jahrhundert. Und in der Zukunft
* liegende Zeitzonenänderungen sind wegen politischer Willkür
* sogar noch unsicherer. </p>
*
* @return unmodifiable list of standard transitions (after 1970-01-01)
* maybe empty
*/
List<ZonalTransition> getStdTransitions();
/**
* <p>Returns the defined transitions in given POSIX-interval. </p>
*
* @param startInclusive start time on POSIX time scale
* @param endExclusive end time on POSIX time scale
* @return unmodifiable list of transitions maybe empty
* @throws IllegalArgumentException if start is after end
* @see #getStdTransitions()
*/
/*[deutsch]
* <p>Bestimmt die im angegebenen POSIX-Intervall vorhandenen zonalen
* Übergänge. </p>
*
* @param startInclusive start time on POSIX time scale
* @param endExclusive end time on POSIX time scale
* @return unmodifiable list of transitions maybe empty
* @throws IllegalArgumentException if start is after end
* @see #getStdTransitions()
*/
List<ZonalTransition> getTransitions(
UnixTime startInclusive,
UnixTime endExclusive
);
/**
* <p>Determines if this history does not have any transitions. </p>
*
* @return {@code true} if there are no transitions else {@code false}
*/
/*[deutsch]
* <p>Ermittelt ob diese Historie keine Übergänge kennt. </p>
*
* @return {@code true} if there are no transitions else {@code false}
*/
boolean isEmpty();
/**
* <p>Creates a dump of this history and writes it to the given buffer. </p>
*
* @param buffer buffer to write the dump to
* @throws IOException in any case of I/O-errors
*/
/*[deutsch]
* <p>Erzeugt eine Textzusammenfassung dieser Instanz und schreibt sie
* in den angegebenen Puffer. </p>
*
* @param buffer buffer to write the dump to
* @throws IOException in any case of I/O-errors
*/
void dump(Appendable buffer) throws IOException;
/**
* <p>Queries the last transition which defines the offset
* for given global timestamp. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is before first defined transition
* @since 4.18
*/
/*[deutsch]
* <p>Ermittelt den letzten Übergang, der die zur angegebenen
* Referenzzeit zugehörige Verschiebung definiert. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is before first defined transition
* @since 4.18
*/
default Optional<ZonalTransition> findStartTransition(UnixTime ut) {
ZonalTransition transition = this.getStartTransition(ut);
return ((transition == null) ? Optional.empty() : Optional.of(transition));
}
/**
* <p>Returns the conflict transition where given local timestamp
* falls either in a gap or in an overlap on the local timeline. </p>
*
* <p>Note that only the expression {@code localDate.getYear()} is used
* to determine the daylight saving rules to be applied in calculation.
* This is particularly important if there is a wall time of 24:00. Here
* only the date before merging to next day matters, not the date of the
* whole timestamp. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return optional conflict transition on the local time axis for gaps or overlaps if present
* @see #getValidOffsets(GregorianDate,WallTime)
* @since 4.18
*/
/*[deutsch]
* <p>Bestimmt den passenden Übergang, wenn die angegebene lokale
* Zeit in eine Lücke oder eine Überlappung auf dem lokalen
* Zeitstrahl fällt. </p>
*
* <p>Zu beachten: Nur der Ausdruck {@code localDate.getYear()} wird
* in der Ermittlung der passenden DST-Regeln benutzt. Das ist insbesondere
* von Bedeutung, wenn die Uhrzeit 24:00 vorliegt. Hier zählt nur
* das Jahr des angegebenen Datums, nicht das des Zeitstempels, der
* wegen der Uhrzeit evtl. im Folgejahr liegt. </p>
*
* @param localDate local date in timezone
* @param localTime local wall time in timezone
* @return optional conflict transition on the local time axis for gaps or overlaps if present
* @see #getValidOffsets(GregorianDate,WallTime)
* @since 4.18
*/
default Optional<ZonalTransition> findConflictTransition(
GregorianDate localDate,
WallTime localTime
) {
ZonalTransition transition = this.getConflictTransition(localDate, localTime);
return ((transition == null) ? Optional.empty() : Optional.of(transition));
}
/**
* <p>Queries the next transition after given global timestamp. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is after any defined transition
* @since 4.18
*/
/*[deutsch]
* <p>Ermittelt den nächsten Übergang nach der angegebenen
* Referenzzeit. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is after any defined transition
* @since 4.18
*/
default Optional<ZonalTransition> findNextTransition(UnixTime ut) {
throw new UnsupportedOperationException("Not yet implemented.");
}
/**
* <p>Queries the previous transition which defines the offset
* for given preceding global timestamp. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is not after any defined transition
* @since 4.18
*/
/*[deutsch]
* <p>Ermittelt den vorherigen Übergang, der die unmittelbar vor der angegebenen
* Referenzzeit zugehörige Verschiebung definiert. </p>
*
* @param ut unix reference time
* @return {@code ZonalTransition}, not present if given reference time is not after any defined transition
* @since 4.18
*/
default Optional<ZonalTransition> findPreviousTransition(final UnixTime ut) {
return this.findStartTransition(
new UnixTime() {
@Override
public long getPosixTime() {
return ((ut.getNanosecond() == 0) ? (ut.getPosixTime() - 1) : ut.getPosixTime());
}
@Override
public int getNanosecond() {
return ((ut.getNanosecond() == 0) ? 999_999_999 : (ut.getNanosecond() - 1));
}
}
);
}
}