Path: blob/master/src/java.base/share/classes/java/time/Clock.java
67862 views
/*1* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file:30*31* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos32*33* All rights reserved.34*35* Redistribution and use in source and binary forms, with or without36* modification, are permitted provided that the following conditions are met:37*38* * Redistributions of source code must retain the above copyright notice,39* this list of conditions and the following disclaimer.40*41* * Redistributions in binary form must reproduce the above copyright notice,42* this list of conditions and the following disclaimer in the documentation43* and/or other materials provided with the distribution.44*45* * Neither the name of JSR-310 nor the names of its contributors46* may be used to endorse or promote products derived from this software47* without specific prior written permission.48*49* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS50* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT51* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR52* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR53* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,54* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,55* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR56* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF57* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING58* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS59* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.60*/61package java.time;6263import java.io.IOException;64import java.io.ObjectInputStream;65import java.io.ObjectStreamException;6667import static java.time.LocalTime.NANOS_PER_MINUTE;68import static java.time.LocalTime.NANOS_PER_SECOND;69import static java.time.LocalTime.NANOS_PER_MILLI;70import java.io.Serializable;71import java.util.Objects;72import java.util.TimeZone;73import jdk.internal.misc.VM;7475/**76* A clock providing access to the current instant, date and time using a time-zone.77* <p>78* Instances of this abstract class are used to access a pluggable representation of the79* current instant, which can be interpreted using the stored time-zone to find the80* current date and time.81* For example, {@code Clock} can be used instead of {@link System#currentTimeMillis()}82* and {@link TimeZone#getDefault()}.83* <p>84* Use of a {@code Clock} is optional. All key date-time classes also have a85* {@code now()} factory method that uses the system clock in the default time zone.86* The primary purpose of this abstraction is to allow alternate clocks to be87* plugged in as and when required. Applications use an object to obtain the88* current time rather than a static method. This can simplify testing.89* <p>90* As such, this abstract class does not guarantee the result actually represents the current instant91* on the time-line. Instead, it allows the application to provide a controlled view as to what92* the current instant and time-zone are.93* <p>94* Best practice for applications is to pass a {@code Clock} into any method95* that requires the current instant and time-zone. A dependency injection framework96* is one way to achieve this:97* <pre>98* public class MyBean {99* private Clock clock; // dependency inject100* ...101* public void process(LocalDate eventDate) {102* if (eventDate.isBefore(LocalDate.now(clock)) {103* ...104* }105* }106* }107* </pre>108* This approach allows an alternative clock, such as {@link #fixed(Instant, ZoneId) fixed}109* or {@link #offset(Clock, Duration) offset} to be used during testing.110* <p>111* The {@code system} factory methods provide clocks based on the best available112* system clock. This may use {@link System#currentTimeMillis()}, or a higher113* resolution clock if one is available.114*115* @implSpec116* This abstract class must be implemented with care to ensure other classes operate correctly.117* All implementations must be thread-safe - a single instance must be capable of be invoked118* from multiple threads without negative consequences such as race conditions.119* <p>120* The principal methods are defined to allow the throwing of an exception.121* In normal use, no exceptions will be thrown, however one possible implementation would be to122* obtain the time from a central time server across the network. Obviously, in this case the123* lookup could fail, and so the method is permitted to throw an exception.124* <p>125* The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,126* as described in {@link Instant}. If the implementation wraps a source that provides leap127* second information, then a mechanism should be used to "smooth" the leap second.128* The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose129* how accurate they are with the time-scale so long as they document how they work.130* Implementations are therefore not required to actually perform the UTC-SLS slew or to131* otherwise be aware of leap seconds.132* <p>133* Implementations should implement {@code Serializable} wherever possible and must134* document whether or not they do support serialization.135*136* @see InstantSource137*138* @since 1.8139*/140public abstract class Clock implements InstantSource {141142/**143* Obtains a clock that returns the current instant using the best available144* system clock, converting to date and time using the UTC time-zone.145* <p>146* This clock, rather than {@link #systemDefaultZone()}, should be used when147* you need the current instant without the date or time.148* <p>149* This clock is based on the best available system clock.150* This may use {@link System#currentTimeMillis()}, or a higher resolution151* clock if one is available.152* <p>153* Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.154* <p>155* The returned implementation is immutable, thread-safe and {@code Serializable}.156* It is equivalent to {@code system(ZoneOffset.UTC)}.157*158* @return a clock that uses the best available system clock in the UTC zone, not null159*/160public static Clock systemUTC() {161return SystemClock.UTC;162}163164/**165* Obtains a clock that returns the current instant using the best available166* system clock, converting to date and time using the default time-zone.167* <p>168* This clock is based on the best available system clock.169* This may use {@link System#currentTimeMillis()}, or a higher resolution170* clock if one is available.171* <p>172* Using this method hard codes a dependency to the default time-zone into your application.173* It is recommended to avoid this and use a specific time-zone whenever possible.174* The {@link #systemUTC() UTC clock} should be used when you need the current instant175* without the date or time.176* <p>177* The returned implementation is immutable, thread-safe and {@code Serializable}.178* It is equivalent to {@code system(ZoneId.systemDefault())}.179*180* @return a clock that uses the best available system clock in the default zone, not null181* @see ZoneId#systemDefault()182*/183public static Clock systemDefaultZone() {184return new SystemClock(ZoneId.systemDefault());185}186187/**188* Obtains a clock that returns the current instant using the best available189* system clock.190* <p>191* This clock is based on the best available system clock.192* This may use {@link System#currentTimeMillis()}, or a higher resolution193* clock if one is available.194* <p>195* Conversion from instant to date or time uses the specified time-zone.196* <p>197* The returned implementation is immutable, thread-safe and {@code Serializable}.198*199* @param zone the time-zone to use to convert the instant to date-time, not null200* @return a clock that uses the best available system clock in the specified zone, not null201*/202public static Clock system(ZoneId zone) {203Objects.requireNonNull(zone, "zone");204if (zone == ZoneOffset.UTC) {205return SystemClock.UTC;206}207return new SystemClock(zone);208}209210//-------------------------------------------------------------------------211/**212* Obtains a clock that returns the current instant ticking in whole milliseconds213* using the best available system clock.214* <p>215* This clock will always have the nano-of-second field truncated to milliseconds.216* This ensures that the visible time ticks in whole milliseconds.217* The underlying clock is the best available system clock, equivalent to218* using {@link #system(ZoneId)}.219* <p>220* Implementations may use a caching strategy for performance reasons.221* As such, it is possible that the start of the millisecond observed via this222* clock will be later than that observed directly via the underlying clock.223* <p>224* The returned implementation is immutable, thread-safe and {@code Serializable}.225* It is equivalent to {@code tick(system(zone), Duration.ofMillis(1))}.226*227* @param zone the time-zone to use to convert the instant to date-time, not null228* @return a clock that ticks in whole milliseconds using the specified zone, not null229* @since 9230*/231public static Clock tickMillis(ZoneId zone) {232return new TickClock(system(zone), NANOS_PER_MILLI);233}234235//-------------------------------------------------------------------------236/**237* Obtains a clock that returns the current instant ticking in whole seconds238* using the best available system clock.239* <p>240* This clock will always have the nano-of-second field set to zero.241* This ensures that the visible time ticks in whole seconds.242* The underlying clock is the best available system clock, equivalent to243* using {@link #system(ZoneId)}.244* <p>245* Implementations may use a caching strategy for performance reasons.246* As such, it is possible that the start of the second observed via this247* clock will be later than that observed directly via the underlying clock.248* <p>249* The returned implementation is immutable, thread-safe and {@code Serializable}.250* It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.251*252* @param zone the time-zone to use to convert the instant to date-time, not null253* @return a clock that ticks in whole seconds using the specified zone, not null254*/255public static Clock tickSeconds(ZoneId zone) {256return new TickClock(system(zone), NANOS_PER_SECOND);257}258259/**260* Obtains a clock that returns the current instant ticking in whole minutes261* using the best available system clock.262* <p>263* This clock will always have the nano-of-second and second-of-minute fields set to zero.264* This ensures that the visible time ticks in whole minutes.265* The underlying clock is the best available system clock, equivalent to266* using {@link #system(ZoneId)}.267* <p>268* Implementations may use a caching strategy for performance reasons.269* As such, it is possible that the start of the minute observed via this270* clock will be later than that observed directly via the underlying clock.271* <p>272* The returned implementation is immutable, thread-safe and {@code Serializable}.273* It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.274*275* @param zone the time-zone to use to convert the instant to date-time, not null276* @return a clock that ticks in whole minutes using the specified zone, not null277*/278public static Clock tickMinutes(ZoneId zone) {279return new TickClock(system(zone), NANOS_PER_MINUTE);280}281282/**283* Obtains a clock that returns instants from the specified clock truncated284* to the nearest occurrence of the specified duration.285* <p>286* This clock will only tick as per the specified duration. Thus, if the duration287* is half a second, the clock will return instants truncated to the half second.288* <p>289* The tick duration must be positive. If it has a part smaller than a whole290* millisecond, then the whole duration must divide into one second without291* leaving a remainder. All normal tick durations will match these criteria,292* including any multiple of hours, minutes, seconds and milliseconds, and293* sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.294* <p>295* A duration of zero or one nanosecond would have no truncation effect.296* Passing one of these will return the underlying clock.297* <p>298* Implementations may use a caching strategy for performance reasons.299* As such, it is possible that the start of the requested duration observed300* via this clock will be later than that observed directly via the underlying clock.301* <p>302* The returned implementation is immutable, thread-safe and {@code Serializable}303* providing that the base clock is.304*305* @param baseClock the base clock to base the ticking clock on, not null306* @param tickDuration the duration of each visible tick, not negative, not null307* @return a clock that ticks in whole units of the duration, not null308* @throws IllegalArgumentException if the duration is negative, or has a309* part smaller than a whole millisecond such that the whole duration is not310* divisible into one second311* @throws ArithmeticException if the duration is too large to be represented as nanos312*/313public static Clock tick(Clock baseClock, Duration tickDuration) {314Objects.requireNonNull(baseClock, "baseClock");315Objects.requireNonNull(tickDuration, "tickDuration");316if (tickDuration.isNegative()) {317throw new IllegalArgumentException("Tick duration must not be negative");318}319long tickNanos = tickDuration.toNanos();320if (tickNanos % 1000_000 == 0) {321// ok, no fraction of millisecond322} else if (1000_000_000 % tickNanos == 0) {323// ok, divides into one second without remainder324} else {325throw new IllegalArgumentException("Invalid tick duration");326}327if (tickNanos <= 1) {328return baseClock;329}330return new TickClock(baseClock, tickNanos);331}332333//-----------------------------------------------------------------------334/**335* Obtains a clock that always returns the same instant.336* <p>337* This clock simply returns the specified instant.338* As such, it is not a clock in the conventional sense.339* The main use case for this is in testing, where the fixed clock ensures340* tests are not dependent on the current clock.341* <p>342* The returned implementation is immutable, thread-safe and {@code Serializable}.343*344* @param fixedInstant the instant to use as the clock, not null345* @param zone the time-zone to use to convert the instant to date-time, not null346* @return a clock that always returns the same instant, not null347*/348public static Clock fixed(Instant fixedInstant, ZoneId zone) {349Objects.requireNonNull(fixedInstant, "fixedInstant");350Objects.requireNonNull(zone, "zone");351return new FixedClock(fixedInstant, zone);352}353354//-------------------------------------------------------------------------355/**356* Obtains a clock that returns instants from the specified clock with the357* specified duration added.358* <p>359* This clock wraps another clock, returning instants that are later by the360* specified duration. If the duration is negative, the instants will be361* earlier than the current date and time.362* The main use case for this is to simulate running in the future or in the past.363* <p>364* A duration of zero would have no offsetting effect.365* Passing zero will return the underlying clock.366* <p>367* The returned implementation is immutable, thread-safe and {@code Serializable}368* providing that the base clock is.369*370* @param baseClock the base clock to add the duration to, not null371* @param offsetDuration the duration to add, not null372* @return a clock based on the base clock with the duration added, not null373*/374public static Clock offset(Clock baseClock, Duration offsetDuration) {375Objects.requireNonNull(baseClock, "baseClock");376Objects.requireNonNull(offsetDuration, "offsetDuration");377if (offsetDuration.equals(Duration.ZERO)) {378return baseClock;379}380return new OffsetClock(baseClock, offsetDuration);381}382383//-----------------------------------------------------------------------384/**385* Constructor accessible by subclasses.386*/387protected Clock() {388}389390//-----------------------------------------------------------------------391/**392* Gets the time-zone being used to create dates and times.393* <p>394* A clock will typically obtain the current instant and then convert that395* to a date or time using a time-zone. This method returns the time-zone used.396*397* @return the time-zone being used to interpret instants, not null398*/399public abstract ZoneId getZone();400401/**402* Returns a copy of this clock with a different time-zone.403* <p>404* A clock will typically obtain the current instant and then convert that405* to a date or time using a time-zone. This method returns a clock with406* similar properties but using a different time-zone.407*408* @param zone the time-zone to change to, not null409* @return a clock based on this clock with the specified time-zone, not null410*/411@Override412public abstract Clock withZone(ZoneId zone);413414//-------------------------------------------------------------------------415/**416* Gets the current millisecond instant of the clock.417* <p>418* This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).419* This is equivalent to the definition of {@link System#currentTimeMillis()}.420* <p>421* Most applications should avoid this method and use {@link Instant} to represent422* an instant on the time-line rather than a raw millisecond value.423* This method is provided to allow the use of the clock in high performance use cases424* where the creation of an object would be unacceptable.425* <p>426* The default implementation currently calls {@link #instant}.427*428* @return the current millisecond instant from this clock, measured from429* the Java epoch of 1970-01-01T00:00Z (UTC), not null430* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations431*/432@Override433public long millis() {434return instant().toEpochMilli();435}436437//-----------------------------------------------------------------------438/**439* Gets the current instant of the clock.440* <p>441* This returns an instant representing the current instant as defined by the clock.442*443* @return the current instant from this clock, not null444* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations445*/446@Override447public abstract Instant instant();448449//-----------------------------------------------------------------------450/**451* Checks if this clock is equal to another clock.452* <p>453* Clocks should override this method to compare equals based on454* their state and to meet the contract of {@link Object#equals}.455* If not overridden, the behavior is defined by {@link Object#equals}456*457* @param obj the object to check, null returns false458* @return true if this is equal to the other clock459*/460@Override461public boolean equals(Object obj) {462return super.equals(obj);463}464465/**466* A hash code for this clock.467* <p>468* Clocks should override this method based on469* their state and to meet the contract of {@link Object#hashCode}.470* If not overridden, the behavior is defined by {@link Object#hashCode}471*472* @return a suitable hash code473*/474@Override475public int hashCode() {476return super.hashCode();477}478479//-----------------------------------------------------------------------480// initial offset481private static final long OFFSET_SEED = System.currentTimeMillis() / 1000 - 1024;482// We don't actually need a volatile here.483// We don't care if offset is set or read concurrently by multiple484// threads - we just need a value which is 'recent enough' - in other485// words something that has been updated at least once in the last486// 2^32 secs (~136 years). And even if we by chance see an invalid487// offset, the worst that can happen is that we will get a -1 value488// from getNanoTimeAdjustment, forcing us to update the offset489// once again.490private static long offset = OFFSET_SEED;491492static Instant currentInstant() {493// Take a local copy of offset. offset can be updated concurrently494// by other threads (even if we haven't made it volatile) so we will495// work with a local copy.496long localOffset = offset;497long adjustment = VM.getNanoTimeAdjustment(localOffset);498499if (adjustment == -1) {500// -1 is a sentinel value returned by VM.getNanoTimeAdjustment501// when the offset it is given is too far off the current UTC502// time. In principle, this should not happen unless the503// JVM has run for more than ~136 years (not likely) or504// someone is fiddling with the system time, or the offset is505// by chance at 1ns in the future (very unlikely).506// We can easily recover from all these conditions by bringing507// back the offset in range and retry.508509// bring back the offset in range. We use -1024 to make510// it more unlikely to hit the 1ns in the future condition.511localOffset = System.currentTimeMillis() / 1000 - 1024;512513// retry514adjustment = VM.getNanoTimeAdjustment(localOffset);515516if (adjustment == -1) {517// Should not happen: we just recomputed a new offset.518// It should have fixed the issue.519throw new InternalError("Offset " + localOffset + " is not in range");520} else {521// OK - recovery succeeded. Update the offset for the522// next call...523offset = localOffset;524}525}526return Instant.ofEpochSecond(localOffset, adjustment);527}528529//-----------------------------------------------------------------------530/**531* An instant source that always returns the latest time from532* {@link System#currentTimeMillis()} or equivalent.533*/534static final class SystemInstantSource implements InstantSource, Serializable {535@java.io.Serial536private static final long serialVersionUID = 3232399674412L;537// this is a singleton, but the class is coded such that it is not a538// problem if someone hacks around and creates another instance539static final SystemInstantSource INSTANCE = new SystemInstantSource();540541SystemInstantSource() {542}543@Override544public Clock withZone(ZoneId zone) {545return Clock.system(zone);546}547@Override548public long millis() {549// System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset)550// use the same time source - System.currentTimeMillis() simply551// limits the resolution to milliseconds.552// So we take the faster path and call System.currentTimeMillis()553// directly - in order to avoid the performance penalty of554// VM.getNanoTimeAdjustment(offset) which is less efficient.555return System.currentTimeMillis();556}557@Override558public Instant instant() {559return currentInstant();560}561@Override562public boolean equals(Object obj) {563return obj instanceof SystemInstantSource;564}565@Override566public int hashCode() {567return SystemInstantSource.class.hashCode();568}569@Override570public String toString() {571return "SystemInstantSource";572}573@java.io.Serial574private Object readResolve() throws ObjectStreamException {575return SystemInstantSource.INSTANCE;576}577}578579//-----------------------------------------------------------------------580/**581* Implementation of a clock that always returns the latest time from582* {@code SystemInstantSource.INSTANCE}.583*/584static final class SystemClock extends Clock implements Serializable {585@java.io.Serial586private static final long serialVersionUID = 6740630888130243051L;587static final SystemClock UTC = new SystemClock(ZoneOffset.UTC);588589private final ZoneId zone;590591SystemClock(ZoneId zone) {592this.zone = zone;593}594@Override595public ZoneId getZone() {596return zone;597}598@Override599public Clock withZone(ZoneId zone) {600if (zone.equals(this.zone)) { // intentional NPE601return this;602}603return new SystemClock(zone);604}605@Override606public long millis() {607// inline of SystemInstantSource.INSTANCE.millis()608return System.currentTimeMillis();609}610@Override611public Instant instant() {612// inline of SystemInstantSource.INSTANCE.instant()613return currentInstant();614}615@Override616public boolean equals(Object obj) {617if (obj instanceof SystemClock) {618return zone.equals(((SystemClock) obj).zone);619}620return false;621}622@Override623public int hashCode() {624return zone.hashCode() + 1;625}626@Override627public String toString() {628return "SystemClock[" + zone + "]";629}630}631632//-----------------------------------------------------------------------633/**634* Implementation of a clock that always returns the same instant.635* This is typically used for testing.636*/637static final class FixedClock extends Clock implements Serializable {638@java.io.Serial639private static final long serialVersionUID = 7430389292664866958L;640private final Instant instant;641private final ZoneId zone;642643FixedClock(Instant fixedInstant, ZoneId zone) {644this.instant = fixedInstant;645this.zone = zone;646}647@Override648public ZoneId getZone() {649return zone;650}651@Override652public Clock withZone(ZoneId zone) {653if (zone.equals(this.zone)) { // intentional NPE654return this;655}656return new FixedClock(instant, zone);657}658@Override659public long millis() {660return instant.toEpochMilli();661}662@Override663public Instant instant() {664return instant;665}666@Override667public boolean equals(Object obj) {668return obj instanceof FixedClock other669&& instant.equals(other.instant)670&& zone.equals(other.zone);671}672@Override673public int hashCode() {674return instant.hashCode() ^ zone.hashCode();675}676@Override677public String toString() {678return "FixedClock[" + instant + "," + zone + "]";679}680}681682//-----------------------------------------------------------------------683/**684* Implementation of a clock that adds an offset to an underlying clock.685*/686static final class OffsetClock extends Clock implements Serializable {687@java.io.Serial688private static final long serialVersionUID = 2007484719125426256L;689@SuppressWarnings("serial") // Not statically typed as Serializable690private final Clock baseClock;691private final Duration offset;692693OffsetClock(Clock baseClock, Duration offset) {694this.baseClock = baseClock;695this.offset = offset;696}697@Override698public ZoneId getZone() {699return baseClock.getZone();700}701@Override702public Clock withZone(ZoneId zone) {703if (zone.equals(baseClock.getZone())) { // intentional NPE704return this;705}706return new OffsetClock(baseClock.withZone(zone), offset);707}708@Override709public long millis() {710return Math.addExact(baseClock.millis(), offset.toMillis());711}712@Override713public Instant instant() {714return baseClock.instant().plus(offset);715}716@Override717public boolean equals(Object obj) {718return obj instanceof OffsetClock other719&& baseClock.equals(other.baseClock)720&& offset.equals(other.offset);721}722@Override723public int hashCode() {724return baseClock.hashCode() ^ offset.hashCode();725}726@Override727public String toString() {728return "OffsetClock[" + baseClock + "," + offset + "]";729}730}731732//-----------------------------------------------------------------------733/**734* Implementation of a clock that reduces the tick frequency of an underlying clock.735*/736static final class TickClock extends Clock implements Serializable {737@java.io.Serial738private static final long serialVersionUID = 6504659149906368850L;739@SuppressWarnings("serial") // Not statically typed as Serializable740private final Clock baseClock;741private final long tickNanos;742743TickClock(Clock baseClock, long tickNanos) {744this.baseClock = baseClock;745this.tickNanos = tickNanos;746}747@Override748public ZoneId getZone() {749return baseClock.getZone();750}751@Override752public Clock withZone(ZoneId zone) {753if (zone.equals(baseClock.getZone())) { // intentional NPE754return this;755}756return new TickClock(baseClock.withZone(zone), tickNanos);757}758@Override759public long millis() {760long millis = baseClock.millis();761return millis - Math.floorMod(millis, tickNanos / 1000_000L);762}763@Override764public Instant instant() {765if ((tickNanos % 1000_000) == 0) {766long millis = baseClock.millis();767return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));768}769Instant instant = baseClock.instant();770long nanos = instant.getNano();771long adjust = Math.floorMod(nanos, tickNanos);772return instant.minusNanos(adjust);773}774@Override775public boolean equals(Object obj) {776return (obj instanceof TickClock other)777&& tickNanos == other.tickNanos778&& baseClock.equals(other.baseClock);779}780@Override781public int hashCode() {782return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));783}784@Override785public String toString() {786return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";787}788}789790//-----------------------------------------------------------------------791/**792* Implementation of a clock based on an {@code InstantSource}.793*/794static final class SourceClock extends Clock implements Serializable {795@java.io.Serial796private static final long serialVersionUID = 235386528762398L;797@SuppressWarnings("serial") // Not statically typed as Serializable798private final InstantSource baseSource;799private final ZoneId zone;800801SourceClock(InstantSource baseSource, ZoneId zone) {802this.baseSource = baseSource;803this.zone = zone;804}805@Override806public ZoneId getZone() {807return zone;808}809@Override810public Clock withZone(ZoneId zone) {811if (zone.equals(this.zone)) { // intentional NPE812return this;813}814return new SourceClock(baseSource, zone);815}816@Override817public long millis() {818return baseSource.millis();819}820@Override821public Instant instant() {822return baseSource.instant();823}824@Override825public boolean equals(Object obj) {826return (obj instanceof SourceClock other)827&& zone.equals(other.zone)828&& baseSource.equals(other.baseSource);829}830@Override831public int hashCode() {832return baseSource.hashCode() ^ zone.hashCode();833}834@Override835public String toString() {836return "SourceClock[" + baseSource + "," + zone + "]";837}838}839840}841842843