• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This file is available under and governed by the GNU General Public
28  * License version 2 only, as published by the Free Software Foundation.
29  * However, the following notice accompanied the original version of this
30  * file:
31  *
32  * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
33  *
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions are met:
38  *
39  *  * Redistributions of source code must retain the above copyright notice,
40  *    this list of conditions and the following disclaimer.
41  *
42  *  * Redistributions in binary form must reproduce the above copyright notice,
43  *    this list of conditions and the following disclaimer in the documentation
44  *    and/or other materials provided with the distribution.
45  *
46  *  * Neither the name of JSR-310 nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61  */
62 package java.time;
63 
64 import static java.time.LocalTime.NANOS_PER_MINUTE;
65 import static java.time.LocalTime.NANOS_PER_SECOND;
66 
67 import java.io.Serializable;
68 import java.util.Objects;
69 import java.util.TimeZone;
70 
71 /**
72  * A clock providing access to the current instant, date and time using a time-zone.
73  * <p>
74  * Instances of this class are used to find the current instant, which can be
75  * interpreted using the stored time-zone to find the current date and time.
76  * As such, a clock can be used instead of {@link System#currentTimeMillis()}
77  * and {@link TimeZone#getDefault()}.
78  * <p>
79  * Use of a {@code Clock} is optional. All key date-time classes also have a
80  * {@code now()} factory method that uses the system clock in the default time zone.
81  * The primary purpose of this abstraction is to allow alternate clocks to be
82  * plugged in as and when required. Applications use an object to obtain the
83  * current time rather than a static method. This can simplify testing.
84  * <p>
85  * Best practice for applications is to pass a {@code Clock} into any method
86  * that requires the current instant. A dependency injection framework is one
87  * way to achieve this:
88  * <pre>
89  *  public class MyBean {
90  *    private Clock clock;  // dependency inject
91  *    ...
92  *    public void process(LocalDate eventDate) {
93  *      if (eventDate.isBefore(LocalDate.now(clock)) {
94  *        ...
95  *      }
96  *    }
97  *  }
98  * </pre>
99  * This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}
100  * or {@link #offset(Clock, Duration) offset} to be used during testing.
101  * <p>
102  * The {@code system} factory methods provide clocks based on the best available
103  * system clock This may use {@link System#currentTimeMillis()}, or a higher
104  * resolution clock if one is available.
105  *
106  * @implSpec
107  * This abstract class must be implemented with care to ensure other classes operate correctly.
108  * All implementations that can be instantiated must be final, immutable and thread-safe.
109  * <p>
110  * The principal methods are defined to allow the throwing of an exception.
111  * In normal use, no exceptions will be thrown, however one possible implementation would be to
112  * obtain the time from a central time server across the network. Obviously, in this case the
113  * lookup could fail, and so the method is permitted to throw an exception.
114  * <p>
115  * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,
116  * as described in {@link Instant}. If the implementation wraps a source that provides leap
117  * second information, then a mechanism should be used to "smooth" the leap second.
118  * The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose
119  * how accurate they are with the time-scale so long as they document how they work.
120  * Implementations are therefore not required to actually perform the UTC-SLS slew or to
121  * otherwise be aware of leap seconds.
122  * <p>
123  * Implementations should implement {@code Serializable} wherever possible and must
124  * document whether or not they do support serialization.
125  *
126  * @implNote
127  * The clock implementation provided here is based on {@link System#currentTimeMillis()}.
128  * That method provides little to no guarantee about the accuracy of the clock.
129  * Applications requiring a more accurate clock must implement this abstract class
130  * themselves using a different external clock, such as an NTP server.
131  *
132  * @since 1.8
133  */
134 public abstract class Clock {
135 
136     /**
137      * Obtains a clock that returns the current instant using the best available
138      * system clock, converting to date and time using the UTC time-zone.
139      * <p>
140      * This clock, rather than {@link #systemDefaultZone()}, should be used when
141      * you need the current instant without the date or time.
142      * <p>
143      * This clock is based on the best available system clock.
144      * This may use {@link System#currentTimeMillis()}, or a higher resolution
145      * clock if one is available.
146      * <p>
147      * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
148      * <p>
149      * The returned implementation is immutable, thread-safe and {@code Serializable}.
150      * It is equivalent to {@code system(ZoneOffset.UTC)}.
151      *
152      * @return a clock that uses the best available system clock in the UTC zone, not null
153      */
systemUTC()154     public static Clock systemUTC() {
155         return new SystemClock(ZoneOffset.UTC);
156     }
157 
158     /**
159      * Obtains a clock that returns the current instant using the best available
160      * system clock, converting to date and time using the default time-zone.
161      * <p>
162      * This clock is based on the best available system clock.
163      * This may use {@link System#currentTimeMillis()}, or a higher resolution
164      * clock if one is available.
165      * <p>
166      * Using this method hard codes a dependency to the default time-zone into your application.
167      * It is recommended to avoid this and use a specific time-zone whenever possible.
168      * The {@link #systemUTC() UTC clock} should be used when you need the current instant
169      * without the date or time.
170      * <p>
171      * The returned implementation is immutable, thread-safe and {@code Serializable}.
172      * It is equivalent to {@code system(ZoneId.systemDefault())}.
173      *
174      * @return a clock that uses the best available system clock in the default zone, not null
175      * @see ZoneId#systemDefault()
176      */
systemDefaultZone()177     public static Clock systemDefaultZone() {
178         return new SystemClock(ZoneId.systemDefault());
179     }
180 
181     /**
182      * Obtains a clock that returns the current instant using best available
183      * system clock.
184      * <p>
185      * This clock is based on the best available system clock.
186      * This may use {@link System#currentTimeMillis()}, or a higher resolution
187      * clock if one is available.
188      * <p>
189      * Conversion from instant to date or time uses the specified time-zone.
190      * <p>
191      * The returned implementation is immutable, thread-safe and {@code Serializable}.
192      *
193      * @param zone  the time-zone to use to convert the instant to date-time, not null
194      * @return a clock that uses the best available system clock in the specified zone, not null
195      */
system(ZoneId zone)196     public static Clock system(ZoneId zone) {
197         Objects.requireNonNull(zone, "zone");
198         return new SystemClock(zone);
199     }
200 
201     //-------------------------------------------------------------------------
202     /**
203      * Obtains a clock that returns the current instant ticking in whole seconds
204      * using best available system clock.
205      * <p>
206      * This clock will always have the nano-of-second field set to zero.
207      * This ensures that the visible time ticks in whole seconds.
208      * The underlying clock is the best available system clock, equivalent to
209      * using {@link #system(ZoneId)}.
210      * <p>
211      * Implementations may use a caching strategy for performance reasons.
212      * As such, it is possible that the start of the second observed via this
213      * clock will be later than that observed directly via the underlying clock.
214      * <p>
215      * The returned implementation is immutable, thread-safe and {@code Serializable}.
216      * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
217      *
218      * @param zone  the time-zone to use to convert the instant to date-time, not null
219      * @return a clock that ticks in whole seconds using the specified zone, not null
220      */
tickSeconds(ZoneId zone)221     public static Clock tickSeconds(ZoneId zone) {
222         return new TickClock(system(zone), NANOS_PER_SECOND);
223     }
224 
225     /**
226      * Obtains a clock that returns the current instant ticking in whole minutes
227      * using best available system clock.
228      * <p>
229      * This clock will always have the nano-of-second and second-of-minute fields set to zero.
230      * This ensures that the visible time ticks in whole minutes.
231      * The underlying clock is the best available system clock, equivalent to
232      * using {@link #system(ZoneId)}.
233      * <p>
234      * Implementations may use a caching strategy for performance reasons.
235      * As such, it is possible that the start of the minute observed via this
236      * clock will be later than that observed directly via the underlying clock.
237      * <p>
238      * The returned implementation is immutable, thread-safe and {@code Serializable}.
239      * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
240      *
241      * @param zone  the time-zone to use to convert the instant to date-time, not null
242      * @return a clock that ticks in whole minutes using the specified zone, not null
243      */
tickMinutes(ZoneId zone)244     public static Clock tickMinutes(ZoneId zone) {
245         return new TickClock(system(zone), NANOS_PER_MINUTE);
246     }
247 
248     /**
249      * Obtains a clock that returns instants from the specified clock truncated
250      * to the nearest occurrence of the specified duration.
251      * <p>
252      * This clock will only tick as per the specified duration. Thus, if the duration
253      * is half a second, the clock will return instants truncated to the half second.
254      * <p>
255      * The tick duration must be positive. If it has a part smaller than a whole
256      * millisecond, then the whole duration must divide into one second without
257      * leaving a remainder. All normal tick durations will match these criteria,
258      * including any multiple of hours, minutes, seconds and milliseconds, and
259      * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
260      * <p>
261      * A duration of zero or one nanosecond would have no truncation effect.
262      * Passing one of these will return the underlying clock.
263      * <p>
264      * Implementations may use a caching strategy for performance reasons.
265      * As such, it is possible that the start of the requested duration observed
266      * via this clock will be later than that observed directly via the underlying clock.
267      * <p>
268      * The returned implementation is immutable, thread-safe and {@code Serializable}
269      * providing that the base clock is.
270      *
271      * @param baseClock  the base clock to base the ticking clock on, not null
272      * @param tickDuration  the duration of each visible tick, not negative, not null
273      * @return a clock that ticks in whole units of the duration, not null
274      * @throws IllegalArgumentException if the duration is negative, or has a
275      *  part smaller than a whole millisecond such that the whole duration is not
276      *  divisible into one second
277      * @throws ArithmeticException if the duration is too large to be represented as nanos
278      */
tick(Clock baseClock, Duration tickDuration)279     public static Clock tick(Clock baseClock, Duration tickDuration) {
280         Objects.requireNonNull(baseClock, "baseClock");
281         Objects.requireNonNull(tickDuration, "tickDuration");
282         if (tickDuration.isNegative()) {
283             throw new IllegalArgumentException("Tick duration must not be negative");
284         }
285         long tickNanos = tickDuration.toNanos();
286         if (tickNanos % 1000_000 == 0) {
287             // ok, no fraction of millisecond
288         } else if (1000_000_000 % tickNanos == 0) {
289             // ok, divides into one second without remainder
290         } else {
291             throw new IllegalArgumentException("Invalid tick duration");
292         }
293         if (tickNanos <= 1) {
294             return baseClock;
295         }
296         return new TickClock(baseClock, tickNanos);
297     }
298 
299     //-----------------------------------------------------------------------
300     /**
301      * Obtains a clock that always returns the same instant.
302      * <p>
303      * This clock simply returns the specified instant.
304      * As such, it is not a clock in the conventional sense.
305      * The main use case for this is in testing, where the fixed clock ensures
306      * tests are not dependent on the current clock.
307      * <p>
308      * The returned implementation is immutable, thread-safe and {@code Serializable}.
309      *
310      * @param fixedInstant  the instant to use as the clock, not null
311      * @param zone  the time-zone to use to convert the instant to date-time, not null
312      * @return a clock that always returns the same instant, not null
313      */
fixed(Instant fixedInstant, ZoneId zone)314     public static Clock fixed(Instant fixedInstant, ZoneId zone) {
315         Objects.requireNonNull(fixedInstant, "fixedInstant");
316         Objects.requireNonNull(zone, "zone");
317         return new FixedClock(fixedInstant, zone);
318     }
319 
320     //-------------------------------------------------------------------------
321     /**
322      * Obtains a clock that returns instants from the specified clock with the
323      * specified duration added
324      * <p>
325      * This clock wraps another clock, returning instants that are later by the
326      * specified duration. If the duration is negative, the instants will be
327      * earlier than the current date and time.
328      * The main use case for this is to simulate running in the future or in the past.
329      * <p>
330      * A duration of zero would have no offsetting effect.
331      * Passing zero will return the underlying clock.
332      * <p>
333      * The returned implementation is immutable, thread-safe and {@code Serializable}
334      * providing that the base clock is.
335      *
336      * @param baseClock  the base clock to add the duration to, not null
337      * @param offsetDuration  the duration to add, not null
338      * @return a clock based on the base clock with the duration added, not null
339      */
offset(Clock baseClock, Duration offsetDuration)340     public static Clock offset(Clock baseClock, Duration offsetDuration) {
341         Objects.requireNonNull(baseClock, "baseClock");
342         Objects.requireNonNull(offsetDuration, "offsetDuration");
343         if (offsetDuration.equals(Duration.ZERO)) {
344             return baseClock;
345         }
346         return new OffsetClock(baseClock, offsetDuration);
347     }
348 
349     //-----------------------------------------------------------------------
350     /**
351      * Constructor accessible by subclasses.
352      */
Clock()353     protected Clock() {
354     }
355 
356     //-----------------------------------------------------------------------
357     /**
358      * Gets the time-zone being used to create dates and times.
359      * <p>
360      * A clock will typically obtain the current instant and then convert that
361      * to a date or time using a time-zone. This method returns the time-zone used.
362      *
363      * @return the time-zone being used to interpret instants, not null
364      */
getZone()365     public abstract ZoneId getZone();
366 
367     /**
368      * Returns a copy of this clock with a different time-zone.
369      * <p>
370      * A clock will typically obtain the current instant and then convert that
371      * to a date or time using a time-zone. This method returns a clock with
372      * similar properties but using a different time-zone.
373      *
374      * @param zone  the time-zone to change to, not null
375      * @return a clock based on this clock with the specified time-zone, not null
376      */
withZone(ZoneId zone)377     public abstract Clock withZone(ZoneId zone);
378 
379     //-------------------------------------------------------------------------
380     /**
381      * Gets the current millisecond instant of the clock.
382      * <p>
383      * This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).
384      * This is equivalent to the definition of {@link System#currentTimeMillis()}.
385      * <p>
386      * Most applications should avoid this method and use {@link Instant} to represent
387      * an instant on the time-line rather than a raw millisecond value.
388      * This method is provided to allow the use of the clock in high performance use cases
389      * where the creation of an object would be unacceptable.
390      * <p>
391      * The default implementation currently calls {@link #instant}.
392      *
393      * @return the current millisecond instant from this clock, measured from
394      *  the Java epoch of 1970-01-01T00:00Z (UTC), not null
395      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
396      */
millis()397     public long millis() {
398         return instant().toEpochMilli();
399     }
400 
401     //-----------------------------------------------------------------------
402     /**
403      * Gets the current instant of the clock.
404      * <p>
405      * This returns an instant representing the current instant as defined by the clock.
406      *
407      * @return the current instant from this clock, not null
408      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
409      */
instant()410     public abstract Instant instant();
411 
412     //-----------------------------------------------------------------------
413     /**
414      * Checks if this clock is equal to another clock.
415      * <p>
416      * Clocks should override this method to compare equals based on
417      * their state and to meet the contract of {@link Object#equals}.
418      * If not overridden, the behavior is defined by {@link Object#equals}
419      *
420      * @param obj  the object to check, null returns false
421      * @return true if this is equal to the other clock
422      */
423     @Override
equals(Object obj)424     public boolean equals(Object obj) {
425         return super.equals(obj);
426     }
427 
428     /**
429      * A hash code for this clock.
430      * <p>
431      * Clocks should override this method based on
432      * their state and to meet the contract of {@link Object#hashCode}.
433      * If not overridden, the behavior is defined by {@link Object#hashCode}
434      *
435      * @return a suitable hash code
436      */
437     @Override
hashCode()438     public  int hashCode() {
439         return super.hashCode();
440     }
441 
442     //-----------------------------------------------------------------------
443     /**
444      * Implementation of a clock that always returns the latest time from
445      * {@link System#currentTimeMillis()}.
446      */
447     static final class SystemClock extends Clock implements Serializable {
448         private static final long serialVersionUID = 6740630888130243051L;
449         private final ZoneId zone;
450 
SystemClock(ZoneId zone)451         SystemClock(ZoneId zone) {
452             this.zone = zone;
453         }
454         @Override
getZone()455         public ZoneId getZone() {
456             return zone;
457         }
458         @Override
withZone(ZoneId zone)459         public Clock withZone(ZoneId zone) {
460             if (zone.equals(this.zone)) {  // intentional NPE
461                 return this;
462             }
463             return new SystemClock(zone);
464         }
465         @Override
millis()466         public long millis() {
467             return System.currentTimeMillis();
468         }
469         @Override
instant()470         public Instant instant() {
471             return Instant.ofEpochMilli(millis());
472         }
473         @Override
equals(Object obj)474         public boolean equals(Object obj) {
475             if (obj instanceof SystemClock) {
476                 return zone.equals(((SystemClock) obj).zone);
477             }
478             return false;
479         }
480         @Override
hashCode()481         public int hashCode() {
482             return zone.hashCode() + 1;
483         }
484         @Override
toString()485         public String toString() {
486             return "SystemClock[" + zone + "]";
487         }
488     }
489 
490     //-----------------------------------------------------------------------
491     /**
492      * Implementation of a clock that always returns the same instant.
493      * This is typically used for testing.
494      */
495     static final class FixedClock extends Clock implements Serializable {
496        private static final long serialVersionUID = 7430389292664866958L;
497         private final Instant instant;
498         private final ZoneId zone;
499 
FixedClock(Instant fixedInstant, ZoneId zone)500         FixedClock(Instant fixedInstant, ZoneId zone) {
501             this.instant = fixedInstant;
502             this.zone = zone;
503         }
504         @Override
getZone()505         public ZoneId getZone() {
506             return zone;
507         }
508         @Override
withZone(ZoneId zone)509         public Clock withZone(ZoneId zone) {
510             if (zone.equals(this.zone)) {  // intentional NPE
511                 return this;
512             }
513             return new FixedClock(instant, zone);
514         }
515         @Override
millis()516         public long millis() {
517             return instant.toEpochMilli();
518         }
519         @Override
instant()520         public Instant instant() {
521             return instant;
522         }
523         @Override
equals(Object obj)524         public boolean equals(Object obj) {
525             if (obj instanceof FixedClock) {
526                 FixedClock other = (FixedClock) obj;
527                 return instant.equals(other.instant) && zone.equals(other.zone);
528             }
529             return false;
530         }
531         @Override
hashCode()532         public int hashCode() {
533             return instant.hashCode() ^ zone.hashCode();
534         }
535         @Override
toString()536         public String toString() {
537             return "FixedClock[" + instant + "," + zone + "]";
538         }
539     }
540 
541     //-----------------------------------------------------------------------
542     /**
543      * Implementation of a clock that adds an offset to an underlying clock.
544      */
545     static final class OffsetClock extends Clock implements Serializable {
546        private static final long serialVersionUID = 2007484719125426256L;
547         private final Clock baseClock;
548         private final Duration offset;
549 
OffsetClock(Clock baseClock, Duration offset)550         OffsetClock(Clock baseClock, Duration offset) {
551             this.baseClock = baseClock;
552             this.offset = offset;
553         }
554         @Override
getZone()555         public ZoneId getZone() {
556             return baseClock.getZone();
557         }
558         @Override
withZone(ZoneId zone)559         public Clock withZone(ZoneId zone) {
560             if (zone.equals(baseClock.getZone())) {  // intentional NPE
561                 return this;
562             }
563             return new OffsetClock(baseClock.withZone(zone), offset);
564         }
565         @Override
millis()566         public long millis() {
567             return Math.addExact(baseClock.millis(), offset.toMillis());
568         }
569         @Override
instant()570         public Instant instant() {
571             return baseClock.instant().plus(offset);
572         }
573         @Override
equals(Object obj)574         public boolean equals(Object obj) {
575             if (obj instanceof OffsetClock) {
576                 OffsetClock other = (OffsetClock) obj;
577                 return baseClock.equals(other.baseClock) && offset.equals(other.offset);
578             }
579             return false;
580         }
581         @Override
hashCode()582         public int hashCode() {
583             return baseClock.hashCode() ^ offset.hashCode();
584         }
585         @Override
toString()586         public String toString() {
587             return "OffsetClock[" + baseClock + "," + offset + "]";
588         }
589     }
590 
591     //-----------------------------------------------------------------------
592     /**
593      * Implementation of a clock that adds an offset to an underlying clock.
594      */
595     static final class TickClock extends Clock implements Serializable {
596         private static final long serialVersionUID = 6504659149906368850L;
597         private final Clock baseClock;
598         private final long tickNanos;
599 
TickClock(Clock baseClock, long tickNanos)600         TickClock(Clock baseClock, long tickNanos) {
601             this.baseClock = baseClock;
602             this.tickNanos = tickNanos;
603         }
604         @Override
getZone()605         public ZoneId getZone() {
606             return baseClock.getZone();
607         }
608         @Override
withZone(ZoneId zone)609         public Clock withZone(ZoneId zone) {
610             if (zone.equals(baseClock.getZone())) {  // intentional NPE
611                 return this;
612             }
613             return new TickClock(baseClock.withZone(zone), tickNanos);
614         }
615         @Override
millis()616         public long millis() {
617             long millis = baseClock.millis();
618             return millis - Math.floorMod(millis, tickNanos / 1000_000L);
619         }
620         @Override
instant()621         public Instant instant() {
622             if ((tickNanos % 1000_000) == 0) {
623                 long millis = baseClock.millis();
624                 return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
625             }
626             Instant instant = baseClock.instant();
627             long nanos = instant.getNano();
628             long adjust = Math.floorMod(nanos, tickNanos);
629             return instant.minusNanos(adjust);
630         }
631         @Override
equals(Object obj)632         public boolean equals(Object obj) {
633             if (obj instanceof TickClock) {
634                 TickClock other = (TickClock) obj;
635                 return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
636             }
637             return false;
638         }
639         @Override
hashCode()640         public int hashCode() {
641             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
642         }
643         @Override
toString()644         public String toString() {
645             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
646         }
647     }
648 
649 }
650