Home | History | Annotate | Download | only in time
      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 }
    650