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      *
 381      * @return the current millisecond instant from this clock, measured from
 382      *  the Java epoch of 1970-01-01T00:00 UTC, not null
 383      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
 384      */
 385     public abstract long millis();


 386 
 387     //-----------------------------------------------------------------------
 388     /**
 389      * Gets the current instant of the clock.
 390      * <p>
 391      * This returns an instant representing the current instant as defined by the clock.
 392      * <p>
 393      * The default implementation currently calls {@link #millis}.
 394      *
 395      * @return the current instant from this clock, not null
 396      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
 397      */
 398     public Instant instant() {
 399         return Instant.ofEpochMilli(millis());
 400     }
 401 
 402     //-----------------------------------------------------------------------
 403     /**
 404      * Checks if this clock is equal to another clock.
 405      * <p>
 406      * Clocks must compare equal based on their state and behavior.


 407      *
 408      * @param obj  the object to check, null returns false
 409      * @return true if this is equal to the other clock
 410      */
 411     @Override
 412     public abstract boolean equals(Object obj);


 413 
 414     /**
 415      * A hash code for this clock.
 416      *
 417      * @return a suitable hash code
 418      */
 419     @Override
 420     public abstract int hashCode();
 421 
 422     //-----------------------------------------------------------------------
 423     /**
 424      * Returns a string describing this clock.
 425      * <p>
 426      * Clocks must have a string representation based on their state and behavior.
 427      * For example, 'System[Europe/Paris]' could be used to represent the System
 428      * clock in the 'Europe/Paris' time-zone.
 429      *
 430      * @return a string representation of this clock, not null
 431      */
 432     @Override
 433     public abstract String toString();


 434 
 435     //-----------------------------------------------------------------------
 436     /**
 437      * Implementation of a clock that always returns the latest time from
 438      * {@link System#currentTimeMillis()}.
 439      */
 440     static final class SystemClock extends Clock implements Serializable {
 441         private static final long serialVersionUID = 6740630888130243051L;
 442         private final ZoneId zone;
 443 
 444         SystemClock(ZoneId zone) {
 445             this.zone = zone;
 446         }
 447         @Override
 448         public ZoneId getZone() {
 449             return zone;
 450         }
 451         @Override
 452         public Clock withZone(ZoneId zone) {
 453             if (zone.equals(this.zone)) {  // intentional NPE
 454                 return this;
 455             }
 456             return new SystemClock(zone);
 457         }
 458         @Override
 459         public long millis() {
 460             return System.currentTimeMillis();
 461         }
 462         @Override




 463         public boolean equals(Object obj) {
 464             if (obj instanceof SystemClock) {
 465                 return zone.equals(((SystemClock) obj).zone);
 466             }
 467             return false;
 468         }
 469         @Override
 470         public int hashCode() {
 471             return zone.hashCode() + 1;
 472         }
 473         @Override
 474         public String toString() {
 475             return "SystemClock[" + zone + "]";
 476         }
 477     }
 478 
 479     //-----------------------------------------------------------------------
 480     /**
 481      * Implementation of a clock that always returns the same instant.
 482      * This is typically used for testing.
 483      */
 484     static final class FixedClock extends Clock implements Serializable {
 485        private static final long serialVersionUID = 7430389292664866958L;
 486         private final Instant instant;
 487         private final ZoneId zone;
 488 
 489         FixedClock(Instant fixedInstant, ZoneId zone) {
 490             this.instant = fixedInstant;
 491             this.zone = zone;
 492         }
 493         @Override
 494         public ZoneId getZone() {
 495             return zone;
 496         }
 497         @Override
 498         public Clock withZone(ZoneId zone) {
 499             if (zone.equals(this.zone)) {  // intentional NPE
 500                 return this;
 501             }
 502             return new FixedClock(instant, zone);
 503         }
 504         @Override
 505         public long millis() {
 506             return instant.toEpochMilli();
 507         }
 508         @Override
 509         public Instant instant() {
 510             return instant;
 511         }
 512         @Override
 513         public boolean equals(Object obj) {
 514             if (obj instanceof FixedClock) {
 515                 FixedClock other = (FixedClock) obj;
 516                 return instant.equals(other.instant) && zone.equals(other.zone);
 517             }
 518             return false;
 519         }
 520         @Override
 521         public int hashCode() {
 522             return instant.hashCode() ^ zone.hashCode();
 523         }
 524         @Override
 525         public String toString() {
 526             return "FixedClock[" + instant + "," + zone + "]";
 527         }
 528     }
 529 
 530     //-----------------------------------------------------------------------
 531     /**
 532      * Implementation of a clock that adds an offset to an underlying clock.
 533      */
 534     static final class OffsetClock extends Clock implements Serializable {
 535        private static final long serialVersionUID = 2007484719125426256L;
 536         private final Clock baseClock;
 537         private final Duration offset;
 538 
 539         OffsetClock(Clock baseClock, Duration offset) {
 540             this.baseClock = baseClock;
 541             this.offset = offset;
 542         }
 543         @Override
 544         public ZoneId getZone() {
 545             return baseClock.getZone();
 546         }
 547         @Override
 548         public Clock withZone(ZoneId zone) {
 549             if (zone.equals(baseClock.getZone())) {  // intentional NPE
 550                 return this;
 551             }
 552             return new OffsetClock(baseClock.withZone(zone), offset);
 553         }
 554         @Override
 555         public long millis() {
 556             return Math.addExact(baseClock.millis(), offset.toMillis());
 557         }
 558         @Override
 559         public Instant instant() {
 560             return baseClock.instant().plus(offset);
 561         }
 562         @Override
 563         public boolean equals(Object obj) {
 564             if (obj instanceof OffsetClock) {
 565                 OffsetClock other = (OffsetClock) obj;
 566                 return baseClock.equals(other.baseClock) && offset.equals(other.offset);
 567             }
 568             return false;
 569         }
 570         @Override
 571         public int hashCode() {
 572             return baseClock.hashCode() ^ offset.hashCode();
 573         }
 574         @Override
 575         public String toString() {
 576             return "OffsetClock[" + baseClock + "," + offset + "]";
 577         }
 578     }
 579 
 580     //-----------------------------------------------------------------------
 581     /**
 582      * Implementation of a clock that adds an offset to an underlying clock.
 583      */
 584     static final class TickClock extends Clock implements Serializable {
 585         private static final long serialVersionUID = 6504659149906368850L;
 586         private final Clock baseClock;
 587         private final long tickNanos;
 588 
 589         TickClock(Clock baseClock, long tickNanos) {
 590             this.baseClock = baseClock;
 591             this.tickNanos = tickNanos;
 592         }
 593         @Override
 594         public ZoneId getZone() {
 595             return baseClock.getZone();
 596         }
 597         @Override
 598         public Clock withZone(ZoneId zone) {
 599             if (zone.equals(baseClock.getZone())) {  // intentional NPE
 600                 return this;
 601             }
 602             return new TickClock(baseClock.withZone(zone), tickNanos);
 603         }
 604         @Override
 605         public long millis() {
 606             long millis = baseClock.millis();
 607             return millis - Math.floorMod(millis, tickNanos / 1000_000L);
 608         }
 609         @Override
 610         public Instant instant() {
 611             if ((tickNanos % 1000_000) == 0) {
 612                 long millis = baseClock.millis();
 613                 return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
 614             }
 615             Instant instant = baseClock.instant();
 616             long nanos = instant.getNano();
 617             long adjust = Math.floorMod(nanos, tickNanos);
 618             return instant.minusNanos(adjust);
 619         }
 620         @Override
 621         public boolean equals(Object obj) {
 622             if (obj instanceof TickClock) {
 623                 TickClock other = (TickClock) obj;
 624                 return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
 625             }
 626             return false;
 627         }
 628         @Override
 629         public int hashCode() {
 630             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
 631         }
 632         @Override
 633         public String toString() {
 634             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
 635         }
 636     }
 637 
 638 }
--- EOF ---