diff --git a/src/main/java/groovy/time/Timed.java b/src/main/java/groovy/time/Timed.java new file mode 100644 index 00000000000..e13a479c43a --- /dev/null +++ b/src/main/java/groovy/time/Timed.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package groovy.time; + +import java.time.Duration; + +/** + * An immutable holder for the outcome of a timed execution: the value produced + * together with the elapsed time in nanoseconds. Instances are created by the + * {@code timed} extension method rather than being constructed directly. + *
+ * The elapsed time is measured with {@link System#nanoTime()}, which is + * monotonic and unaffected by wall-clock adjustments. Convenience views of the + * duration are available via {@link #getDuration()} and {@link #getMillis()}, + * which Groovy exposes as the {@code duration} and {@code millis} properties. + *
+ * def t = System.timed { (1..1_000).sum() }
+ * assert t.result == 500_500
+ * assert t.nanos >= 0
+ * assert t.duration instanceof java.time.Duration
+ *
+ *
+ * @param + * Timing uses {@link System#nanoTime()}, which is monotonic and unaffected by + * wall-clock adjustments. The closure is executed synchronously on the calling + * thread and any exception it throws propagates unchanged (the elapsed time is + * not reported in that case). Its result, if any, is discarded; use + * {@link #timed(System, Closure)} when the result is also needed. + *
+ * long elapsed = System.timedNanos { (1..1_000).sum() }
+ * assert elapsed >= 0
+ *
+ *
+ * @param self placeholder variable used by Groovy categories; ignored for default static methods
+ * @param code the closure to execute and time
+ * @return the elapsed time in nanoseconds
+ * @see #timedMillis(System, Closure)
+ * @see #timed(System, Closure)
+ * @since 6.0.0
+ */
+ public static long timedNanos(System self, Closure> code) {
+ long start = System.nanoTime();
+ code.call();
+ return System.nanoTime() - start;
+ }
+
+ /**
+ * Executes the given closure and returns the elapsed time in whole milliseconds.
+ * + * This is a convenience for {@code timedNanos(code) / 1_000_000}. Timing uses + * {@link System#nanoTime()}, which is monotonic and unaffected by wall-clock + * adjustments. The closure is executed synchronously on the calling thread and + * any exception it throws propagates unchanged. Its result, if any, is + * discarded; use {@link #timed(System, Closure)} when the result is also needed. + *
+ * long elapsed = System.timedMillis { (1..1_000).sum() }
+ * assert elapsed >= 0
+ *
+ *
+ * @param self placeholder variable used by Groovy categories; ignored for default static methods
+ * @param code the closure to execute and time
+ * @return the elapsed time in milliseconds, truncated toward zero
+ * @see #timedNanos(System, Closure)
+ * @see #timed(System, Closure)
+ * @since 6.0.0
+ */
+ public static long timedMillis(System self, Closure> code) {
+ return timedNanos(self, code) / 1_000_000;
+ }
+
+ /**
+ * Executes the given closure and returns a {@link Timed} capturing both the
+ * closure's result and the elapsed time in nanoseconds.
+ * + * Timing uses {@link System#nanoTime()}, which is monotonic and unaffected by + * wall-clock adjustments. The closure is executed synchronously on the calling + * thread and any exception it throws propagates unchanged. + *
+ * def t = System.timed { (1..1_000).sum() }
+ * assert t.result == 500_500
+ * assert t.nanos >= 0
+ * println "computed ${t.result} in ${t.millis}ms"
+ *
+ *
+ * @param self placeholder variable used by Groovy categories; ignored for default static methods
+ * @param code the closure to execute and time
+ * @param