1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.lang3.time;
19
20 import java.time.Duration;
21 import java.time.Instant;
22 import java.time.temporal.ChronoUnit;
23 import java.time.temporal.Temporal;
24 import java.time.temporal.TemporalUnit;
25 import java.util.Objects;
26 import java.util.concurrent.TimeUnit;
27
28 import org.apache.commons.lang3.LongRange;
29 import org.apache.commons.lang3.ObjectUtils;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.function.FailableBiConsumer;
32 import org.apache.commons.lang3.function.FailableConsumer;
33 import org.apache.commons.lang3.function.FailableRunnable;
34 import org.apache.commons.lang3.math.NumberUtils;
35
36 /**
37 * Utilities for {@link Duration}.
38 *
39 * @since 3.12.0
40 */
41 public class DurationUtils {
42
43 /**
44 * An Integer Range that accepts Longs.
45 */
46 static final LongRange LONG_TO_INT_RANGE = LongRange.of(NumberUtils.LONG_INT_MIN_VALUE, NumberUtils.LONG_INT_MAX_VALUE);
47
48 /**
49 * Accepts the function with the duration as a long milliseconds and int nanoseconds.
50 *
51 * @param <T> The function exception.
52 * @param consumer Accepting function.
53 * @param duration The duration to pick apart.
54 * @throws T See the function signature.
55 * @see StopWatch
56 */
57 @SuppressWarnings("boxing") // boxing unavoidable
58 public static <T extends Throwable> void accept(final FailableBiConsumer<Long, Integer, T> consumer, final Duration duration)
59 throws T {
60 if (consumer != null && duration != null) {
61 consumer.accept(duration.toMillis(), getNanosOfMilli(duration));
62 }
63 }
64
65 /**
66 * Gets a Duration of unit stored in the system property at the given key.
67 *
68 * @param key The property name.
69 * @param unit The unit that the duration is measured in, not null.
70 * @param def The default value in the given unit.
71 * @return a Duration of seconds.
72 * @since 3.19.0
73 */
74 public static Duration get(final String key, final TemporalUnit unit, final long def) {
75 return Duration.of(getLong(key, def), unit);
76 }
77
78 private static long getLong(final String key, final long def) {
79 return StringUtils.isEmpty(key) ? def : Long.getLong(key, def);
80 }
81
82 /**
83 * Gets a Duration of milliseconds stored in the system property at the given key.
84 *
85 * @param key The property name.
86 * @param def The default value in milliseconds.
87 * @return a Duration of milliseconds.
88 * @since 3.19.0
89 */
90 public static Duration getMillis(final String key, final long def) {
91 return Duration.ofMillis(getLong(key, def));
92 }
93
94 /**
95 * Gets the nanosecond part of a Duration converted to milliseconds.
96 * <p>
97 * Handy when calling an API that takes a long of milliseconds and an int of nanoseconds. For example,
98 * {@link Object#wait(long, int)} and {@link Thread#sleep(long, int)}.
99 * </p>
100 * <p>
101 * Note that is this different from {@link Duration#getNano()} because a duration are seconds and nanoseconds.
102 * </p>
103 *
104 * @param duration The duration to query.
105 * @return nanoseconds between 0 and 999,999.
106 * @deprecated Use {@link #getNanosOfMilli(Duration)}.
107 */
108 @Deprecated
109 public static int getNanosOfMiili(final Duration duration) {
110 return getNanosOfMilli(duration);
111 }
112
113 /**
114 * Gets the nanosecond part of a Duration converted to milliseconds.
115 * <p>
116 * Handy when calling an API that takes a long of milliseconds and an int of nanoseconds. For example,
117 * {@link Object#wait(long, int)} and {@link Thread#sleep(long, int)}.
118 * </p>
119 * <p>
120 * Note that is this different from {@link Duration#getNano()} because a duration are seconds and nanoseconds.
121 * </p>
122 *
123 * @param duration The duration to query.
124 * @return nanoseconds between 0 and 999,999.
125 * @since 3.13.0
126 */
127 public static int getNanosOfMilli(final Duration duration) {
128 return zeroIfNull(duration).getNano() % 1_000_000;
129 }
130
131 /**
132 * Gets a Duration of seconds stored in the system property at the given key.
133 *
134 * @param key The property name.
135 * @param def The default value in seconds.
136 * @return a Duration of seconds.
137 * @since 3.19.0
138 */
139 public static Duration getSeconds(final String key, final long def) {
140 return Duration.ofSeconds(getLong(key, def));
141 }
142
143 /**
144 * Tests whether the given Duration is positive (duration > 0).
145 *
146 * @param duration the value to test
147 * @return whether the given Duration is positive (duration > 0).
148 */
149 public static boolean isPositive(final Duration duration) {
150 return !duration.isNegative() && !duration.isZero();
151 }
152
153 private static <E extends Throwable> Instant now(final FailableConsumer<Instant, E> nowConsumer) throws E {
154 final Instant start = Instant.now();
155 nowConsumer.accept(start);
156 return start;
157 }
158
159 /**
160 * Runs the lambda and returns the duration of its execution.
161 *
162 * @param <E> The type of exception throw by the lambda.
163 * @param consumer What to execute.
164 * @return The Duration of execution.
165 * @throws E thrown by the lambda.
166 * @see StopWatch
167 * @since 3.13.0
168 */
169 public static <E extends Throwable> Duration of(final FailableConsumer<Instant, E> consumer) throws E {
170 return since(now(consumer::accept));
171 }
172
173 /**
174 * Runs the lambda and returns the duration of its execution.
175 *
176 * @param <E> The type of exception throw by the lambda.
177 * @param runnable What to execute.
178 * @return The Duration of execution.
179 * @throws E thrown by the lambda.
180 * @see StopWatch
181 * @since 3.13.0
182 */
183 public static <E extends Throwable> Duration of(final FailableRunnable<E> runnable) throws E {
184 return of(start -> runnable.run());
185 }
186
187 /**
188 * Computes the Duration between a start instant and now.
189 *
190 * @param startInclusive the start instant, inclusive, not null.
191 * @return a {@link Duration}, not null.
192 * @since 3.13.0
193 */
194 public static Duration since(final Temporal startInclusive) {
195 return Duration.between(startInclusive, Instant.now());
196 }
197
198 /**
199 * Converts a {@link TimeUnit} to a {@link ChronoUnit}.
200 *
201 * @param timeUnit A non-null TimeUnit.
202 * @return The corresponding ChronoUnit.
203 */
204 static ChronoUnit toChronoUnit(final TimeUnit timeUnit) {
205 // TODO when using Java >= 9: Use TimeUnit.toChronoUnit().
206 switch (Objects.requireNonNull(timeUnit)) {
207 case NANOSECONDS:
208 return ChronoUnit.NANOS;
209 case MICROSECONDS:
210 return ChronoUnit.MICROS;
211 case MILLISECONDS:
212 return ChronoUnit.MILLIS;
213 case SECONDS:
214 return ChronoUnit.SECONDS;
215 case MINUTES:
216 return ChronoUnit.MINUTES;
217 case HOURS:
218 return ChronoUnit.HOURS;
219 case DAYS:
220 return ChronoUnit.DAYS;
221 default:
222 throw new IllegalArgumentException(timeUnit.toString());
223 }
224 }
225
226 /**
227 * Converts an amount and TimeUnit into a Duration.
228 *
229 * @param amount the amount of the duration, measured in terms of the unit, positive or negative
230 * @param timeUnit the unit that the duration is measured in, must have an exact duration, not null
231 * @return a Duration.
232 */
233 public static Duration toDuration(final long amount, final TimeUnit timeUnit) {
234 return Duration.of(amount, toChronoUnit(timeUnit));
235 }
236
237 /**
238 * Converts a Duration to milliseconds bound to an int (instead of a long).
239 * <p>
240 * Handy for low-level APIs that take millisecond timeouts in ints rather than longs.
241 * </p>
242 * <ul>
243 * <li>If the duration milliseconds are greater than {@link Integer#MAX_VALUE}, then return
244 * {@link Integer#MAX_VALUE}.</li>
245 * <li>If the duration milliseconds are lesser than {@link Integer#MIN_VALUE}, then return
246 * {@link Integer#MIN_VALUE}.</li>
247 * </ul>
248 *
249 * @param duration The duration to convert, not null.
250 * @return int milliseconds.
251 */
252 public static int toMillisInt(final Duration duration) {
253 Objects.requireNonNull(duration, "duration");
254 // intValue() does not do a narrowing conversion here
255 return LONG_TO_INT_RANGE.fit(Long.valueOf(duration.toMillis())).intValue();
256 }
257
258 /**
259 * Returns the given non-null value or {@link Duration#ZERO} if null.
260 *
261 * @param duration The duration to test.
262 * @return The given duration or {@link Duration#ZERO}.
263 */
264 public static Duration zeroIfNull(final Duration duration) {
265 return ObjectUtils.getIfNull(duration, Duration.ZERO);
266 }
267
268 /**
269 * Make private in 4.0.
270 *
271 * @deprecated TODO Make private in 4.0.
272 */
273 @Deprecated
274 public DurationUtils() {
275 // empty
276 }
277 }