• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp;
33 
34 import static org.threeten.bp.LocalTime.NANOS_PER_MINUTE;
35 import static org.threeten.bp.LocalTime.NANOS_PER_SECOND;
36 
37 import java.io.Serializable;
38 import java.util.TimeZone;
39 
40 import org.threeten.bp.jdk8.Jdk8Methods;
41 
42 /**
43  * A clock providing access to the current instant, date and time using a time-zone.
44  * <p>
45  * Instances of this class are used to find the current instant, which can be
46  * interpreted using the stored time-zone to find the current date and time.
47  * As such, a clock can be used instead of {@link System#currentTimeMillis()}
48  * and {@link TimeZone#getDefault()}.
49  * <p>
50  * Use of a {@code Clock} is optional. All key date-time classes also have a
51  * {@code now()} factory method that uses the system clock in the default time zone.
52  * The primary purpose of this abstraction is to allow alternate clocks to be
53  * plugged in as and when required. Applications use an object to obtain the
54  * current time rather than a static method. This can simplify testing.
55  * <p>
56  * Best practice for applications is to pass a {@code Clock} into any method
57  * that requires the current instant. A dependency injection framework is one
58  * way to achieve this:
59  * <pre>
60  *  public class MyBean {
61  *    private Clock clock;  // dependency inject
62  *    ...
63  *    public void process(LocalDate eventDate) {
64  *      if (eventDate.isBefore(LocalDate.now(clock)) {
65  *        ...
66  *      }
67  *    }
68  *  }
69  * </pre>
70  * This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}
71  * or {@link #offset(Clock, Duration) offset} to be used during testing.
72  * <p>
73  * The {@code system} factory methods provide clocks based on the best available
74  * system clock This may use {@link System#currentTimeMillis()}, or a higher
75  * resolution clock if one is available.
76  *
77  * <h3>Specification for implementors</h3>
78  * This abstract class must be implemented with care to ensure other operate correctly.
79  * All implementations that can be instantiated must be final, immutable and thread-safe.
80  * <p>
81  * The principal methods are defined to allow the throwing of an exception.
82  * In normal use, no exceptions will be thrown, however one possible implementation would be to
83  * obtain the time from a central time server across the network. Obviously, in this case the
84  * lookup could fail, and so the method is permitted to throw an exception.
85  * <p>
86  * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds.
87  * If the implementation wraps a source that provides leap second information, then a mechanism
88  * should be used to "smooth" the leap second, such as UTC-SLS.
89  * <p>
90  * Implementations should implement {@code Serializable} wherever possible and must
91  * document whether or not they do support serialization.
92  */
93 public abstract class Clock {
94 
95     /**
96      * Obtains a clock that returns the current instant using the best available
97      * system clock, converting to date and time using the UTC time-zone.
98      * <p>
99      * This clock, rather than {@link #systemDefaultZone()}, should be used when
100      * you need the current instant without the date or time.
101      * <p>
102      * This clock is based on the best available system clock.
103      * This may use {@link System#currentTimeMillis()}, or a higher resolution
104      * clock if one is available.
105      * <p>
106      * Conversion from instant to date or time uses the {@link ZoneOffset#UTC UTC time-zone}.
107      * <p>
108      * The returned implementation is immutable, thread-safe and {@code Serializable}.
109      * It is equivalent to {@code system(ZoneOffset.UTC)}.
110      *
111      * @return a clock that uses the best available system clock in the UTC zone, not null
112      */
systemUTC()113     public static Clock systemUTC() {
114         return new SystemClock(ZoneOffset.UTC);
115     }
116 
117     /**
118      * Obtains a clock that returns the current instant using the best available
119      * system clock, converting to date and time using the default time-zone.
120      * <p>
121      * This clock is based on the best available system clock.
122      * This may use {@link System#currentTimeMillis()}, or a higher resolution
123      * clock if one is available.
124      * <p>
125      * Using this method hard codes a dependency to the default time-zone into your application.
126      * It is recommended to avoid this and use a specific time-zone whenever possible.
127      * The {@link #systemUTC() UTC clock} should be used when you need the current instant
128      * without the date or time.
129      * <p>
130      * The returned implementation is immutable, thread-safe and {@code Serializable}.
131      * It is equivalent to {@code system(ZoneId.systemDefault())}.
132      *
133      * @return a clock that uses the best available system clock in the default zone, not null
134      * @see ZoneId#systemDefault()
135      */
systemDefaultZone()136     public static Clock systemDefaultZone() {
137         return new SystemClock(ZoneId.systemDefault());
138     }
139 
140     /**
141      * Obtains a clock that returns the current instant using best available
142      * system clock.
143      * <p>
144      * This clock is based on the best available system clock.
145      * This may use {@link System#currentTimeMillis()}, or a higher resolution
146      * clock if one is available.
147      * <p>
148      * Conversion from instant to date or time uses the specified time-zone.
149      * <p>
150      * The returned implementation is immutable, thread-safe and {@code Serializable}.
151      *
152      * @param zone  the time-zone to use to convert the instant to date-time, not null
153      * @return a clock that uses the best available system clock in the specified zone, not null
154      */
system(ZoneId zone)155     public static Clock system(ZoneId zone) {
156         Jdk8Methods.requireNonNull(zone, "zone");
157         return new SystemClock(zone);
158     }
159 
160     //-------------------------------------------------------------------------
161     /**
162      * Obtains a clock that returns the current instant ticking in whole seconds
163      * using best available system clock.
164      * <p>
165      * This clock will always have the nano-of-second field set to zero.
166      * This ensures that the visible time ticks in whole seconds.
167      * The underlying clock is the best available system clock, equivalent to
168      * using {@link #system(ZoneId)}.
169      * <p>
170      * Implementations may use a caching strategy for performance reasons.
171      * As such, it is possible that the start of the second observed via this
172      * clock will be later than that observed directly via the underlying clock.
173      * <p>
174      * The returned implementation is immutable, thread-safe and {@code Serializable}.
175      * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
176      *
177      * @param zone  the time-zone to use to convert the instant to date-time, not null
178      * @return a clock that ticks in whole seconds using the specified zone, not null
179      */
tickSeconds(ZoneId zone)180     public static Clock tickSeconds(ZoneId zone) {
181         return new TickClock(system(zone), NANOS_PER_SECOND);
182     }
183 
184     /**
185      * Obtains a clock that returns the current instant ticking in whole minutes
186      * using best available system clock.
187      * <p>
188      * This clock will always have the nano-of-second and second-of-minute fields set to zero.
189      * This ensures that the visible time ticks in whole minutes.
190      * The underlying clock is the best available system clock, equivalent to
191      * using {@link #system(ZoneId)}.
192      * <p>
193      * Implementations may use a caching strategy for performance reasons.
194      * As such, it is possible that the start of the minute observed via this
195      * clock will be later than that observed directly via the underlying clock.
196      * <p>
197      * The returned implementation is immutable, thread-safe and {@code Serializable}.
198      * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
199      *
200      * @param zone  the time-zone to use to convert the instant to date-time, not null
201      * @return a clock that ticks in whole minutes using the specified zone, not null
202      */
tickMinutes(ZoneId zone)203     public static Clock tickMinutes(ZoneId zone) {
204         return new TickClock(system(zone), NANOS_PER_MINUTE);
205     }
206 
207     /**
208      * Obtains a clock that returns instants from the specified clock truncated
209      * to the nearest occurrence of the specified duration.
210      * <p>
211      * This clock will only tick as per the specified duration. Thus, if the duration
212      * is half a second, the clock will return instants truncated to the half second.
213      * <p>
214      * The tick duration must be positive. If it has a part smaller than a whole
215      * millisecond, then the whole duration must divide into one second without
216      * leaving a remainder. All normal tick durations will match these criteria,
217      * including any multiple of hours, minutes, seconds and milliseconds, and
218      * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
219      * <p>
220      * A duration of zero or one nanosecond would have no truncation effect.
221      * Passing one of these will return the underlying clock.
222      * <p>
223      * Implementations may use a caching strategy for performance reasons.
224      * As such, it is possible that the start of the requested duration observed
225      * via this clock will be later than that observed directly via the underlying clock.
226      * <p>
227      * The returned implementation is immutable, thread-safe and {@code Serializable}
228      * providing that the base clock is.
229      *
230      * @param baseClock  the base clock to base the ticking clock on, not null
231      * @param tickDuration  the duration of each visible tick, not negative, not null
232      * @return a clock that ticks in whole units of the duration, not null
233      * @throws IllegalArgumentException if the duration is negative, or has a
234      *  part smaller than a whole millisecond such that the whole duration is not
235      *  divisible into one second
236      * @throws ArithmeticException if the duration is too large to be represented as nanos
237      */
tick(Clock baseClock, Duration tickDuration)238     public static Clock tick(Clock baseClock, Duration tickDuration) {
239         Jdk8Methods.requireNonNull(baseClock, "baseClock");
240         Jdk8Methods.requireNonNull(tickDuration, "tickDuration");
241         if (tickDuration.isNegative()) {
242             throw new IllegalArgumentException("Tick duration must not be negative");
243         }
244         long tickNanos = tickDuration.toNanos();
245         if (tickNanos % 1000000 == 0) {
246             // ok, no fraction of millisecond
247         } else if (1000000000 % tickNanos == 0) {
248             // ok, divides into one second without remainder
249         } else {
250             throw new IllegalArgumentException("Invalid tick duration");
251         }
252         if (tickNanos <= 1) {
253             return baseClock;
254         }
255         return new TickClock(baseClock, tickNanos);
256     }
257 
258     //-----------------------------------------------------------------------
259     /**
260      * Obtains a clock that always returns the same instant.
261      * <p>
262      * This clock simply returns the specified instant.
263      * As such, it is not a clock in the conventional sense.
264      * The main use case for this is in testing, where the fixed clock ensures
265      * tests are not dependent on the current clock.
266      * <p>
267      * The returned implementation is immutable, thread-safe and {@code Serializable}.
268      *
269      * @param fixedInstant  the instant to use as the clock, not null
270      * @param zone  the time-zone to use to convert the instant to date-time, not null
271      * @return a clock that always returns the same instant, not null
272      */
fixed(Instant fixedInstant, ZoneId zone)273     public static Clock fixed(Instant fixedInstant, ZoneId zone) {
274         Jdk8Methods.requireNonNull(fixedInstant, "fixedInstant");
275         Jdk8Methods.requireNonNull(zone, "zone");
276         return new FixedClock(fixedInstant, zone);
277     }
278 
279     //-------------------------------------------------------------------------
280     /**
281      * Obtains a clock that returns instants from the specified clock with the
282      * specified duration added
283      * <p>
284      * This clock wraps another clock, returning instants that are later by the
285      * specified duration. If the duration is negative, the instants will be
286      * earlier than the current date and time.
287      * The main use case for this is to simulate running in the future or in the past.
288      * <p>
289      * A duration of zero would have no offsetting effect.
290      * Passing zero will return the underlying clock.
291      * <p>
292      * The returned implementation is immutable, thread-safe and {@code Serializable}
293      * providing that the base clock is.
294      *
295      * @param baseClock  the base clock to add the duration to, not null
296      * @param offsetDuration  the duration to add, not null
297      * @return a clock based on the base clock with the duration added, not null
298      */
offset(Clock baseClock, Duration offsetDuration)299     public static Clock offset(Clock baseClock, Duration offsetDuration) {
300         Jdk8Methods.requireNonNull(baseClock, "baseClock");
301         Jdk8Methods.requireNonNull(offsetDuration, "offsetDuration");
302         if (offsetDuration.equals(Duration.ZERO)) {
303             return baseClock;
304         }
305         return new OffsetClock(baseClock, offsetDuration);
306     }
307 
308     //-----------------------------------------------------------------------
309     /**
310      * Constructor accessible by subclasses.
311      */
Clock()312     protected Clock() {
313     }
314 
315     //-----------------------------------------------------------------------
316     /**
317      * Gets the time-zone being used to create dates and times.
318      * <p>
319      * A clock will typically obtain the current instant and then convert that
320      * to a date or time using a time-zone. This method returns the time-zone used.
321      *
322      * @return the time-zone being used to interpret instants, not null
323      */
getZone()324     public abstract ZoneId getZone();
325 
326     /**
327      * Returns a copy of this clock with a different time-zone.
328      * <p>
329      * A clock will typically obtain the current instant and then convert that
330      * to a date or time using a time-zone. This method returns a clock with
331      * similar properties but using a different time-zone.
332      *
333      * @param zone  the time-zone to change to, not null
334      * @return a clock based on this clock with the specified time-zone, not null
335      */
withZone(ZoneId zone)336     public abstract Clock withZone(ZoneId zone);
337 
338     //-------------------------------------------------------------------------
339     /**
340      * Gets the current millisecond instant of the clock.
341      * <p>
342      * This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC.
343      * This is equivalent to the definition of {@link System#currentTimeMillis()}.
344      * <p>
345      * Most applications should avoid this method and use {@link Instant} to represent
346      * an instant on the time-line rather than a raw millisecond value.
347      * This method is provided to allow the use of the clock in high performance use cases
348      * where the creation of an object would be unacceptable.
349      * The default implementation currently calls {@link #instant()}.
350      * <p>
351      *
352      * @return the current millisecond instant from this clock, measured from
353      *  the Java epoch of 1970-01-01T00:00 UTC, not null
354      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
355      */
millis()356     public long millis() {
357         return instant().toEpochMilli();
358     }
359 
360     /**
361      * Gets the current instant of the clock.
362      * <p>
363      * This returns an instant representing the current instant as defined by the clock.
364      *
365      * @return the current instant from this clock, not null
366      * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
367      */
instant()368     public abstract Instant instant();
369 
370     //-----------------------------------------------------------------------
371     /**
372      * Checks if this clock is equal to another clock.
373      * <p>
374      * Clocks must compare equal based on their state and behavior.
375      *
376      * @param obj  the object to check, null returns false
377      * @return true if this is equal to the other clock
378      */
379     @Override
equals(Object obj)380     public boolean equals(Object obj) {
381         return super.equals(obj);
382     }
383 
384     /**
385      * A hash code for this clock.
386      *
387      * @return a suitable hash code
388      */
389     @Override
hashCode()390     public int hashCode() {
391         return super.hashCode();
392     }
393 
394     //-----------------------------------------------------------------------
395     /**
396      * Implementation of a clock that always returns the latest time from
397      * {@link System#currentTimeMillis()}.
398      */
399     static final class SystemClock extends Clock implements Serializable {
400         private static final long serialVersionUID = 6740630888130243051L;
401         private final ZoneId zone;
402 
SystemClock(ZoneId zone)403         SystemClock(ZoneId zone) {
404             this.zone = zone;
405         }
406         @Override
getZone()407         public ZoneId getZone() {
408             return zone;
409         }
410         @Override
withZone(ZoneId zone)411         public Clock withZone(ZoneId zone) {
412             if (zone.equals(this.zone)) {  // intentional NPE
413                 return this;
414             }
415             return new SystemClock(zone);
416         }
417         @Override
millis()418         public long millis() {
419             return System.currentTimeMillis();
420         }
421         @Override
instant()422         public Instant instant() {
423             return Instant.ofEpochMilli(millis());
424         }
425         @Override
equals(Object obj)426         public boolean equals(Object obj) {
427             if (obj instanceof SystemClock) {
428                 return zone.equals(((SystemClock) obj).zone);
429             }
430             return false;
431         }
432         @Override
hashCode()433         public int hashCode() {
434             return zone.hashCode() + 1;
435         }
436         @Override
toString()437         public String toString() {
438             return "SystemClock[" + zone + "]";
439         }
440     }
441 
442     //-----------------------------------------------------------------------
443     /**
444      * Implementation of a clock that always returns the same instant.
445      * This is typically used for testing.
446      */
447     static final class FixedClock extends Clock implements Serializable {
448        private static final long serialVersionUID = 7430389292664866958L;
449         private final Instant instant;
450         private final ZoneId zone;
451 
FixedClock(Instant fixedInstant, ZoneId zone)452         FixedClock(Instant fixedInstant, ZoneId zone) {
453             this.instant = fixedInstant;
454             this.zone = zone;
455         }
456         @Override
getZone()457         public ZoneId getZone() {
458             return zone;
459         }
460         @Override
withZone(ZoneId zone)461         public Clock withZone(ZoneId zone) {
462             if (zone.equals(this.zone)) {  // intentional NPE
463                 return this;
464             }
465             return new FixedClock(instant, zone);
466         }
467         @Override
millis()468         public long millis() {
469             return instant.toEpochMilli();
470         }
471         @Override
instant()472         public Instant instant() {
473             return instant;
474         }
475         @Override
equals(Object obj)476         public boolean equals(Object obj) {
477             if (obj instanceof FixedClock) {
478                 FixedClock other = (FixedClock) obj;
479                 return instant.equals(other.instant) && zone.equals(other.zone);
480             }
481             return false;
482         }
483         @Override
hashCode()484         public int hashCode() {
485             return instant.hashCode() ^ zone.hashCode();
486         }
487         @Override
toString()488         public String toString() {
489             return "FixedClock[" + instant + "," + zone + "]";
490         }
491     }
492 
493     //-----------------------------------------------------------------------
494     /**
495      * Implementation of a clock that adds an offset to an underlying clock.
496      */
497     static final class OffsetClock extends Clock implements Serializable {
498        private static final long serialVersionUID = 2007484719125426256L;
499         private final Clock baseClock;
500         private final Duration offset;
501 
OffsetClock(Clock baseClock, Duration offset)502         OffsetClock(Clock baseClock, Duration offset) {
503             this.baseClock = baseClock;
504             this.offset = offset;
505         }
506         @Override
getZone()507         public ZoneId getZone() {
508             return baseClock.getZone();
509         }
510         @Override
withZone(ZoneId zone)511         public Clock withZone(ZoneId zone) {
512             if (zone.equals(baseClock.getZone())) {  // intentional NPE
513                 return this;
514             }
515             return new OffsetClock(baseClock.withZone(zone), offset);
516         }
517         @Override
millis()518         public long millis() {
519             return Jdk8Methods.safeAdd(baseClock.millis(), offset.toMillis());
520         }
521         @Override
instant()522         public Instant instant() {
523             return baseClock.instant().plus(offset);
524         }
525         @Override
equals(Object obj)526         public boolean equals(Object obj) {
527             if (obj instanceof OffsetClock) {
528                 OffsetClock other = (OffsetClock) obj;
529                 return baseClock.equals(other.baseClock) && offset.equals(other.offset);
530             }
531             return false;
532         }
533         @Override
hashCode()534         public int hashCode() {
535             return baseClock.hashCode() ^ offset.hashCode();
536         }
537         @Override
toString()538         public String toString() {
539             return "OffsetClock[" + baseClock + "," + offset + "]";
540         }
541     }
542 
543     //-----------------------------------------------------------------------
544     /**
545      * Implementation of a clock that adds an offset to an underlying clock.
546      */
547     static final class TickClock extends Clock implements Serializable {
548         private static final long serialVersionUID = 6504659149906368850L;
549         private final Clock baseClock;
550         private final long tickNanos;
551 
TickClock(Clock baseClock, long tickNanos)552         TickClock(Clock baseClock, long tickNanos) {
553             this.baseClock = baseClock;
554             this.tickNanos = tickNanos;
555         }
556         @Override
getZone()557         public ZoneId getZone() {
558             return baseClock.getZone();
559         }
560         @Override
withZone(ZoneId zone)561         public Clock withZone(ZoneId zone) {
562             if (zone.equals(baseClock.getZone())) {  // intentional NPE
563                 return this;
564             }
565             return new TickClock(baseClock.withZone(zone), tickNanos);
566         }
567         @Override
millis()568         public long millis() {
569             long millis = baseClock.millis();
570             return millis - Jdk8Methods.floorMod(millis, tickNanos / 1000000L);
571         }
572         @Override
instant()573         public Instant instant() {
574             if ((tickNanos % 1000000) == 0) {
575                 long millis = baseClock.millis();
576                 return Instant.ofEpochMilli(millis - Jdk8Methods.floorMod(millis, tickNanos / 1000000L));
577             }
578             Instant instant = baseClock.instant();
579             long nanos = instant.getNano();
580             long adjust = Jdk8Methods.floorMod(nanos, tickNanos);
581             return instant.minusNanos(adjust);
582         }
583         @Override
equals(Object obj)584         public boolean equals(Object obj) {
585             if (obj instanceof TickClock) {
586                 TickClock other = (TickClock) obj;
587                 return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
588             }
589             return false;
590         }
591         @Override
hashCode()592         public int hashCode() {
593             return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
594         }
595         @Override
toString()596         public String toString() {
597             return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
598         }
599     }
600 
601 }
602