net.time4j.ZonalClock Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2017 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (ZonalClock.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;
import net.time4j.base.TimeSource;
import net.time4j.base.UnixTime;
import net.time4j.engine.CalendarFamily;
import net.time4j.engine.CalendarVariant;
import net.time4j.engine.ChronoEntity;
import net.time4j.engine.Chronology;
import net.time4j.engine.StartOfDay;
import net.time4j.engine.VariantSource;
import net.time4j.format.Attributes;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;
/**
* Represents a clock which yields the current local time according
* to a timezone.
*
* This class is immutable as long as the underlying implementations
* of time source and time zone are.
*
* @author Meno Hochschild
* @see SystemClock#inLocalView()
* @see SystemClock#inZonalView(TZID)
*/
/*[deutsch]
* Repräsentiert eine Uhr, die die aktuelle lokale Zeit anzeigt.
*
* Diese Klasse ist solange immutable (unveränderlich), wie
* die zugrundeliegenden Implementierungen der Zeitquelle und der Zeitzone
* es sind.
*
* @author Meno Hochschild
* @see SystemClock#inLocalView()
* @see SystemClock#inZonalView(TZID)
*/
public final class ZonalClock {
// --------------------
// Implementation note:
// --------------------
// This class does not implement the interface TimeSource intentionally
// because it is really designed for querying "zonal" times but not for
// being injected into any test class or business object. Otherwise
// zonal dependencies could be obfuscated from a user-perspective.
// Instead users are strongly encouraged to use expressions like
// SystemClock#inZonalView(TZID).
//~ Statische Felder/Initialisierungen --------------------------------
private static final ZonalClock SYSTEM = new ZonalClock();
//~ Instanzvariablen --------------------------------------------------
private final TimeSource> timeSource;
private final Timezone timezone;
//~ Konstruktoren -----------------------------------------------------
/**
* Constructs a new clock which can yield the current local time in
* given timezone.
*
* Most users have no need to directly call this constructor. It is
* mainly designed for being called by dedicated expressions like
* {@code SystemClock.inZonalView(tzid)} etc.
*
* @param timeSource source for current world time (UTC)
* @param tzid timezone id
* @throws IllegalArgumentException if given timezone cannot be loaded
*/
/*[deutsch]
* Konstruiert eine neue Uhr, die die aktuelle Zeit in einer Zeitzone
* ermitteln kann.
*
* Die meisten Anwender brauchen diesen Konstruktor nicht. Er ist
* im wesentlichen für den Aufruf durch spezielle Ausdrücke
* wie {@code SystemClock.inZonalView(tzid)} etc. gedacht.
*
* @param timeSource source for current world time (UTC)
* @param tzid timezone id
* @throws IllegalArgumentException if given timezone cannot be loaded
*/
public ZonalClock(
TimeSource> timeSource,
TZID tzid
) {
this(timeSource, Timezone.of(tzid));
}
/**
* Constructs a new clock which can yield the current local time in
* given timezone.
*
* Most users have no need to directly call this constructor. It is
* mainly designed for being called by dedicated expressions like
* {@code SystemClock.inZonalView(tzid)} etc.
*
* @param timeSource source for current world time (UTC)
* @param tzid timezone id
* @throws IllegalArgumentException if given timezone cannot be loaded
*/
/*[deutsch]
* Konstruiert eine neue Uhr, die die aktuelle Zeit in einer Zeitzone
* ermitteln kann.
*
* Die meisten Anwender brauchen diesen Konstruktor nicht. Er ist
* im wesentlichen für den Aufruf durch spezielle Ausdrücke
* wie {@code SystemClock.inZonalView(tzid)} etc. gedacht.
*
* @param timeSource source for current world time (UTC)
* @param tzid timezone id
* @throws IllegalArgumentException if given timezone cannot be loaded
*/
public ZonalClock(
TimeSource> timeSource,
String tzid
) {
this(timeSource, Timezone.of(tzid));
}
/**
* Constructs a new clock which can yield the current local time in
* given timezone.
*
* Most users have no need to directly call this constructor. It is
* mainly designed for being called by dedicated expressions like
* {@code SystemClock.inLocalView()} etc.
*
* @param timeSource source for current world time (UTC)
* @param tz timezone
* @throws IllegalArgumentException if given timezone cannot be loaded
* @since 3.22/4.18
*/
/*[deutsch]
* Konstruiert eine neue Uhr, die die aktuelle Zeit in einer Zeitzone
* ermitteln kann.
*
* Die meisten Anwender brauchen diesen Konstruktor nicht. Er ist
* im wesentlichen für den Aufruf durch spezielle Ausdrücke
* wie {@code SystemClock.inLocalView()} etc. gedacht.
*
* @param timeSource source for current world time (UTC)
* @param tz timezone
* @throws IllegalArgumentException if given timezone cannot be loaded
* @since 3.22/4.18
*/
public ZonalClock(
TimeSource> timeSource,
Timezone tz
) {
if (timeSource == null) {
throw new NullPointerException("Missing time source.");
} else if (tz == null) {
throw new NullPointerException("Missing timezone.");
}
this.timeSource = timeSource;
this.timezone = tz;
}
private ZonalClock() {
super();
this.timeSource = SystemClock.INSTANCE;
this.timezone = null;
}
//~ Methoden ----------------------------------------------------------
/**
* Gets the current date in the associated timezone.
*
* The result dynamically depends on the associated timezone meaning if and only if the underlying
* timezone is the system timezone.
*
* @return calendar date representing today
*/
/**
* Ermittelt das aktuelle Datum in der assoziierten Zeitzone.
*
* Das Ergebnis hängt genau dann dynamisch von der assoziierten Zeitzone ab, wenn die
* System-Zeitzone vorliegt.
*
* @return calendar date representing today
*/
public PlainDate today() {
final UnixTime ut = this.timeSource.currentTime();
Timezone tz = (this.timezone == null) ? Timezone.ofSystem() : this.timezone;
return PlainDate.from(ut, tz.getOffset(ut));
}
/**
* Gets the current timestamp in the associated timezone.
*
* The result dynamically depends on the associated timezone meaning if and only if the underlying
* timezone is the system timezone.
*
* @return current local timestamp
*/
/*[deutsch]
* Ermittelt die aktuelle Zeit in der assoziierten Zeitzone.
*
* Das Ergebnis hängt genau dann dynamisch von der assoziierten Zeitzone ab, wenn die
* System-Zeitzone vorliegt.
*
* @return current local timestamp
*/
public PlainTimestamp now() {
final UnixTime ut = this.timeSource.currentTime();
Timezone tz = (this.timezone == null) ? Timezone.ofSystem() : this.timezone;
return PlainTimestamp.from(ut, tz.getOffset(ut));
}
/**
* Gets the current timestamp in the associated timezone and given chronology.
*
* The result always dynamically depends on the associated timezone meaning if the underlying
* timezone data change then the result will also change by next call.
*
* Code example:
*
*
* System.out.println(SystemClock.inLocalView().now(PlainTime.axis())); // local wall time
*
*
* @param generic type of chronology
* @param chronology chronology to be used
* @return current local timestamp or date in given chronology
* @throws IllegalArgumentException if given chronology requires a calendar variant
* @since 3.3/4.2
*/
/*[deutsch]
* Ermittelt die aktuelle Zeit in der assoziierten Zeitzone und angegebenen Chronologie.
*
* Das Ergebnis hängt immer dynamisch von der assoziierten Zeitzone ab. Wenn deren Daten sich
* ändern, dann wird diese Methode beim nächsten Aufruf ein angepasstes Ergebnis liefern.
*
* Code-Beispiel:
*
*
* System.out.println(SystemClock.inLocalView().now(PlainTime.axis())); // lokale Uhrzeit
*
*
* @param generic type of chronology
* @param chronology chronology to be used
* @return current local timestamp or date in given chronology
* @throws IllegalArgumentException if given chronology requires a calendar variant
* @since 3.3/4.2
*/
public > T now(Chronology chronology) {
Timezone tz = (this.timezone == null) ? Timezone.ofSystem() : this.timezone;
Attributes attrs = new Attributes.Builder().setTimezone(tz.getID()).build();
T result = chronology.createFrom(this.timeSource, attrs);
if (result == null) {
Class> type = chronology.getChronoType();
if (CalendarVariant.class.isAssignableFrom(type)) {
throw new IllegalArgumentException("Calendar variant required: " + type.getName());
} else {
throw new IllegalArgumentException("Insufficient data: " + type.getName());
}
} else {
return result;
}
}
/**
* Gets the current timestamp in the associated timezone and given chronology taking into account
* given calendar variant and start of day.
*
* The result always dynamically depends on the associated timezone meaning if the underlying
* timezone data change then the result will also change by next call.
*
* Code example:
*
*
* HijriCalendar hijriDate =
* CLOCK.now(
* HijriCalendar.family(),
* HijriCalendar.VARIANT_UMALQURA,
* StartOfDay.EVENING)
* .toDate();
* System.out.println(hijriDate); // AH-1436-10-02[islamic-umalqura]
*
*
* Note that this example is even true if the current timestamp is 2015-07-17T18:00 which would
* normally map to AH-1436-10-01 (if the clock time is not considered). Reason is that the islamic
* day starts on the evening of the previous day.
*
* @param generic type of chronology
* @param family calendar family to be used
* @param variant calendar variant
* @param startOfDay start of calendar day
* @return current general timestamp in given chronology
* @throws IllegalArgumentException if given variant is not supported
* @since 3.8/4.5
*/
/*[deutsch]
* Ermittelt die aktuelle Zeit in der assoziierten Zeitzone und angegebenen Chronologie unter
* Berücksichtigung von Kalendervariante und Start des Kalendertages.
*
* Das Ergebnis hängt immer dynamisch von der assoziierten Zeitzone ab. Wenn deren Daten sich
* ändern, dann wird diese Methode beim nächsten Aufruf ein angepasstes Ergebnis liefern.
*
* Code-Beispiel:
*
*
* HijriCalendar hijriDate =
* CLOCK.now(
* HijriCalendar.family(),
* HijriCalendar.VARIANT_UMALQURA,
* StartOfDay.EVENING)
* .toDate();
* System.out.println(hijriDate); // AH-1436-10-02[islamic-umalqura]
*
*
* Zu beachten: Dieses Beispiel stimmt sogar dann, wenn der aktuelle Zeitstempel 2015-07-17T18:00 ist,
* welcher normalerweise auf das islamische Datum AH-1436-10-01 abgebildet wird (wenn die Uhrzeit nicht
* betrachtet wird), denn der islamische Tag beginnt am Abend des Vortags.
*
* @param generic type of chronology
* @param family calendar family to be used
* @param variant calendar variant
* @param startOfDay start of calendar day
* @return current general timestamp in given chronology
* @throws IllegalArgumentException if given variant is not supported
* @since 3.8/4.5
*/
public > GeneralTimestamp now(
CalendarFamily family,
String variant,
StartOfDay startOfDay
) {
Timezone tz = (this.timezone == null) ? Timezone.ofSystem() : this.timezone;
Moment moment = Moment.from(this.timeSource.currentTime());
return moment.toGeneralTimestamp(family, variant, tz.getID(), startOfDay);
}
/**
* Equivalent to {@code now(chronology, variantSource.getVariant(), startOfDay)}.
*
* @param generic type of chronology
* @param family calendar family to be used
* @param variantSource source of calendar variant
* @param startOfDay start of calendar day
* @return current local timestamp or date in given chronology
* @throws IllegalArgumentException if given variant is not supported
* @see #now(CalendarFamily, String, StartOfDay)
* @since 3.8/4.5
*/
/*[deutsch]
* Äquivalent to {@code now(chronology, variantSource.getVariant(), startOfDay)}.
*
* @param generic type of chronology
* @param family calendar family to be used
* @param variantSource source of calendar variant
* @param startOfDay start of calendar day
* @return current local timestamp or date in given chronology
* @throws IllegalArgumentException if given variant is not supported
* @see #now(CalendarFamily, String, StartOfDay)
* @since 3.8/4.5
*/
public > GeneralTimestamp now(
CalendarFamily family,
VariantSource variantSource,
StartOfDay startOfDay
) {
return this.now(family, variantSource.getVariant(), startOfDay);
}
/**
* Equivalent to the expression {@code now().inStdTimezone()}.
*
* For performance reasons, it is usually better to directly call {@code SystemClock.currentMoment()}.
* However, this method is designed for mobile platforms where users have adjusted the clock to compensate
* outdated or wrong device timezone data, see also {@link SystemClock#inPlatformView()}.
*
* @return current moment
* @since 3.29/4.25
*/
/*[deutsch]
* Äquivalent zum Ausdruck {@code now().inStdTimezone()}.
*
* Für ein optimales Antwortzeitverhalten ist es gewöhnlich besser, direkt
* {@code SystemClock.currentMoment()} aufzurufen. Aber diese Methode ist speziell für Mobilplattformen
* gedacht, auf denen Anwender die Uhr verstellt haben, um veraltete oder falsche Zeitzonendaten der
* Plattform auszugleichen, siehe auch {@link SystemClock#inPlatformView()}.
*
* @return current moment
* @since 3.29/4.25
*/
public Moment currentMoment() {
return this.now().inStdTimezone();
}
/**
* Gets the associated clock.
*
* @return time source
*/
/*[deutsch]
* Liefert die assoziierte Uhr.
*
* @return Zeitquelle
*/
public TimeSource> getSource() {
return this.timeSource;
}
/**
* Gets the associated timezone.
*
* @return timezone id
*/
/*[deutsch]
* Liefert die assoziierte Zeitzone.
*
* @return timezone id
*/
public TZID getTimezone() {
Timezone tz = (this.timezone == null) ? Timezone.ofSystem() : this.timezone;
return tz.getID();
}
/**
* Zonale Uhr basierend auf den Systemeinstellungen beim Laden
* dieser Klasse.
*
* @return local clock in default system timezone
*/
static ZonalClock ofSystem() {
return SYSTEM;
}
}