Path: blob/master/src/java.base/share/classes/java/time/Clock.java
41152 views
/*1* Copyright (c) 2012, 2019, 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 static java.time.LocalTime.NANOS_PER_MINUTE;66import static java.time.LocalTime.NANOS_PER_SECOND;67import static java.time.LocalTime.NANOS_PER_MILLI;68import java.io.Serializable;69import java.util.Objects;70import java.util.TimeZone;71import jdk.internal.misc.VM;7273/**74* A clock providing access to the current instant, date and time using a time-zone.75* <p>76* Instances of this class are used to find the current instant, which can be77* interpreted using the stored time-zone to find the current date and time.78* As such, a clock can be used instead of {@link System#currentTimeMillis()}79* and {@link TimeZone#getDefault()}.80* <p>81* Use of a {@code Clock} is optional. All key date-time classes also have a82* {@code now()} factory method that uses the system clock in the default time zone.83* The primary purpose of this abstraction is to allow alternate clocks to be84* plugged in as and when required. Applications use an object to obtain the85* current time rather than a static method. This can simplify testing.86* <p>87* Best practice for applications is to pass a {@code Clock} into any method88* that requires the current instant. A dependency injection framework is one89* way to achieve this:90* <pre>91* public class MyBean {92* private Clock clock; // dependency inject93* ...94* public void process(LocalDate eventDate) {95* if (eventDate.isBefore(LocalDate.now(clock)) {96* ...97* }98* }99* }100* </pre>101* This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}102* or {@link #offset(Clock, Duration) offset} to be used during testing.103* <p>104* The {@code system} factory methods provide clocks based on the best available105* system clock This may use {@link System#currentTimeMillis()}, or a higher106* resolution clock if one is available.107*108* @implSpec109* This abstract class must be implemented with care to ensure other classes operate correctly.110* All implementations that can be instantiated must be final, immutable and thread-safe.111* <p>112* The principal methods are defined to allow the throwing of an exception.113* In normal use, no exceptions will be thrown, however one possible implementation would be to114* obtain the time from a central time server across the network. Obviously, in this case the115* lookup could fail, and so the method is permitted to throw an exception.116* <p>117* The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,118* as described in {@link Instant}. If the implementation wraps a source that provides leap119* second information, then a mechanism should be used to "smooth" the leap second.120* The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose121* how accurate they are with the time-scale so long as they document how they work.122* Implementations are therefore not required to actually perform the UTC-SLS slew or to123* otherwise be aware of leap seconds.124* <p>125* Implementations should implement {@code Serializable} wherever possible and must126* document whether or not they do support serialization.127*128* @implNote129* The clock implementation provided here is based on the same underlying clock130* as {@link System#currentTimeMillis()}, but may have a precision finer than131* milliseconds if available.132* However, little to no guarantee is provided about the accuracy of the133* underlying clock. Applications requiring a more accurate clock must implement134* this abstract class themselves using a different external clock, such as an135* NTP server.136*137* @since 1.8138*/139public abstract class Clock {140141/**142* Obtains a clock that returns the current instant using the best available143* system clock, converting to date and time using the UTC time-zone.144* <p>145* This clock, rather than {@link #systemDefaultZone()}, should be used when146* you need the current instant without the date or time.147* <p>148* This clock is based on the best available system clock.149* This may use {@link System#currentTimeMillis()}, or a higher resolution150* clock if one is available.151* <p>152* Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.153* <p>154* The returned implementation is immutable, thread-safe and {@code Serializable}.155* It is equivalent to {@code system(ZoneOffset.UTC)}.156*157* @return a clock that uses the best available system clock in the UTC zone, not null158*/159public static Clock systemUTC() {160return SystemClock.UTC;161}162163/**164* Obtains a clock that returns the current instant using the best available165* system clock, converting to date and time using the default time-zone.166* <p>167* This clock is based on the best available system clock.168* This may use {@link System#currentTimeMillis()}, or a higher resolution169* clock if one is available.170* <p>171* Using this method hard codes a dependency to the default time-zone into your application.172* It is recommended to avoid this and use a specific time-zone whenever possible.173* The {@link #systemUTC() UTC clock} should be used when you need the current instant174* without the date or time.175* <p>176* The returned implementation is immutable, thread-safe and {@code Serializable}.177* It is equivalent to {@code system(ZoneId.systemDefault())}.178*179* @return a clock that uses the best available system clock in the default zone, not null180* @see ZoneId#systemDefault()181*/182public static Clock systemDefaultZone() {183return new SystemClock(ZoneId.systemDefault());184}185186/**187* Obtains a clock that returns the current instant using the best available188* system clock.189* <p>190* This clock is based on the best available system clock.191* This may use {@link System#currentTimeMillis()}, or a higher resolution192* clock if one is available.193* <p>194* Conversion from instant to date or time uses the specified time-zone.195* <p>196* The returned implementation is immutable, thread-safe and {@code Serializable}.197*198* @param zone the time-zone to use to convert the instant to date-time, not null199* @return a clock that uses the best available system clock in the specified zone, not null200*/201public static Clock system(ZoneId zone) {202Objects.requireNonNull(zone, "zone");203if (zone == ZoneOffset.UTC) {204return SystemClock.UTC;205}206return new SystemClock(zone);207}208209//-------------------------------------------------------------------------210/**211* Obtains a clock that returns the current instant ticking in whole milliseconds212* using the best available system clock.213* <p>214* This clock will always have the nano-of-second field truncated to milliseconds.215* This ensures that the visible time ticks in whole milliseconds.216* The underlying clock is the best available system clock, equivalent to217* using {@link #system(ZoneId)}.218* <p>219* Implementations may use a caching strategy for performance reasons.220* As such, it is possible that the start of the millisecond observed via this221* clock will be later than that observed directly via the underlying clock.222* <p>223* The returned implementation is immutable, thread-safe and {@code Serializable}.224* It is equivalent to {@code tick(system(zone), Duration.ofMillis(1))}.225*226* @param zone the time-zone to use to convert the instant to date-time, not null227* @return a clock that ticks in whole milliseconds using the specified zone, not null228* @since 9229*/230public static Clock tickMillis(ZoneId zone) {231return new TickClock(system(zone), NANOS_PER_MILLI);232}233234//-------------------------------------------------------------------------235/**236* Obtains a clock that returns the current instant ticking in whole seconds237* using the best available system clock.238* <p>239* This clock will always have the nano-of-second field set to zero.240* This ensures that the visible time ticks in whole seconds.241* The underlying clock is the best available system clock, equivalent to242* using {@link #system(ZoneId)}.243* <p>244* Implementations may use a caching strategy for performance reasons.245* As such, it is possible that the start of the second observed via this246* clock will be later than that observed directly via the underlying clock.247* <p>248* The returned implementation is immutable, thread-safe and {@code Serializable}.249* It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.250*251* @param zone the time-zone to use to convert the instant to date-time, not null252* @return a clock that ticks in whole seconds using the specified zone, not null253*/254public static Clock tickSeconds(ZoneId zone) {255return new TickClock(system(zone), NANOS_PER_SECOND);256}257258/**259* Obtains a clock that returns the current instant ticking in whole minutes260* using the best available system clock.261* <p>262* This clock will always have the nano-of-second and second-of-minute fields set to zero.263* This ensures that the visible time ticks in whole minutes.264* The underlying clock is the best available system clock, equivalent to265* using {@link #system(ZoneId)}.266* <p>267* Implementations may use a caching strategy for performance reasons.268* As such, it is possible that the start of the minute observed via this269* clock will be later than that observed directly via the underlying clock.270* <p>271* The returned implementation is immutable, thread-safe and {@code Serializable}.272* It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.273*274* @param zone the time-zone to use to convert the instant to date-time, not null275* @return a clock that ticks in whole minutes using the specified zone, not null276*/277public static Clock tickMinutes(ZoneId zone) {278return new TickClock(system(zone), NANOS_PER_MINUTE);279}280281/**282* Obtains a clock that returns instants from the specified clock truncated283* to the nearest occurrence of the specified duration.284* <p>285* This clock will only tick as per the specified duration. Thus, if the duration286* is half a second, the clock will return instants truncated to the half second.287* <p>288* The tick duration must be positive. If it has a part smaller than a whole289* millisecond, then the whole duration must divide into one second without290* leaving a remainder. All normal tick durations will match these criteria,291* including any multiple of hours, minutes, seconds and milliseconds, and292* sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.293* <p>294* A duration of zero or one nanosecond would have no truncation effect.295* Passing one of these will return the underlying clock.296* <p>297* Implementations may use a caching strategy for performance reasons.298* As such, it is possible that the start of the requested duration observed299* via this clock will be later than that observed directly via the underlying clock.300* <p>301* The returned implementation is immutable, thread-safe and {@code Serializable}302* providing that the base clock is.303*304* @param baseClock the base clock to base the ticking clock on, not null305* @param tickDuration the duration of each visible tick, not negative, not null306* @return a clock that ticks in whole units of the duration, not null307* @throws IllegalArgumentException if the duration is negative, or has a308* part smaller than a whole millisecond such that the whole duration is not309* divisible into one second310* @throws ArithmeticException if the duration is too large to be represented as nanos311*/312public static Clock tick(Clock baseClock, Duration tickDuration) {313Objects.requireNonNull(baseClock, "baseClock");314Objects.requireNonNull(tickDuration, "tickDuration");315if (tickDuration.isNegative()) {316throw new IllegalArgumentException("Tick duration must not be negative");317}318long tickNanos = tickDuration.toNanos();319if (tickNanos % 1000_000 == 0) {320// ok, no fraction of millisecond321} else if (1000_000_000 % tickNanos == 0) {322// ok, divides into one second without remainder323} else {324throw new IllegalArgumentException("Invalid tick duration");325}326if (tickNanos <= 1) {327return baseClock;328}329return new TickClock(baseClock, tickNanos);330}331332//-----------------------------------------------------------------------333/**334* Obtains a clock that always returns the same instant.335* <p>336* This clock simply returns the specified instant.337* As such, it is not a clock in the conventional sense.338* The main use case for this is in testing, where the fixed clock ensures339* tests are not dependent on the current clock.340* <p>341* The returned implementation is immutable, thread-safe and {@code Serializable}.342*343* @param fixedInstant the instant to use as the clock, not null344* @param zone the time-zone to use to convert the instant to date-time, not null345* @return a clock that always returns the same instant, not null346*/347public static Clock fixed(Instant fixedInstant, ZoneId zone) {348Objects.requireNonNull(fixedInstant, "fixedInstant");349Objects.requireNonNull(zone, "zone");350return new FixedClock(fixedInstant, zone);351}352353//-------------------------------------------------------------------------354/**355* Obtains a clock that returns instants from the specified clock with the356* specified duration added357* <p>358* This clock wraps another clock, returning instants that are later by the359* specified duration. If the duration is negative, the instants will be360* earlier than the current date and time.361* The main use case for this is to simulate running in the future or in the past.362* <p>363* A duration of zero would have no offsetting effect.364* Passing zero will return the underlying clock.365* <p>366* The returned implementation is immutable, thread-safe and {@code Serializable}367* providing that the base clock is.368*369* @param baseClock the base clock to add the duration to, not null370* @param offsetDuration the duration to add, not null371* @return a clock based on the base clock with the duration added, not null372*/373public static Clock offset(Clock baseClock, Duration offsetDuration) {374Objects.requireNonNull(baseClock, "baseClock");375Objects.requireNonNull(offsetDuration, "offsetDuration");376if (offsetDuration.equals(Duration.ZERO)) {377return baseClock;378}379return new OffsetClock(baseClock, offsetDuration);380}381382//-----------------------------------------------------------------------383/**384* Constructor accessible by subclasses.385*/386protected Clock() {387}388389//-----------------------------------------------------------------------390/**391* Gets the time-zone being used to create dates and times.392* <p>393* A clock will typically obtain the current instant and then convert that394* to a date or time using a time-zone. This method returns the time-zone used.395*396* @return the time-zone being used to interpret instants, not null397*/398public abstract ZoneId getZone();399400/**401* Returns a copy of this clock with a different time-zone.402* <p>403* A clock will typically obtain the current instant and then convert that404* to a date or time using a time-zone. This method returns a clock with405* similar properties but using a different time-zone.406*407* @param zone the time-zone to change to, not null408* @return a clock based on this clock with the specified time-zone, not null409*/410public abstract Clock withZone(ZoneId zone);411412//-------------------------------------------------------------------------413/**414* Gets the current millisecond instant of the clock.415* <p>416* This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).417* This is equivalent to the definition of {@link System#currentTimeMillis()}.418* <p>419* Most applications should avoid this method and use {@link Instant} to represent420* an instant on the time-line rather than a raw millisecond value.421* This method is provided to allow the use of the clock in high performance use cases422* where the creation of an object would be unacceptable.423* <p>424* The default implementation currently calls {@link #instant}.425*426* @return the current millisecond instant from this clock, measured from427* the Java epoch of 1970-01-01T00:00Z (UTC), not null428* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations429*/430public long millis() {431return instant().toEpochMilli();432}433434//-----------------------------------------------------------------------435/**436* Gets the current instant of the clock.437* <p>438* This returns an instant representing the current instant as defined by the clock.439*440* @return the current instant from this clock, not null441* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations442*/443public abstract Instant instant();444445//-----------------------------------------------------------------------446/**447* Checks if this clock is equal to another clock.448* <p>449* Clocks should override this method to compare equals based on450* their state and to meet the contract of {@link Object#equals}.451* If not overridden, the behavior is defined by {@link Object#equals}452*453* @param obj the object to check, null returns false454* @return true if this is equal to the other clock455*/456@Override457public boolean equals(Object obj) {458return super.equals(obj);459}460461/**462* A hash code for this clock.463* <p>464* Clocks should override this method based on465* their state and to meet the contract of {@link Object#hashCode}.466* If not overridden, the behavior is defined by {@link Object#hashCode}467*468* @return a suitable hash code469*/470@Override471public int hashCode() {472return super.hashCode();473}474475//-----------------------------------------------------------------------476/**477* Implementation of a clock that always returns the latest time from478* {@link System#currentTimeMillis()}.479*/480static final class SystemClock extends Clock implements Serializable {481@java.io.Serial482private static final long serialVersionUID = 6740630888130243051L;483private static final long OFFSET_SEED =484System.currentTimeMillis()/1000 - 1024; // initial offest485static final SystemClock UTC = new SystemClock(ZoneOffset.UTC);486487private final ZoneId zone;488// We don't actually need a volatile here.489// We don't care if offset is set or read concurrently by multiple490// threads - we just need a value which is 'recent enough' - in other491// words something that has been updated at least once in the last492// 2^32 secs (~136 years). And even if we by chance see an invalid493// offset, the worst that can happen is that we will get a -1 value494// from getNanoTimeAdjustment, forcing us to update the offset495// once again.496private transient long offset;497498SystemClock(ZoneId zone) {499this.zone = zone;500this.offset = OFFSET_SEED;501}502@Override503public ZoneId getZone() {504return zone;505}506@Override507public Clock withZone(ZoneId zone) {508if (zone.equals(this.zone)) { // intentional NPE509return this;510}511return new SystemClock(zone);512}513@Override514public long millis() {515// System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset)516// use the same time source - System.currentTimeMillis() simply517// limits the resolution to milliseconds.518// So we take the faster path and call System.currentTimeMillis()519// directly - in order to avoid the performance penalty of520// VM.getNanoTimeAdjustment(offset) which is less efficient.521return System.currentTimeMillis();522}523@Override524public Instant instant() {525// Take a local copy of offset. offset can be updated concurrently526// by other threads (even if we haven't made it volatile) so we will527// work with a local copy.528long localOffset = offset;529long adjustment = VM.getNanoTimeAdjustment(localOffset);530531if (adjustment == -1) {532// -1 is a sentinel value returned by VM.getNanoTimeAdjustment533// when the offset it is given is too far off the current UTC534// time. In principle, this should not happen unless the535// JVM has run for more than ~136 years (not likely) or536// someone is fiddling with the system time, or the offset is537// by chance at 1ns in the future (very unlikely).538// We can easily recover from all these conditions by bringing539// back the offset in range and retry.540541// bring back the offset in range. We use -1024 to make542// it more unlikely to hit the 1ns in the future condition.543localOffset = System.currentTimeMillis()/1000 - 1024;544545// retry546adjustment = VM.getNanoTimeAdjustment(localOffset);547548if (adjustment == -1) {549// Should not happen: we just recomputed a new offset.550// It should have fixed the issue.551throw new InternalError("Offset " + localOffset + " is not in range");552} else {553// OK - recovery succeeded. Update the offset for the554// next call...555offset = localOffset;556}557}558return Instant.ofEpochSecond(localOffset, adjustment);559}560@Override561public boolean equals(Object obj) {562if (obj instanceof SystemClock) {563return zone.equals(((SystemClock) obj).zone);564}565return false;566}567@Override568public int hashCode() {569return zone.hashCode() + 1;570}571@Override572public String toString() {573return "SystemClock[" + zone + "]";574}575@java.io.Serial576private void readObject(ObjectInputStream is)577throws IOException, ClassNotFoundException {578// ensure that offset is initialized579is.defaultReadObject();580offset = OFFSET_SEED;581}582}583584//-----------------------------------------------------------------------585/**586* Implementation of a clock that always returns the same instant.587* This is typically used for testing.588*/589static final class FixedClock extends Clock implements Serializable {590@java.io.Serial591private static final long serialVersionUID = 7430389292664866958L;592private final Instant instant;593private final ZoneId zone;594595FixedClock(Instant fixedInstant, ZoneId zone) {596this.instant = fixedInstant;597this.zone = zone;598}599@Override600public ZoneId getZone() {601return zone;602}603@Override604public Clock withZone(ZoneId zone) {605if (zone.equals(this.zone)) { // intentional NPE606return this;607}608return new FixedClock(instant, zone);609}610@Override611public long millis() {612return instant.toEpochMilli();613}614@Override615public Instant instant() {616return instant;617}618@Override619public boolean equals(Object obj) {620return obj instanceof FixedClock other621&& instant.equals(other.instant)622&& zone.equals(other.zone);623}624@Override625public int hashCode() {626return instant.hashCode() ^ zone.hashCode();627}628@Override629public String toString() {630return "FixedClock[" + instant + "," + zone + "]";631}632}633634//-----------------------------------------------------------------------635/**636* Implementation of a clock that adds an offset to an underlying clock.637*/638static final class OffsetClock extends Clock implements Serializable {639@java.io.Serial640private static final long serialVersionUID = 2007484719125426256L;641@SuppressWarnings("serial") // Not statically typed as Serializable642private final Clock baseClock;643private final Duration offset;644645OffsetClock(Clock baseClock, Duration offset) {646this.baseClock = baseClock;647this.offset = offset;648}649@Override650public ZoneId getZone() {651return baseClock.getZone();652}653@Override654public Clock withZone(ZoneId zone) {655if (zone.equals(baseClock.getZone())) { // intentional NPE656return this;657}658return new OffsetClock(baseClock.withZone(zone), offset);659}660@Override661public long millis() {662return Math.addExact(baseClock.millis(), offset.toMillis());663}664@Override665public Instant instant() {666return baseClock.instant().plus(offset);667}668@Override669public boolean equals(Object obj) {670return obj instanceof OffsetClock other671&& baseClock.equals(other.baseClock)672&& offset.equals(other.offset);673}674@Override675public int hashCode() {676return baseClock.hashCode() ^ offset.hashCode();677}678@Override679public String toString() {680return "OffsetClock[" + baseClock + "," + offset + "]";681}682}683684//-----------------------------------------------------------------------685/**686* Implementation of a clock that adds an offset to an underlying clock.687*/688static final class TickClock extends Clock implements Serializable {689@java.io.Serial690private static final long serialVersionUID = 6504659149906368850L;691@SuppressWarnings("serial") // Not statically typed as Serializable692private final Clock baseClock;693private final long tickNanos;694695TickClock(Clock baseClock, long tickNanos) {696this.baseClock = baseClock;697this.tickNanos = tickNanos;698}699@Override700public ZoneId getZone() {701return baseClock.getZone();702}703@Override704public Clock withZone(ZoneId zone) {705if (zone.equals(baseClock.getZone())) { // intentional NPE706return this;707}708return new TickClock(baseClock.withZone(zone), tickNanos);709}710@Override711public long millis() {712long millis = baseClock.millis();713return millis - Math.floorMod(millis, tickNanos / 1000_000L);714}715@Override716public Instant instant() {717if ((tickNanos % 1000_000) == 0) {718long millis = baseClock.millis();719return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));720}721Instant instant = baseClock.instant();722long nanos = instant.getNano();723long adjust = Math.floorMod(nanos, tickNanos);724return instant.minusNanos(adjust);725}726@Override727public boolean equals(Object obj) {728return (obj instanceof TickClock other)729&& tickNanos == other.tickNanos730&& baseClock.equals(other.baseClock);731}732@Override733public int hashCode() {734return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));735}736@Override737public String toString() {738return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";739}740}741742}743744745