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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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
 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
 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 
 451         SystemClock(ZoneId zone) {
 452             this.zone = zone;
 453         }
 454         @Override
 455         public ZoneId getZone() {
 456             return zone;
 457         }
 458         @Override
 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
 466         public long millis() {
 467             return System.currentTimeMillis();
 468         }
 469         @Override
 470         public Instant instant() {
 471             return Instant.ofEpochMilli(millis());
 472         }
 473         @Override
 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
 481         public int hashCode() {
 482             return zone.hashCode() + 1;
 483         }
 484         @Override
 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 
 500         FixedClock(Instant fixedInstant, ZoneId zone) {
 501             this.instant = fixedInstant;
 502             this.zone = zone;
 503         }
 504         @Override
 505         public ZoneId getZone() {
 506             return zone;
 507         }
 508         @Override
 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
 516         public long millis() {
 517             return instant.toEpochMilli();
 518         }
 519         @Override
 520         public Instant instant() {
 521             return instant;
 522         }
 523         @Override
 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
 532         public int hashCode() {
 533             return instant.hashCode() ^ zone.hashCode();
 534         }
 535         @Override
 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 
 550         OffsetClock(Clock baseClock, Duration offset) {
 551             this.baseClock = baseClock;
 552             this.offset = offset;
 553         }
 554         @Override
 555         public ZoneId getZone() {
 556             return baseClock.getZone();
 557         }
 558         @Override
 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
 566         public long millis() {
 567             return Math.addExact(baseClock.millis(), offset.toMillis());
 568         }
 569         @Override
 570         public Instant instant() {
 571             return baseClock.instant().plus(offset);
 572         }
 573         @Override
 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
 582         public int hashCode() {
 583             return baseClock.hashCode() ^ offset.hashCode();
 584         }
 585         @Override
 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 
 600         TickClock(Clock baseClock, long tickNanos) {
 601             this.baseClock = baseClock;
 602             this.tickNanos = tickNanos;
 603         }
 604         @Override
 605         public ZoneId getZone() {
 606             return baseClock.getZone();
 607         }
 608         @Override
 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
 616         public long millis() {
 617             long millis = baseClock.millis();
 618             return millis - Math.floorMod(millis, tickNanos / 1000_000L);
 619         }
 620         @Override
 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
 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
 640         public int hashCode() {
 641             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
 642         }
 643         @Override
 644         public String toString() {
 645             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
 646         }
 647     }
 648 
 649 }