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

net.time4j.SystemClock Maven / Gradle / Ivy

There is a newer version: 4.38
Show newest version
/*
 * -----------------------------------------------------------------------
 * Copyright © 2013-2015 Meno Hochschild, 
 * -----------------------------------------------------------------------
 * This file (SystemClock.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.ResourceLoader;
import net.time4j.base.TimeSource;
import net.time4j.scale.LeapSeconds;
import net.time4j.scale.TickProvider;
import net.time4j.scale.TimeScale;
import net.time4j.tz.TZID;
import net.time4j.tz.Timezone;

import java.time.Clock;
import java.time.Instant;


/**
 * 

Represents a clock which is based on the clock of the underlying operating system.

* * @author Meno Hochschild * @doctags.concurrency {immutable} */ /*[deutsch] *

Repräsentiert eine Uhr, die auf dem Taktgeber des Betriebssystems basiert.

* * @author Meno Hochschild * @doctags.concurrency {immutable} */ public final class SystemClock implements TimeSource { //~ Statische Felder/Initialisierungen -------------------------------- private static final int MIO = 1000000; private static final int MRD = MIO * 1000; private static final TickProvider PROVIDER; private static final boolean MONOTON_MODE; static { String platform = System.getProperty("java.vm.name"); TickProvider candidate = null; for (TickProvider temp : ResourceLoader.getInstance().services(TickProvider.class)) { if (platform.equals(temp.getPlatform())) { candidate = temp; break; } } if (candidate == null) { candidate = new StdTickProvider(); } PROVIDER = candidate; MONOTON_MODE = Boolean.getBoolean("net.time4j.systemclock.nanoTime"); } /** *

Standard implementation.

* *

The system property "net.time4j.systemclock.nanoTime" controls if this clock is internally * based on the expression {@link System#nanoTime()} (if property is set to "true") or * {@link System#currentTimeMillis()} (default). The standard case is a clock which is affected by * OS-triggered time jumps and user adjustments so there is no guarantee for a monotonic time.

*/ /*[deutsch] *

Standard-Implementierung.

* *

Mit der System-Property "net.time4j.systemclock.nanoTime" kann gesteuert werden, ob diese * Uhr intern auf dem Ausdruck {@link System#nanoTime()} (wenn Property auf "true" gesetzt) * oder {@link System#currentTimeMillis()} (Standard) basiert. Der Standardfall ist eine Uhr, die * für Zeitsprünge und manuelle Verstellungen der Betriebssystem-Uhr empfindlich ist, so * daß keine Garantie für eine monoton ablaufende Zeit gegeben werden kann.

*/ public static final SystemClock INSTANCE = new SystemClock(false, calibrate()); /** *

Monotonic clock based on the best available clock of the underlying operating system.

* *

A side effect of this implementation can be increased nominal precision up to nanoseconds * although no guarantee is made to ensure nanosecond accuracy. The accuracy is often limited to * milliseconds. However, the main focus and motivation is realizing a monotonic behaviour by * delegating to the use of a monotonic clock of the underlying OS. Equivalent to {@code CLOCK_MONOTONIC} * on a Linux-server.

* * @see TickProvider#getNanos() * @since 3.2/4.1 */ /*[deutsch] *

Monotone Uhr, die auf der besten verfügbaren Uhr des Betriebssystems basiert.

* *

Ein Seiteneffekt dieser Implementierung kann eine erhöhte nominelle Genauigkeit bis hin * zu Nanosekunden sein. Allerdings ist die reale Genauigkeit oft auf Millisekunden beschränkt. * Jedoch liegt der Hauptfokus darauf, ein monotones Verhalten dadurch zu realisieren, daß * eine monotone Uhr des zugrundeliegenden Betriebssystems verwendet wird. Äquivalent zu * {@code CLOCK_MONOTONIC} auf einem Linux-Server.

* * @see TickProvider#getNanos() * @since 3.2/4.1 */ public static final SystemClock MONOTONIC = new SystemClock(true, calibrate()); //~ Instanzvariablen -------------------------------------------------- private final boolean monotonic; private final long offset; //~ Konstruktoren ----------------------------------------------------- private SystemClock( boolean monotonic, long offset ) { super(); this.monotonic = monotonic; this.offset = offset; } //~ Methoden ---------------------------------------------------------- @Override public Moment currentTime() { if (this.monotonic || MONOTON_MODE) { long nanos = this.utcNanos(); return Moment.of(Math.floorDiv(nanos, MRD), (int) Math.floorMod(nanos, MRD), TimeScale.UTC); } else { long millis = System.currentTimeMillis(); int nanos = ((int) Math.floorMod(millis, 1000)) * MIO; return Moment.of(Math.floorDiv(millis, 1000), nanos, TimeScale.POSIX); } } /** *

Yields the current time in milliseconds elapsed since * [1970-01-01T00:00:00,000Z].

* * @return count of milliseconds since UNIX epoch without leap seconds * @see #currentTimeInMicros() */ /*[deutsch] *

Liefert die aktuelle seit [1970-01-01T00:00:00,000Z] verstrichene * Zeit in Millisekunden.

* * @return count of milliseconds since UNIX epoch without leap seconds * @see #currentTimeInMicros() */ public long currentTimeInMillis() { if (this.monotonic || MONOTON_MODE) { long nanos = this.utcNanos(); long secs = LeapSeconds.getInstance().strip(Math.floorDiv(nanos, MRD)); return Math.multiplyExact(secs, 1000) + Math.floorMod(nanos, MIO); } else { return System.currentTimeMillis(); } } /** *

Yields the current time in microseconds elapsed since * [1970-01-01T00:00:00,000000Z].

* *

If this clock is based only on {@link System#currentTimeMillis()} * then this method will just multiply the millisecond value by factor * {@code 1000}. On many operating systems the precision is limited to * milliseconds. This is even true if this clock is based on * {@link System#nanoTime()} because for purpose of calibration even * here the method {@code System.currentTimeMillis()} must be accessed * at least one time.

* * @return count of microseconds since UNIX epoch without leap seconds */ /*[deutsch] *

Liefert die aktuelle seit [1970-01-01T00:00:00,000000Z] verstrichene * Zeit in Mikrosekunden.

* *

Basiert diese Uhr nur auf {@link System#currentTimeMillis()}, wird * diese Methode lediglich den Millisekundenwert mit dem Faktor {@code 1000} * multiplizieren. Auf vielen Betriebssystemen ist die Genauigkeit auch * nur auf Millisekunden begrenzt. Das gilt selbst dann, wenn diese * Uhr auf {@link System#nanoTime()} basiert, weil hier wenigstens einmal * zum Zweck der Kalibrierung auf {@code System.currentTimeMillis()} * zurückgegriffen werden muß.

* * @return count of microseconds since UNIX epoch without leap seconds */ public long currentTimeInMicros() { if (this.monotonic || MONOTON_MODE) { long nanos = this.utcNanos(); long secs = LeapSeconds.getInstance().strip(Math.floorDiv(nanos, MRD)); return Math.multiplyExact(secs, MIO) + Math.floorMod(nanos, 1000); } else { return Math.multiplyExact(System.currentTimeMillis(), 1000); } } /** *

Yields the current time in microseconds elapsed since * UTC epoch [1972-01-01T00:00:00,000000Z].

* * @return count of microseconds since UTC epoch including leap seconds * @see #currentTimeInMicros() * @since 3.2/4.1 */ /*[deutsch] *

Liefert die aktuelle seit [1972-01-01T00:00:00,000000Z] verstrichene * UTC-Zeit in Mikrosekunden.

* * @return count of microseconds since UTC epoch including leap seconds * @see #currentTimeInMicros() * @since 3.2/4.1 */ public long realTimeInMicros() { if (this.monotonic || MONOTON_MODE) { return Math.floorDiv(this.utcNanos(), 1000); } else { long millis = System.currentTimeMillis(); long utc = LeapSeconds.getInstance().enhance(Math.floorDiv(millis, 1000)); return Math.multiplyExact(utc, MIO) + Math.floorMod(millis, 1000) * 1000; } } /** *

Creates a local clock in platform timezone.

* *

Uses the standard clock {@code SystemClock.INSTANCE} and the platform timezone data.

* * @return local clock in system timezone using the platform timezone data * @since 3.3/4.2 * @see net.time4j.tz.Timezone#ofSystem() * @see #INSTANCE * @see java.util.TimeZone */ /*[deutsch] *

Erzeugt eine lokale Uhr in der Plattform-Zeitzone.

* *

Verwendet die Standarduhr {@code SystemClock.INSTANCE} und die Zeitzonendaten der Plattform.

* * @return local clock in system timezone using the platform timezone data * @since 3.3/4.2 * @see net.time4j.tz.Timezone#ofSystem() * @see #INSTANCE * @see java.util.TimeZone */ public static ZonalClock inPlatformView() { String tzid = "java.util.TimeZone~" + Timezone.ofSystem().getID().canonical(); return new ZonalClock(INSTANCE, tzid); } /** *

Creates a local clock in system timezone.

* *

Uses the standard clock {@code SystemClock.INSTANCE}.

* * @return cached local clock in system timezone using the best available timezone data * @see net.time4j.tz.Timezone#ofSystem() * @see #INSTANCE */ /*[deutsch] *

Erzeugt eine lokale Uhr in der System-Zeitzone.

* *

Verwendet die Standarduhr {@code SystemClock.INSTANCE}.

* * @return cached local clock in system timezone using the best available timezone data * @see net.time4j.tz.Timezone#ofSystem() * @see #INSTANCE */ public static ZonalClock inLocalView() { return ZonalClock.ofSystem(); } /** *

Creates a local clock in given timezone.

* *

In order to achieve a monotonic zonal clock, users can use the expression * {@code new ZonalClock(SystemClock.MONOTONIC, tzid}.

* * @param tzid timezone id * @return local clock in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @see #INSTANCE */ /*[deutsch] *

Erzeugt eine lokale Uhr in der angegebenen Zeitzone.

* *

Um eine monotone zonale Uhr zu erhalten, können Anwender den Ausdruck * {@code new ZonalClock(SystemClock.MONOTONIC, tzid} verwenden.

* * @param tzid timezone id * @return local clock in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @see #INSTANCE */ public static ZonalClock inZonalView(TZID tzid) { return new ZonalClock(SystemClock.INSTANCE, tzid); } /** *

Creates a local clock in given timezone.

* *

In order to achieve a monotonic zonal clock, users can use the expression * {@code new ZonalClock(SystemClock.MONOTONIC, tzid}.

* * @param tzid timezone id * @return local clock in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @see #INSTANCE */ /*[deutsch] *

Erzeugt eine lokale Uhr in der angegebenen Zeitzone.

* *

Um eine monotone zonale Uhr zu erhalten, können Anwender den Ausdruck * {@code new ZonalClock(SystemClock.MONOTONIC, tzid} verwenden.

* * @param tzid timezone id * @return local clock in given timezone * @throws IllegalArgumentException if given timezone cannot be loaded * @see #INSTANCE */ public static ZonalClock inZonalView(String tzid) { return new ZonalClock(SystemClock.INSTANCE, tzid); } /** *

Equivalent to {@code SystemClock.INSTANCE.currentTime()}.

* * @return current time using the standard implementation * @see #INSTANCE * @since 2.3 */ /*[deutsch] *

Äquivalent zu {@code SystemClock.INSTANCE.currentTime()}.

* * @return current time using the standard implementation * @see #INSTANCE * @since 2.3 */ public static Moment currentMoment() { return SystemClock.INSTANCE.currentTime(); } /** *

Recalibrates this instance and yields a new copy.

* *

This method is only relevant if this clock is operated in monotonic mode. It is strongly advised * not to recalibrate during or near a leap second. Please also note that this method might cause jumps * in time - even backwards.

* * @return new and recalibrated copy of this instance * @see #MONOTONIC * @since 3.2/4.1 */ /*[deutsch] *

Eicht diese Instanz und liefert eine neue Kopie.

* *

Diese Methode ist nur relevant, wenn diese Uhr im monotonen Modus läuft. Es wird dringend * angeraten, nicht während oder nahe einer Schaltsekunde zu eichen. Achtung: Diese Methode kann * Zeitsprünge verursachen - eventuell sogar rückwärts.

* * @return new and recalibrated copy of this instance * @see #MONOTONIC * @since 3.2/4.1 */ public SystemClock recalibrated() { return new SystemClock(this.monotonic, calibrate()); } /** *

Synchronizes this instance with given time source and yields a new copy.

* *

This method is only relevant if this clock is operated in monotonic mode. It is strongly advised * not to recalibrate during or near a leap second. Please also note that this method might cause jumps * in time - even backwards.

* * @param clock another clock which this instance should be synchronized with * @return synchronized copy of this instance * @see #MONOTONIC * @since 3.2/4.1 */ /*[deutsch] *

Synchronisiert diese Instanz mit der angegebenen Zeitquelle und liefert eine neue Kopie.

* *

Diese Methode ist nur relevant, wenn diese Uhr im monotonen Modus läuft. Es wird dringend * angeraten, nicht während oder nahe einer Schaltsekunde zu eichen. Achtung: Diese Methode kann * Zeitsprünge verursachen - eventuell sogar rückwärts.

* * @param clock another clock which this instance should be synchronized with * @return synchronized copy of this instance * @see #MONOTONIC * @since 3.2/4.1 */ public SystemClock synchronizedWith(TimeSource clock) { Moment time = Moment.from(clock.currentTime()); long compare = (MONOTON_MODE ? System.nanoTime() : PROVIDER.getNanos()); long utc = time.getElapsedTime(TimeScale.UTC); long instantNanos = Math.multiplyExact(utc, MRD) + time.getNanosecond(TimeScale.UTC); long newOffset = Math.subtractExact(instantNanos, compare); return new SystemClock(this.monotonic, newOffset); } private static long calibrate() { // see https://bugs.openjdk.java.net/browse/JDK-8068730 (affects Java 9 or later) Instant instant = Clock.systemUTC().instant(); long compare = (MONOTON_MODE ? System.nanoTime() : PROVIDER.getNanos()); // handle Instant like POSIX, see real conversion between Instant and j.u.Date long utc = LeapSeconds.getInstance().enhance(instant.getEpochSecond()); // offset = [instant] - [counter] long instantNanos = Math.multiplyExact(utc, MRD) + instant.getNano(); return Math.subtractExact(instantNanos, compare); } private long utcNanos() { long nanos = (MONOTON_MODE ? System.nanoTime() : PROVIDER.getNanos()); return Math.addExact(nanos, this.offset); } //~ Innere Klassen ---------------------------------------------------- private static class StdTickProvider implements TickProvider { //~ Methoden ------------------------------------------------------ @Override public String getPlatform() { return ""; } @Override public long getNanos() { return System.nanoTime(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy