View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.api;
20  
21  import java.time.Clock;
22  import java.time.Instant;
23  import java.time.ZoneId;
24  import java.time.ZoneOffset;
25  
26  /**
27   * A Clock implementation that combines monotonic timing with wall-clock time.
28   * <p>
29   * This class provides precise time measurements using {@link System#nanoTime()}
30   * while maintaining wall-clock time information in UTC. The wall-clock time
31   * is computed from the monotonic duration since system start to ensure consistency
32   * between time measurements.
33   * <p>
34   * This implementation is singleton-based and always uses UTC timezone. The clock
35   * cannot be adjusted to different timezones to maintain consistent monotonic behavior.
36   * Users needing local time representation should convert the result of {@link #instant()}
37   * to their desired timezone:
38   * <pre>{@code
39   * Instant now = MonotonicClock.now();
40   * ZonedDateTime local = now.atZone(ZoneId.systemDefault());
41   * }</pre>
42   *
43   * @see System#nanoTime()
44   * @see Clock
45   */
46  public class MonotonicClock extends Clock {
47      private static final MonotonicClock CLOCK = new MonotonicClock();
48  
49      private final long startNanos;
50      private final Instant startInstant;
51  
52      /**
53       * Private constructor to enforce singleton pattern.
54       * Initializes the clock with the current system time and nanoTime.
55       */
56      private MonotonicClock() {
57          this.startNanos = System.nanoTime();
58          this.startInstant = Clock.systemUTC().instant();
59      }
60  
61      /**
62       * Returns the singleton instance of MonotonicClock.
63       *
64       * @return the monotonic clock instance
65       */
66      public static MonotonicClock get() {
67          return CLOCK;
68      }
69  
70      /**
71       * Returns the current instant from the monotonic clock.
72       * This is a convenience method equivalent to {@code get().instant()}.
73       *
74       * @return the current instant using monotonic timing
75       */
76      public static Instant now() {
77          return get().instant();
78      }
79  
80      /**
81       * Returns a monotonically increasing instant.
82       * <p>
83       * The returned instant is calculated by adding the elapsed nanoseconds
84       * since clock creation to the initial wall clock time. This ensures that
85       * the time never goes backwards and maintains a consistent relationship
86       * with the wall clock time.
87       *
88       * @return the current instant using monotonic timing
89       */
90      @Override
91      public Instant instant() {
92          long elapsedNanos = System.nanoTime() - startNanos;
93          return startInstant.plusNanos(elapsedNanos);
94      }
95  
96      /**
97       * Returns the zone ID of this clock, which is always UTC.
98       *
99       * @return the UTC zone ID
100      */
101     @Override
102     public ZoneId getZone() {
103         return ZoneOffset.UTC;
104     }
105 
106     /**
107      * Returns this clock since timezone adjustments are not supported.
108      * <p>
109      * This implementation maintains UTC time to ensure monotonic behavior.
110      * The provided zone parameter is ignored.
111      *
112      * @param zone the target timezone (ignored)
113      * @return this clock instance
114      */
115     @Override
116     public Clock withZone(ZoneId zone) {
117         // Monotonic clock is always UTC-based
118         return this;
119     }
120 }