• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2021, 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 java.io.IOException;
65 import java.io.ObjectInputStream;
66 import java.io.ObjectStreamException;
67 
68 import static java.time.LocalTime.NANOS_PER_MINUTE;
69 import static java.time.LocalTime.NANOS_PER_SECOND;
70 import static java.time.LocalTime.NANOS_PER_MILLI;
71 import java.io.Serializable;
72 import java.util.Objects;
73 import java.util.TimeZone;
74 import jdk.internal.misc.VM;
75 
76 /**
77  * A clock providing access to the current instant, date and time using a time-zone.
78  * <p>
79  * Instances of this abstract class are used to access a pluggable representation of the
80  * current instant, which can be interpreted using the stored time-zone to find the
81  * current date and time.
82  * For example, {@code Clock} can be used instead of {@link System#currentTimeMillis()}
83  * and {@link TimeZone#getDefault()}.
84  * <p>
85  * Use of a {@code Clock} is optional. All key date-time classes also have a
86  * {@code now()} factory method that uses the system clock in the default time zone.
87  * The primary purpose of this abstraction is to allow alternate clocks to be
88  * plugged in as and when required. Applications use an object to obtain the
89  * current time rather than a static method. This can simplify testing.
90  * <p>
91  * As such, this abstract class does not guarantee the result actually represents the current instant
92  * on the time-line. Instead, it allows the application to provide a controlled view as to what
93  * the current instant and time-zone are.
94  * <p>
95  * Best practice for applications is to pass a {@code Clock} into any method
96  * that requires the current instant and time-zone. A dependency injection framework
97  * is one way to achieve this:
98  * <pre>
99  *  public class MyBean {
100  *    private Clock clock;  // dependency inject
101  *    ...
102  *    public void process(LocalDate eventDate) {
103  *      if (eventDate.isBefore(LocalDate.now(clock)) {
104  *        ...
105  *      }
106  *    }
107  *  }
108  * </pre>
109  * This approach allows an alternative clock, such as {@link #fixed(Instant, ZoneId) fixed}
110  * or {@link #offset(Clock, Duration) offset} to be used during testing.
111  * <p>
112  * The {@code system} factory methods provide clocks based on the best available
113  * system clock. This may use {@link System#currentTimeMillis()}, or a higher
114  * resolution clock if one is available.
115  *
116  * @implSpec
117  * This abstract class must be implemented with care to ensure other classes operate correctly.
118  * All implementations must be thread-safe - a single instance must be capable of be invoked
119  * from multiple threads without negative consequences such as race conditions.
120  * <p>
121  * The principal methods are defined to allow the throwing of an exception.
122  * In normal use, no exceptions will be thrown, however one possible implementation would be to
123  * obtain the time from a central time server across the network. Obviously, in this case the
124  * lookup could fail, and so the method is permitted to throw an exception.
125  * <p>
126  * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,
127  * as described in {@link Instant}. If the implementation wraps a source that provides leap
128  * second information, then a mechanism should be used to "smooth" the leap second.
129  * The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose
130  * how accurate they are with the time-scale so long as they document how they work.
131  * Implementations are therefore not required to actually perform the UTC-SLS slew or to
132  * otherwise be aware of leap seconds.
133  * <p>
134  * Implementations should implement {@code Serializable} wherever possible and must
135  * document whether or not they do support serialization.
136  *
137  * @since 1.8
138  */
139 public abstract class Clock implements InstantSource {
140 
141     /**
142      * Obtains a clock that returns the current instant using the best available
143      * system clock, converting to date and time using the UTC time-zone.
144      * <p>
145      * This clock, rather than {@link #systemDefaultZone()}, should be used when
146      * you need the current instant without the date or time.
147      * <p>
148      * This clock is based on the best available system clock.
149      * This may use {@link System#currentTimeMillis()}, or a higher resolution
150      * clock if one is available.
151      * <p>
152      * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
153      * <p>
154      * The returned implementation is immutable, thread-safe and {@code Serializable}.
155      * It is equivalent to {@code system(ZoneOffset.UTC)}.
156      *
157      * @return a clock that uses the best available system clock in the UTC zone, not null
158      */
systemUTC()159     public static Clock systemUTC() {
160         return SystemClock.UTC;
161     }
162 
163     /**
164      * Obtains a clock that returns the current instant using the best available
165      * system clock, converting to date and time using the default time-zone.
166      * <p>
167      * This clock is based on the best available system clock.
168      * This may use {@link System#currentTimeMillis()}, or a higher resolution
169      * clock if one is available.
170      * <p>
171      * Using this method hard codes a dependency to the default time-zone into your application.
172      * It is recommended to avoid this and use a specific time-zone whenever possible.
173      * The {@link #systemUTC() UTC clock} should be used when you need the current instant
174      * without the date or time.
175      * <p>
176      * The returned implementation is immutable, thread-safe and {@code Serializable}.
177      * It is equivalent to {@code system(ZoneId.systemDefault())}.
178      *
179      * @return a clock that uses the best available system clock in the default zone, not null
180      * @see ZoneId#systemDefault()
181      */
systemDefaultZone()182     public static Clock systemDefaultZone() {
183         return new SystemClock(ZoneId.systemDefault());
184     }
185 
186     /**
187      * Obtains a clock that returns the current instant using the best available
188      * system clock.
189      * <p>
190      * This clock is based on the best available system clock.
191      * This may use {@link System#currentTimeMillis()}, or a higher resolution
192      * clock if one is available.
193      * <p>
194      * Conversion from instant to date or time uses the specified time-zone.
195      * <p>
196      * The returned implementation is immutable, thread-safe and {@code Serializable}.
197      *
198      * @param zone  the time-zone to use to convert the instant to date-time, not null
199      * @return a clock that uses the best available system clock in the specified zone, not null
200      */
system(ZoneId zone)201     public static Clock system(ZoneId zone) {
202         Objects.requireNonNull(zone, "zone");
203         if (zone == ZoneOffset.UTC) {
204             return SystemClock.UTC;
205         }
206         return new SystemClock(zone);
207     }
208 
209     //-------------------------------------------------------------------------
210     /**
211      * Obtains a clock that returns the current instant ticking in whole milliseconds
212      * using the best available system clock.
213      * <p>
214      * This clock will always have the nano-of-second field truncated to milliseconds.
215      * This ensures that the visible time ticks in whole milliseconds.
216      * The underlying clock is the best available system clock, equivalent to
217      * using {@link #system(ZoneId)}.
218      * <p>
219      * Implementations may use a caching strategy for performance reasons.
220      * As such, it is possible that the start of the millisecond observed via this
221      * clock will be later than that observed directly via the underlying clock.
222      * <p>
223      * The returned implementation is immutable, thread-safe and {@code Serializable}.
224      * It is equivalent to {@code tick(system(zone), Duration.ofMillis(1))}.
225      *
226      * @param zone  the time-zone to use to convert the instant to date-time, not null
227      * @return a clock that ticks in whole milliseconds using the specified zone, not null
228      * @since 9
229      */
tickMillis(ZoneId zone)230     public static Clock tickMillis(ZoneId zone) {
231         return new TickClock(system(zone), NANOS_PER_MILLI);
232     }
233 
234     //-------------------------------------------------------------------------
235     /**
236      * Obtains a clock that returns the current instant ticking in whole seconds
237      * using the best available system clock.
238      * <p>
239      * This clock will always have the nano-of-second field set to zero.
240      * This ensures that the visible time ticks in whole seconds.
241      * The underlying clock is the best available system clock, equivalent to
242      * using {@link #system(ZoneId)}.
243      * <p>
244      * Implementations may use a caching strategy for performance reasons.
245      * As such, it is possible that the start of the second observed via this
246      * clock will be later than that observed directly via the underlying clock.
247      * <p>
248      * The returned implementation is immutable, thread-safe and {@code Serializable}.
249      * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
250      *
251      * @param zone  the time-zone to use to convert the instant to date-time, not null
252      * @return a clock that ticks in whole seconds using the specified zone, not null
253      */
tickSeconds(ZoneId zone)254     public static Clock tickSeconds(ZoneId zone) {
255         return new TickClock(system(zone), NANOS_PER_SECOND);
256     }
257 
258     /**
259      * Obtains a clock that returns the current instant ticking in whole minutes
260      * using the best available system clock.
261      * <p>
262      * This clock will always have the nano-of-second and second-of-minute fields set to zero.
263      * This ensures that the visible time ticks in whole minutes.
264      * The underlying clock is the best available system clock, equivalent to
265      * using {@link #system(ZoneId)}.
266      * <p>
267      * Implementations may use a caching strategy for performance reasons.
268      * As such, it is possible that the start of the minute observed via this
269      * clock will be later than that observed directly via the underlying clock.
270      * <p>
271      * The returned implementation is immutable, thread-safe and {@code Serializable}.
272      * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
273      *
274      * @param zone  the time-zone to use to convert the instant to date-time, not null
275      * @return a clock that ticks in whole minutes using the specified zone, not null
276      */
tickMinutes(ZoneId zone)277     public static Clock tickMinutes(ZoneId zone) {
278         return new TickClock(system(zone), NANOS_PER_MINUTE);
279     }
280 
281     /**
282      * Obtains a clock that returns instants from the specified clock truncated
283      * to the nearest occurrence of the specified duration.
284      * <p>
285      * This clock will only tick as per the specified duration. Thus, if the duration
286      * is half a second, the clock will return instants truncated to the half second.
287      * <p>
288      * The tick duration must be positive. If it has a part smaller than a whole
289      * millisecond, then the whole duration must divide into one second without
290      * leaving a remainder. All normal tick durations will match these criteria,
291      * including any multiple of hours, minutes, seconds and milliseconds, and
292      * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
293      * <p>
294      * A duration of zero or one nanosecond would have no truncation effect.
295      * Passing one of these will return the underlying clock.
296      * <p>
297      * Implementations may use a caching strategy for performance reasons.
298      * As such, it is possible that the start of the requested duration observed
299      * via this clock will be later than that observed directly via the underlying clock.
300      * <p>
301      * The returned implementation is immutable, thread-safe and {@code Serializable}
302      * providing that the base clock is.
303      *
304      * @param baseClock  the base clock to base the ticking clock on, not null
305      * @param tickDuration  the duration of each visible tick, not negative, not null
306      * @return a clock that ticks in whole units of the duration, not null
307      * @throws IllegalArgumentException if the duration is negative, or has a
308      *  part smaller than a whole millisecond such that the whole duration is not
309      *  divisible into one second
310      * @throws ArithmeticException if the duration is too large to be represented as nanos
311      */
tick(Clock baseClock, Duration tickDuration)312     public static Clock tick(Clock baseClock, Duration tickDuration) {
313         Objects.requireNonNull(baseClock, "baseClock");
314         Objects.requireNonNull(tickDuration, "tickDuration");
315         if (tickDuration.isNegative()) {
316             throw new IllegalArgumentException("Tick duration must not be negative");
317         }
318         long tickNanos = tickDuration.toNanos();
319         if (tickNanos % 1000_000 == 0) {
320             // ok, no fraction of millisecond
321         } else if (1000_000_000 % tickNanos == 0) {
322             // ok, divides into one second without remainder
323         } else {
324             throw new IllegalArgumentException("Invalid tick duration");
325         }
326         if (tickNanos <= 1) {
327             return baseClock;
328         }
329         return new TickClock(baseClock, tickNanos);
330     }
331 
332     //-----------------------------------------------------------------------
333     /**
334      * Obtains a clock that always returns the same instant.
335      * <p>
336      * This clock simply returns the specified instant.
337      * As such, it is not a clock in the conventional sense.
338      * The main use case for this is in testing, where the fixed clock ensures
339      * tests are not dependent on the current clock.
340      * <p>
341      * The returned implementation is immutable, thread-safe and {@code Serializable}.
342      *
343      * @param fixedInstant  the instant to use as the clock, not null
344      * @param zone  the time-zone to use to convert the instant to date-time, not null
345      * @return a clock that always returns the same instant, not null
346      */
fixed(Instant fixedInstant, ZoneId zone)347     public static Clock fixed(Instant fixedInstant, ZoneId zone) {
348         Objects.requireNonNull(fixedInstant, "fixedInstant");
349         Objects.requireNonNull(zone, "zone");
350         return new FixedClock(fixedInstant, zone);
351     }
352 
353     //-------------------------------------------------------------------------
354     /**
355      * Obtains a clock that returns instants from the specified clock with the
356      * specified duration added.
357      * <p>
358      * This clock wraps another clock, returning instants that are later by the
359      * specified duration. If the duration is negative, the instants will be
360      * earlier than the current date and time.
361      * The main use case for this is to simulate running in the future or in the past.
362      * <p>
363      * A duration of zero would have no offsetting effect.
364      * Passing zero will return the underlying clock.
365      * <p>
366      * The returned implementation is immutable, thread-safe and {@code Serializable}
367      * providing that the base clock is.
368      *
369      * @param baseClock  the base clock to add the duration to, not null
370      * @param offsetDuration  the duration to add, not null
371      * @return a clock based on the base clock with the duration added, not null
372      */
offset(Clock baseClock, Duration offsetDuration)373     public static Clock offset(Clock baseClock, Duration offsetDuration) {
374         Objects.requireNonNull(baseClock, "baseClock");
375         Objects.requireNonNull(offsetDuration, "offsetDuration");
376         if (offsetDuration.equals(Duration.ZERO)) {
377             return baseClock;
378         }
379         return new OffsetClock(baseClock, offsetDuration);
380     }
381 
382     //-----------------------------------------------------------------------
383     /**
384      * Constructor accessible by subclasses.
385      */
Clock()386     protected Clock() {
387     }
388 
389     //-----------------------------------------------------------------------
390     /**
391      * Gets the time-zone being used to create dates and times.
392      * <p>
393      * A clock will typically obtain the current instant and then convert that
394      * to a date or time using a time-zone. This method returns the time-zone used.
395      *
396      * @return the time-zone being used to interpret instants, not null
397      */
getZone()398     public abstract ZoneId getZone();
399 
400     /**
401      * Returns a copy of this clock with a different time-zone.
402      * <p>
403      * A clock will typically obtain the current instant and then convert that
404      * to a date or time using a time-zone. This method returns a clock with
405      * similar properties but using a different time-zone.
406      *
407      * @param zone  the time-zone to change to, not null
408      * @return a clock based on this clock with the specified time-zone, not null
409      */
410     @Override
withZone(ZoneId zone)411     public abstract Clock withZone(ZoneId zone);
412 
413     //-------------------------------------------------------------------------
414     /**
415      * Gets the current millisecond instant of the clock.
416      * <p>
417      * This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).
418      * This is equivalent to the definition of {@link System#currentTimeMillis()}.
419      * <p>
420      * Most applications should avoid this method and use {@link Instant} to represent
421      * an instant on the time-line rather than a raw millisecond value.
422      * This method is provided to allow the use of the clock in high performance use cases
423      * where the creation of an object would be unacceptable.
424      * <p>
425      * The default implementation currently calls {@link #instant}.
426      *
427      * @return the current millisecond instant from this clock, measured from
428      *  the Java epoch of 1970-01-01T00:00Z (UTC), not null
429      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
430      */
431     @Override
millis()432     public long millis() {
433         return instant().toEpochMilli();
434     }
435 
436     //-----------------------------------------------------------------------
437     /**
438      * Gets the current instant of the clock.
439      * <p>
440      * This returns an instant representing the current instant as defined by the clock.
441      *
442      * @return the current instant from this clock, not null
443      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
444      */
445     @Override
instant()446     public abstract Instant instant();
447 
448     //-----------------------------------------------------------------------
449     /**
450      * Checks if this clock is equal to another clock.
451      * <p>
452      * Clocks should override this method to compare equals based on
453      * their state and to meet the contract of {@link Object#equals}.
454      * If not overridden, the behavior is defined by {@link Object#equals}
455      *
456      * @param obj  the object to check, null returns false
457      * @return true if this is equal to the other clock
458      */
459     @Override
equals(Object obj)460     public boolean equals(Object obj) {
461         return super.equals(obj);
462     }
463 
464     /**
465      * A hash code for this clock.
466      * <p>
467      * Clocks should override this method based on
468      * their state and to meet the contract of {@link Object#hashCode}.
469      * If not overridden, the behavior is defined by {@link Object#hashCode}
470      *
471      * @return a suitable hash code
472      */
473     @Override
hashCode()474     public  int hashCode() {
475         return super.hashCode();
476     }
477 
478     //-----------------------------------------------------------------------
479     // initial offset
480     private static final long OFFSET_SEED = System.currentTimeMillis() / 1000 - 1024;
481     // We don't actually need a volatile here.
482     // We don't care if offset is set or read concurrently by multiple
483     // threads - we just need a value which is 'recent enough' - in other
484     // words something that has been updated at least once in the last
485     // 2^32 secs (~136 years). And even if we by chance see an invalid
486     // offset, the worst that can happen is that we will get a -1 value
487     // from getNanoTimeAdjustment, forcing us to update the offset
488     // once again.
489     private static long offset = OFFSET_SEED;
490 
currentInstant()491     static Instant currentInstant() {
492         // Take a local copy of offset. offset can be updated concurrently
493         // by other threads (even if we haven't made it volatile) so we will
494         // work with a local copy.
495         long localOffset = offset;
496         long adjustment = VM.getNanoTimeAdjustment(localOffset);
497 
498         if (adjustment == -1) {
499             // -1 is a sentinel value returned by VM.getNanoTimeAdjustment
500             // when the offset it is given is too far off the current UTC
501             // time. In principle, this should not happen unless the
502             // JVM has run for more than ~136 years (not likely) or
503             // someone is fiddling with the system time, or the offset is
504             // by chance at 1ns in the future (very unlikely).
505             // We can easily recover from all these conditions by bringing
506             // back the offset in range and retry.
507 
508             // bring back the offset in range. We use -1024 to make
509             // it more unlikely to hit the 1ns in the future condition.
510             localOffset = System.currentTimeMillis() / 1000 - 1024;
511 
512             // retry
513             adjustment = VM.getNanoTimeAdjustment(localOffset);
514 
515             if (adjustment == -1) {
516                 // Should not happen: we just recomputed a new offset.
517                 // It should have fixed the issue.
518                 throw new InternalError("Offset " + localOffset + " is not in range");
519             } else {
520                 // OK - recovery succeeded. Update the offset for the
521                 // next call...
522                 offset = localOffset;
523             }
524         }
525         return Instant.ofEpochSecond(localOffset, adjustment);
526     }
527 
528     //-----------------------------------------------------------------------
529     /**
530      * An instant source that always returns the latest time from
531      * {@link System#currentTimeMillis()} or equivalent.
532      */
533     static final class SystemInstantSource implements InstantSource, Serializable {
534         @java.io.Serial
535         private static final long serialVersionUID = 3232399674412L;
536         // this is a singleton, but the class is coded such that it is not a
537         // problem if someone hacks around and creates another instance
538         static final SystemInstantSource INSTANCE = new SystemInstantSource();
539 
SystemInstantSource()540         SystemInstantSource() {
541         }
542         @Override
withZone(ZoneId zone)543         public Clock withZone(ZoneId zone) {
544             return Clock.system(zone);
545         }
546         @Override
millis()547         public long millis() {
548             // System.currentTimeMillis() and VM.getNanoTimeAdjustment(offset)
549             // use the same time source - System.currentTimeMillis() simply
550             // limits the resolution to milliseconds.
551             // So we take the faster path and call System.currentTimeMillis()
552             // directly - in order to avoid the performance penalty of
553             // VM.getNanoTimeAdjustment(offset) which is less efficient.
554             return System.currentTimeMillis();
555         }
556         @Override
instant()557         public Instant instant() {
558             return currentInstant();
559         }
560         @Override
equals(Object obj)561         public boolean equals(Object obj) {
562             return obj instanceof SystemInstantSource;
563         }
564         @Override
hashCode()565         public int hashCode() {
566             return SystemInstantSource.class.hashCode();
567         }
568         @Override
toString()569         public String toString() {
570             return "SystemInstantSource";
571         }
572         @java.io.Serial
readResolve()573         private Object readResolve() throws ObjectStreamException {
574             return SystemInstantSource.INSTANCE;
575         }
576     }
577 
578     //-----------------------------------------------------------------------
579     /**
580      * Implementation of a clock that always returns the latest time from
581      * {@code SystemInstantSource.INSTANCE}.
582      */
583     static final class SystemClock extends Clock implements Serializable {
584         @java.io.Serial
585         private static final long serialVersionUID = 6740630888130243051L;
586         static final SystemClock UTC = new SystemClock(ZoneOffset.UTC);
587 
588         private final ZoneId zone;
589 
SystemClock(ZoneId zone)590         SystemClock(ZoneId zone) {
591             this.zone = zone;
592         }
593         @Override
getZone()594         public ZoneId getZone() {
595             return zone;
596         }
597         @Override
withZone(ZoneId zone)598         public Clock withZone(ZoneId zone) {
599             if (zone.equals(this.zone)) {  // intentional NPE
600                 return this;
601             }
602             return new SystemClock(zone);
603         }
604         @Override
millis()605         public long millis() {
606             // inline of SystemInstantSource.INSTANCE.millis()
607             return System.currentTimeMillis();
608         }
609         @Override
instant()610         public Instant instant() {
611             // inline of SystemInstantSource.INSTANCE.instant()
612             return currentInstant();
613         }
614         @Override
equals(Object obj)615         public boolean equals(Object obj) {
616             if (obj instanceof SystemClock) {
617                 return zone.equals(((SystemClock) obj).zone);
618             }
619             return false;
620         }
621         @Override
hashCode()622         public int hashCode() {
623             return zone.hashCode() + 1;
624         }
625         @Override
toString()626         public String toString() {
627             return "SystemClock[" + zone + "]";
628         }
629     }
630 
631     //-----------------------------------------------------------------------
632     /**
633      * Implementation of a clock that always returns the same instant.
634      * This is typically used for testing.
635      */
636     static final class FixedClock extends Clock implements Serializable {
637         @java.io.Serial
638         private static final long serialVersionUID = 7430389292664866958L;
639         private final Instant instant;
640         private final ZoneId zone;
641 
FixedClock(Instant fixedInstant, ZoneId zone)642         FixedClock(Instant fixedInstant, ZoneId zone) {
643             this.instant = fixedInstant;
644             this.zone = zone;
645         }
646         @Override
getZone()647         public ZoneId getZone() {
648             return zone;
649         }
650         @Override
withZone(ZoneId zone)651         public Clock withZone(ZoneId zone) {
652             if (zone.equals(this.zone)) {  // intentional NPE
653                 return this;
654             }
655             return new FixedClock(instant, zone);
656         }
657         @Override
millis()658         public long millis() {
659             return instant.toEpochMilli();
660         }
661         @Override
instant()662         public Instant instant() {
663             return instant;
664         }
665         @Override
equals(Object obj)666         public boolean equals(Object obj) {
667             return obj instanceof FixedClock other
668                     && instant.equals(other.instant)
669                     && zone.equals(other.zone);
670         }
671         @Override
hashCode()672         public int hashCode() {
673             return instant.hashCode() ^ zone.hashCode();
674         }
675         @Override
toString()676         public String toString() {
677             return "FixedClock[" + instant + "," + zone + "]";
678         }
679     }
680 
681     //-----------------------------------------------------------------------
682     /**
683      * Implementation of a clock that adds an offset to an underlying clock.
684      */
685     static final class OffsetClock extends Clock implements Serializable {
686         @java.io.Serial
687         private static final long serialVersionUID = 2007484719125426256L;
688         @SuppressWarnings("serial") // Not statically typed as Serializable
689         private final Clock baseClock;
690         private final Duration offset;
691 
OffsetClock(Clock baseClock, Duration offset)692         OffsetClock(Clock baseClock, Duration offset) {
693             this.baseClock = baseClock;
694             this.offset = offset;
695         }
696         @Override
getZone()697         public ZoneId getZone() {
698             return baseClock.getZone();
699         }
700         @Override
withZone(ZoneId zone)701         public Clock withZone(ZoneId zone) {
702             if (zone.equals(baseClock.getZone())) {  // intentional NPE
703                 return this;
704             }
705             return new OffsetClock(baseClock.withZone(zone), offset);
706         }
707         @Override
millis()708         public long millis() {
709             return Math.addExact(baseClock.millis(), offset.toMillis());
710         }
711         @Override
instant()712         public Instant instant() {
713             return baseClock.instant().plus(offset);
714         }
715         @Override
equals(Object obj)716         public boolean equals(Object obj) {
717             return obj instanceof OffsetClock other
718                     && baseClock.equals(other.baseClock)
719                     && offset.equals(other.offset);
720         }
721         @Override
hashCode()722         public int hashCode() {
723             return baseClock.hashCode() ^ offset.hashCode();
724         }
725         @Override
toString()726         public String toString() {
727             return "OffsetClock[" + baseClock + "," + offset + "]";
728         }
729     }
730 
731     //-----------------------------------------------------------------------
732     /**
733      * Implementation of a clock that reduces the tick frequency of an underlying clock.
734      */
735     static final class TickClock extends Clock implements Serializable {
736         @java.io.Serial
737         private static final long serialVersionUID = 6504659149906368850L;
738         @SuppressWarnings("serial") // Not statically typed as Serializable
739         private final Clock baseClock;
740         private final long tickNanos;
741 
TickClock(Clock baseClock, long tickNanos)742         TickClock(Clock baseClock, long tickNanos) {
743             this.baseClock = baseClock;
744             this.tickNanos = tickNanos;
745         }
746         @Override
getZone()747         public ZoneId getZone() {
748             return baseClock.getZone();
749         }
750         @Override
withZone(ZoneId zone)751         public Clock withZone(ZoneId zone) {
752             if (zone.equals(baseClock.getZone())) {  // intentional NPE
753                 return this;
754             }
755             return new TickClock(baseClock.withZone(zone), tickNanos);
756         }
757         @Override
millis()758         public long millis() {
759             long millis = baseClock.millis();
760             return millis - Math.floorMod(millis, tickNanos / 1000_000L);
761         }
762         @Override
instant()763         public Instant instant() {
764             if ((tickNanos % 1000_000) == 0) {
765                 long millis = baseClock.millis();
766                 return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
767             }
768             Instant instant = baseClock.instant();
769             long nanos = instant.getNano();
770             long adjust = Math.floorMod(nanos, tickNanos);
771             return instant.minusNanos(adjust);
772         }
773         @Override
equals(Object obj)774         public boolean equals(Object obj) {
775             return (obj instanceof TickClock other)
776                     && tickNanos == other.tickNanos
777                     && baseClock.equals(other.baseClock);
778         }
779         @Override
hashCode()780         public int hashCode() {
781             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
782         }
783         @Override
toString()784         public String toString() {
785             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
786         }
787     }
788 
789     //-----------------------------------------------------------------------
790     /**
791      * Implementation of a clock based on an {@code InstantSource}.
792      */
793     static final class SourceClock extends Clock implements Serializable {
794         @java.io.Serial
795         private static final long serialVersionUID = 235386528762398L;
796         @SuppressWarnings("serial") // Not statically typed as Serializable
797         private final InstantSource baseSource;
798         private final ZoneId zone;
799 
SourceClock(InstantSource baseSource, ZoneId zone)800         SourceClock(InstantSource baseSource, ZoneId zone) {
801             this.baseSource = baseSource;
802             this.zone = zone;
803         }
804         @Override
getZone()805         public ZoneId getZone() {
806             return zone;
807         }
808         @Override
withZone(ZoneId zone)809         public Clock withZone(ZoneId zone) {
810             if (zone.equals(this.zone)) {  // intentional NPE
811                 return this;
812             }
813             return new SourceClock(baseSource, zone);
814         }
815         @Override
millis()816         public long millis() {
817             return baseSource.millis();
818         }
819         @Override
instant()820         public Instant instant() {
821             return baseSource.instant();
822         }
823         @Override
equals(Object obj)824         public boolean equals(Object obj) {
825             return (obj instanceof SourceClock other)
826                     && zone.equals(other.zone)
827                     && baseSource.equals(other.baseSource);
828         }
829         @Override
hashCode()830         public int hashCode() {
831             return baseSource.hashCode() ^ zone.hashCode();
832         }
833         @Override
toString()834         public String toString() {
835             return "SourceClock[" + baseSource + "," + zone + "]";
836         }
837     }
838 
839 }
840