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  * <h3>Specification for implementors</h3>
 107  * This abstract class must be implemented with care to ensure other 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  * If the implementation wraps a source that provides leap second information, then a mechanism
 117  * should be used to "smooth" the leap second, such as UTC-SLS.
 118  * <p>
 119  * Implementations should implement {@code Serializable} wherever possible and must
 120  * document whether or not they do support serialization.
 121  *
 122  * @since 1.8
 123  */
 124 public abstract class Clock {
 125 
 126     /**
 127      * Obtains a clock that returns the current instant using the best available
 128      * system clock, converting to date and time using the UTC time-zone.
 129      * <p>
 130      * This clock, rather than {@link #systemDefaultZone()}, should be used when
 131      * you need the current instant without the date or time.
 132      * <p>
 133      * This clock is based on the best available system clock.
 134      * This may use {@link System#currentTimeMillis()}, or a higher resolution
 135      * clock if one is available.
 136      * <p>
 137      * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
 138      * <p>
 139      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 140      * It is equivalent to {@code system(ZoneOffset.UTC)}.
 141      *
 142      * @return a clock that uses the best available system clock in the UTC zone, not null
 143      */
 144     public static Clock systemUTC() {
 145         return new SystemClock(ZoneOffset.UTC);
 146     }
 147 
 148     /**
 149      * Obtains a clock that returns the current instant using the best available
 150      * system clock, converting to date and time using the default time-zone.
 151      * <p>
 152      * This clock is based on the best available system clock.
 153      * This may use {@link System#currentTimeMillis()}, or a higher resolution
 154      * clock if one is available.
 155      * <p>
 156      * Using this method hard codes a dependency to the default time-zone into your application.
 157      * It is recommended to avoid this and use a specific time-zone whenever possible.
 158      * The {@link #systemUTC() UTC clock} should be used when you need the current instant
 159      * without the date or time.
 160      * <p>
 161      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 162      * It is equivalent to {@code system(ZoneId.systemDefault())}.
 163      *
 164      * @return a clock that uses the best available system clock in the default zone, not null
 165      * @see ZoneId#systemDefault()
 166      */
 167     public static Clock systemDefaultZone() {
 168         return new SystemClock(ZoneId.systemDefault());
 169     }
 170 
 171     /**
 172      * Obtains a clock that returns the current instant using best available
 173      * system clock.
 174      * <p>
 175      * This clock is based on the best available system clock.
 176      * This may use {@link System#currentTimeMillis()}, or a higher resolution
 177      * clock if one is available.
 178      * <p>
 179      * Conversion from instant to date or time uses the specified time-zone.
 180      * <p>
 181      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 182      *
 183      * @param zone  the time-zone to use to convert the instant to date-time, not null
 184      * @return a clock that uses the best available system clock in the specified zone, not null
 185      */
 186     public static Clock system(ZoneId zone) {
 187         Objects.requireNonNull(zone, "zone");
 188         return new SystemClock(zone);
 189     }
 190 
 191     //-------------------------------------------------------------------------
 192     /**
 193      * Obtains a clock that returns the current instant ticking in whole seconds
 194      * using best available system clock.
 195      * <p>
 196      * This clock will always have the nano-of-second field set to zero.
 197      * This ensures that the visible time ticks in whole seconds.
 198      * The underlying clock is the best available system clock, equivalent to
 199      * using {@link #system(ZoneId)}.
 200      * <p>
 201      * Implementations may use a caching strategy for performance reasons.
 202      * As such, it is possible that the start of the second observed via this
 203      * clock will be later than that observed directly via the underlying clock.
 204      * <p>
 205      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 206      * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
 207      *
 208      * @param zone  the time-zone to use to convert the instant to date-time, not null
 209      * @return a clock that ticks in whole seconds using the specified zone, not null
 210      */
 211     public static Clock tickSeconds(ZoneId zone) {
 212         return new TickClock(system(zone), NANOS_PER_SECOND);
 213     }
 214 
 215     /**
 216      * Obtains a clock that returns the current instant ticking in whole minutes
 217      * using best available system clock.
 218      * <p>
 219      * This clock will always have the nano-of-second and second-of-minute fields set to zero.
 220      * This ensures that the visible time ticks in whole minutes.
 221      * The underlying clock is the best available system clock, equivalent to
 222      * using {@link #system(ZoneId)}.
 223      * <p>
 224      * Implementations may use a caching strategy for performance reasons.
 225      * As such, it is possible that the start of the minute observed via this
 226      * clock will be later than that observed directly via the underlying clock.
 227      * <p>
 228      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 229      * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
 230      *
 231      * @param zone  the time-zone to use to convert the instant to date-time, not null
 232      * @return a clock that ticks in whole minutes using the specified zone, not null
 233      */
 234     public static Clock tickMinutes(ZoneId zone) {
 235         return new TickClock(system(zone), NANOS_PER_MINUTE);
 236     }
 237 
 238     /**
 239      * Obtains a clock that returns instants from the specified clock truncated
 240      * to the nearest occurrence of the specified duration.
 241      * <p>
 242      * This clock will only tick as per the specified duration. Thus, if the duration
 243      * is half a second, the clock will return instants truncated to the half second.
 244      * <p>
 245      * The tick duration must be positive. If it has a part smaller than a whole
 246      * millisecond, then the whole duration must divide into one second without
 247      * leaving a remainder. All normal tick durations will match these criteria,
 248      * including any multiple of hours, minutes, seconds and milliseconds, and
 249      * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
 250      * <p>
 251      * A duration of zero or one nanosecond would have no truncation effect.
 252      * Passing one of these will return the underlying clock.
 253      * <p>
 254      * Implementations may use a caching strategy for performance reasons.
 255      * As such, it is possible that the start of the requested duration observed
 256      * via this clock will be later than that observed directly via the underlying clock.
 257      * <p>
 258      * The returned implementation is immutable, thread-safe and {@code Serializable}
 259      * providing that the base clock is.
 260      *
 261      * @param baseClock  the base clock to base the ticking clock on, not null
 262      * @param tickDuration  the duration of each visible tick, not negative, not null
 263      * @return a clock that ticks in whole units of the duration, not null
 264      * @throws IllegalArgumentException if the duration is negative, or has a
 265      *  part smaller than a whole millisecond such that the whole duration is not
 266      *  divisible into one second
 267      * @throws ArithmeticException if the duration is too large to be represented as nanos
 268      */
 269     public static Clock tick(Clock baseClock, Duration tickDuration) {
 270         Objects.requireNonNull(baseClock, "baseClock");
 271         Objects.requireNonNull(tickDuration, "tickDuration");
 272         if (tickDuration.isNegative()) {
 273             throw new IllegalArgumentException("Tick duration must not be negative");
 274         }
 275         long tickNanos = tickDuration.toNanos();
 276         if (tickNanos % 1000_000 == 0) {
 277             // ok, no fraction of millisecond
 278         } else if (1000_000_000 % tickNanos == 0) {
 279             // ok, divides into one second without remainder
 280         } else {
 281             throw new IllegalArgumentException("Invalid tick duration");
 282         }
 283         if (tickNanos <= 1) {
 284             return baseClock;
 285         }
 286         return new TickClock(baseClock, tickNanos);
 287     }
 288 
 289     //-----------------------------------------------------------------------
 290     /**
 291      * Obtains a clock that always returns the same instant.
 292      * <p>
 293      * This clock simply returns the specified instant.
 294      * As such, it is not a clock in the conventional sense.
 295      * The main use case for this is in testing, where the fixed clock ensures
 296      * tests are not dependent on the current clock.
 297      * <p>
 298      * The returned implementation is immutable, thread-safe and {@code Serializable}.
 299      *
 300      * @param fixedInstant  the instant to use as the clock, not null
 301      * @param zone  the time-zone to use to convert the instant to date-time, not null
 302      * @return a clock that always returns the same instant, not null
 303      */
 304     public static Clock fixed(Instant fixedInstant, ZoneId zone) {
 305         Objects.requireNonNull(fixedInstant, "fixedInstant");
 306         Objects.requireNonNull(zone, "zone");
 307         return new FixedClock(fixedInstant, zone);
 308     }
 309 
 310     //-------------------------------------------------------------------------
 311     /**
 312      * Obtains a clock that returns instants from the specified clock with the
 313      * specified duration added
 314      * <p>
 315      * This clock wraps another clock, returning instants that are later by the
 316      * specified duration. If the duration is negative, the instants will be
 317      * earlier than the current date and time.
 318      * The main use case for this is to simulate running in the future or in the past.
 319      * <p>
 320      * A duration of zero would have no offsetting effect.
 321      * Passing zero will return the underlying clock.
 322      * <p>
 323      * The returned implementation is immutable, thread-safe and {@code Serializable}
 324      * providing that the base clock is.
 325      *
 326      * @param baseClock  the base clock to add the duration to, not null
 327      * @param offsetDuration  the duration to add, not null
 328      * @return a clock based on the base clock with the duration added, not null
 329      */
 330     public static Clock offset(Clock baseClock, Duration offsetDuration) {
 331         Objects.requireNonNull(baseClock, "baseClock");
 332         Objects.requireNonNull(offsetDuration, "offsetDuration");
 333         if (offsetDuration.equals(Duration.ZERO)) {
 334             return baseClock;
 335         }
 336         return new OffsetClock(baseClock, offsetDuration);
 337     }
 338 
 339     //-----------------------------------------------------------------------
 340     /**
 341      * Constructor accessible by subclasses.
 342      */
 343     protected Clock() {
 344     }
 345 
 346     //-----------------------------------------------------------------------
 347     /**
 348      * Gets the time-zone being used to create dates and times.
 349      * <p>
 350      * A clock will typically obtain the current instant and then convert that
 351      * to a date or time using a time-zone. This method returns the time-zone used.
 352      *
 353      * @return the time-zone being used to interpret instants, not null
 354      */
 355     public abstract ZoneId getZone();
 356 
 357     /**
 358      * Returns a copy of this clock with a different time-zone.
 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 a clock with
 362      * similar properties but using a different time-zone.
 363      *
 364      * @param zone  the time-zone to change to, not null
 365      * @return a clock based on this clock with the specified time-zone, not null
 366      */
 367     public abstract Clock withZone(ZoneId zone);
 368 
 369     //-------------------------------------------------------------------------
 370     /**
 371      * Gets the current millisecond instant of the clock.
 372      * <p>
 373      * This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC.
 374      * This is equivalent to the definition of {@link System#currentTimeMillis()}.
 375      * <p>
 376      * Most applications should avoid this method and use {@link Instant} to represent
 377      * an instant on the time-line rather than a raw millisecond value.
 378      * This method is provided to allow the use of the clock in high performance use cases
 379      * where the creation of an object would be unacceptable.
 380      * <p>
 381      * The default implementation currently calls {@link #instant}.
 382      *
 383      * @return the current millisecond instant from this clock, measured from
 384      *  the Java epoch of 1970-01-01T00:00 UTC, not null
 385      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
 386      */
 387     public long millis() {
 388         return instant().toEpochMilli();
 389     }
 390 
 391     //-----------------------------------------------------------------------
 392     /**
 393      * Gets the current instant of the clock.
 394      * <p>
 395      * This returns an instant representing the current instant as defined by the clock.
 396      *
 397      * @return the current instant from this clock, not null
 398      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
 399      */
 400     public abstract Instant instant();
 401 
 402     //-----------------------------------------------------------------------
 403     /**
 404      * Checks if this clock is equal to another clock.
 405      * <p>
 406      * Clocks should override this method to compare equals based on
 407      * their state and to meet the contract of {@link Object#equals}.
 408      * If not overridden, the behavior is defined by {@link Object#equals}
 409      *
 410      * @param obj  the object to check, null returns false
 411      * @return true if this is equal to the other clock
 412      */
 413     @Override
 414     public boolean equals(Object obj) {
 415         return super.equals(obj);
 416     }
 417 
 418     /**
 419      * A hash code for this clock.
 420      * <p>
 421      * Clocks should override this method based on
 422      * their state and to meet the contract of {@link Object#hashCode}.
 423      * If not overridden, the behavior is defined by {@link Object#hashCode}
 424      *
 425      * @return a suitable hash code
 426      */
 427     @Override
 428     public  int hashCode() {
 429         return super.hashCode();
 430     }
 431 
 432     //-----------------------------------------------------------------------
 433     /**
 434      * Implementation of a clock that always returns the latest time from
 435      * {@link System#currentTimeMillis()}.
 436      */
 437     static final class SystemClock extends Clock implements Serializable {
 438         private static final long serialVersionUID = 6740630888130243051L;
 439         private final ZoneId zone;
 440 
 441         SystemClock(ZoneId zone) {
 442             this.zone = zone;
 443         }
 444         @Override
 445         public ZoneId getZone() {
 446             return zone;
 447         }
 448         @Override
 449         public Clock withZone(ZoneId zone) {
 450             if (zone.equals(this.zone)) {  // intentional NPE
 451                 return this;
 452             }
 453             return new SystemClock(zone);
 454         }
 455         @Override
 456         public long millis() {
 457             return System.currentTimeMillis();
 458         }
 459         @Override
 460         public Instant instant() {
 461             return Instant.ofEpochMilli(millis());
 462         }
 463         @Override
 464         public boolean equals(Object obj) {
 465             if (obj instanceof SystemClock) {
 466                 return zone.equals(((SystemClock) obj).zone);
 467             }
 468             return false;
 469         }
 470         @Override
 471         public int hashCode() {
 472             return zone.hashCode() + 1;
 473         }
 474         @Override
 475         public String toString() {
 476             return "SystemClock[" + zone + "]";
 477         }
 478     }
 479 
 480     //-----------------------------------------------------------------------
 481     /**
 482      * Implementation of a clock that always returns the same instant.
 483      * This is typically used for testing.
 484      */
 485     static final class FixedClock extends Clock implements Serializable {
 486        private static final long serialVersionUID = 7430389292664866958L;
 487         private final Instant instant;
 488         private final ZoneId zone;
 489 
 490         FixedClock(Instant fixedInstant, ZoneId zone) {
 491             this.instant = fixedInstant;
 492             this.zone = zone;
 493         }
 494         @Override
 495         public ZoneId getZone() {
 496             return zone;
 497         }
 498         @Override
 499         public Clock withZone(ZoneId zone) {
 500             if (zone.equals(this.zone)) {  // intentional NPE
 501                 return this;
 502             }
 503             return new FixedClock(instant, zone);
 504         }
 505         @Override
 506         public long millis() {
 507             return instant.toEpochMilli();
 508         }
 509         @Override
 510         public Instant instant() {
 511             return instant;
 512         }
 513         @Override
 514         public boolean equals(Object obj) {
 515             if (obj instanceof FixedClock) {
 516                 FixedClock other = (FixedClock) obj;
 517                 return instant.equals(other.instant) && zone.equals(other.zone);
 518             }
 519             return false;
 520         }
 521         @Override
 522         public int hashCode() {
 523             return instant.hashCode() ^ zone.hashCode();
 524         }
 525         @Override
 526         public String toString() {
 527             return "FixedClock[" + instant + "," + zone + "]";
 528         }
 529     }
 530 
 531     //-----------------------------------------------------------------------
 532     /**
 533      * Implementation of a clock that adds an offset to an underlying clock.
 534      */
 535     static final class OffsetClock extends Clock implements Serializable {
 536        private static final long serialVersionUID = 2007484719125426256L;
 537         private final Clock baseClock;
 538         private final Duration offset;
 539 
 540         OffsetClock(Clock baseClock, Duration offset) {
 541             this.baseClock = baseClock;
 542             this.offset = offset;
 543         }
 544         @Override
 545         public ZoneId getZone() {
 546             return baseClock.getZone();
 547         }
 548         @Override
 549         public Clock withZone(ZoneId zone) {
 550             if (zone.equals(baseClock.getZone())) {  // intentional NPE
 551                 return this;
 552             }
 553             return new OffsetClock(baseClock.withZone(zone), offset);
 554         }
 555         @Override
 556         public long millis() {
 557             return Math.addExact(baseClock.millis(), offset.toMillis());
 558         }
 559         @Override
 560         public Instant instant() {
 561             return baseClock.instant().plus(offset);
 562         }
 563         @Override
 564         public boolean equals(Object obj) {
 565             if (obj instanceof OffsetClock) {
 566                 OffsetClock other = (OffsetClock) obj;
 567                 return baseClock.equals(other.baseClock) && offset.equals(other.offset);
 568             }
 569             return false;
 570         }
 571         @Override
 572         public int hashCode() {
 573             return baseClock.hashCode() ^ offset.hashCode();
 574         }
 575         @Override
 576         public String toString() {
 577             return "OffsetClock[" + baseClock + "," + offset + "]";
 578         }
 579     }
 580 
 581     //-----------------------------------------------------------------------
 582     /**
 583      * Implementation of a clock that adds an offset to an underlying clock.
 584      */
 585     static final class TickClock extends Clock implements Serializable {
 586         private static final long serialVersionUID = 6504659149906368850L;
 587         private final Clock baseClock;
 588         private final long tickNanos;
 589 
 590         TickClock(Clock baseClock, long tickNanos) {
 591             this.baseClock = baseClock;
 592             this.tickNanos = tickNanos;
 593         }
 594         @Override
 595         public ZoneId getZone() {
 596             return baseClock.getZone();
 597         }
 598         @Override
 599         public Clock withZone(ZoneId zone) {
 600             if (zone.equals(baseClock.getZone())) {  // intentional NPE
 601                 return this;
 602             }
 603             return new TickClock(baseClock.withZone(zone), tickNanos);
 604         }
 605         @Override
 606         public long millis() {
 607             long millis = baseClock.millis();
 608             return millis - Math.floorMod(millis, tickNanos / 1000_000L);
 609         }
 610         @Override
 611         public Instant instant() {
 612             if ((tickNanos % 1000_000) == 0) {
 613                 long millis = baseClock.millis();
 614                 return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
 615             }
 616             Instant instant = baseClock.instant();
 617             long nanos = instant.getNano();
 618             long adjust = Math.floorMod(nanos, tickNanos);
 619             return instant.minusNanos(adjust);
 620         }
 621         @Override
 622         public boolean equals(Object obj) {
 623             if (obj instanceof TickClock) {
 624                 TickClock other = (TickClock) obj;
 625                 return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
 626             }
 627             return false;
 628         }
 629         @Override
 630         public int hashCode() {
 631             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
 632         }
 633         @Override
 634         public String toString() {
 635             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
 636         }
 637     }
 638 
 639 }