1 /*
2 * ModeShape (http://www.modeshape.org)
3 * See the COPYRIGHT.txt file distributed with this work for information
4 * regarding copyright ownership. Some portions may be licensed
5 * to Red Hat, Inc. under one or more contributor license agreements.
6 * See the AUTHORS.txt file in the distribution for a full listing of
7 * individual contributors.
8 *
9 * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10 * is licensed to you under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * ModeShape is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this software; if not, write to the Free
21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23 */
24 package org.modeshape.common.math;
25
26 import java.math.BigDecimal;
27 import java.text.DecimalFormat;
28 import java.util.concurrent.TimeUnit;
29 import net.jcip.annotations.Immutable;
30
31 /**
32 * A number representing an immutable duration of time. This is intended to be used in the same manner as other {@link Number}
33 * subclasses.
34 */
35 @Immutable
36 public class Duration extends Number implements Comparable<Duration> {
37
38 private static final long serialVersionUID = 1L;
39
40 private final long durationInNanos;
41 private Components components;
42
43 /**
44 * Create a duration given the number of nanoseconds.
45 *
46 * @param nanos the number of nanoseconds in the duration
47 */
48 public Duration( long nanos ) {
49 this(nanos, TimeUnit.NANOSECONDS);
50 }
51
52 /**
53 * Create a duration and the time unit.
54 *
55 * @param duration the duration in the supplied time units
56 * @param unit the time unit
57 */
58 public Duration( long duration,
59 TimeUnit unit ) {
60 this.durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
61 }
62
63 /**
64 * {@inheritDoc}
65 */
66 @Override
67 public double doubleValue() {
68 return this.durationInNanos;
69 }
70
71 /**
72 * {@inheritDoc}
73 */
74 @Override
75 public float floatValue() {
76 return this.durationInNanos;
77 }
78
79 /**
80 * {@inheritDoc}
81 */
82 @Override
83 public int intValue() {
84 return (int)this.durationInNanos;
85 }
86
87 /**
88 * {@inheritDoc}
89 */
90 @Override
91 public long longValue() {
92 return this.durationInNanos;
93 }
94
95 public BigDecimal toBigDecimal() {
96 return new BigDecimal(this.durationInNanos);
97 }
98
99 /**
100 * Add the supplied duration to this duration, and return the result.
101 *
102 * @param duration the duration to add to this object
103 * @param unit the unit of the duration being added; may not be null
104 * @return the total duration
105 */
106 public Duration add( long duration,
107 TimeUnit unit ) {
108 long durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
109 return new Duration(this.durationInNanos + durationInNanos);
110 }
111
112 /**
113 * Subtract the supplied duration from this duration, and return the result.
114 *
115 * @param duration the duration to subtract from this object
116 * @param unit the unit of the duration being subtracted; may not be null
117 * @return the total duration
118 */
119 public Duration subtract( long duration,
120 TimeUnit unit ) {
121 long durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
122 return new Duration(this.durationInNanos - durationInNanos);
123 }
124
125 /**
126 * Add the supplied duration to this duration, and return the result. A null value is treated as a duration of 0 nanoseconds.
127 *
128 * @param duration the duration to add to this object
129 * @return the total duration
130 */
131 public Duration add( Duration duration ) {
132 return new Duration(this.durationInNanos + (duration == null ? 0l : duration.longValue()));
133 }
134
135 /**
136 * Subtract the supplied duration from this duration, and return the result. A null value is treated as a duration of 0
137 * nanoseconds.
138 *
139 * @param duration the duration to subtract from this object
140 * @return the resulting duration
141 */
142 public Duration subtract( Duration duration ) {
143 return new Duration(this.durationInNanos - (duration == null ? 0l : duration.longValue()));
144 }
145
146 /**
147 * Multiply the duration by the supplied scale factor, and return the result.
148 *
149 * @param scale the factor by which the duration is to be scaled.
150 * @return the scaled duration
151 */
152 public Duration multiply( long scale ) {
153 return new Duration(this.durationInNanos * scale);
154 }
155
156 /**
157 * Divide the duration by the supplied number, and return the result.
158 *
159 * @param denominator the factor by which the duration is to be divided.
160 * @return the resulting duration
161 */
162 public Duration divide( long denominator ) {
163 return new Duration(this.durationInNanos / denominator);
164 }
165
166 /**
167 * Divide the duration by another duration to calculate the ratio.
168 *
169 * @param duration the duration that this duration is to be divided by; may not be null
170 * @return the resulting duration
171 */
172 public double divide( Duration duration ) {
173 return this.toBigDecimal().divide(duration.toBigDecimal()).doubleValue();
174 }
175
176 /**
177 * {@inheritDoc}
178 */
179 public int compareTo( Duration that ) {
180 if (that == null) return 1;
181 return this.durationInNanos < that.durationInNanos ? -1 : this.durationInNanos > that.durationInNanos ? 1 : 0;
182 }
183
184 /**
185 * Return the total duration in nanoseconds.
186 *
187 * @return the total duration in nanoseconds
188 */
189 public long getDuratinInNanoseconds() {
190 return this.durationInNanos;
191 }
192
193 /**
194 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
195 *
196 * @return the total duration in microseconds
197 */
198 public BigDecimal getDurationInMicroseconds() {
199 return this.toBigDecimal().divide(new BigDecimal(1000));
200 }
201
202 /**
203 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
204 *
205 * @return the total duration in microseconds
206 */
207 public BigDecimal getDurationInMilliseconds() {
208 return this.toBigDecimal().divide(new BigDecimal(1000000));
209 }
210
211 /**
212 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
213 *
214 * @return the total duration in microseconds
215 */
216 public BigDecimal getDurationInSeconds() {
217 return this.toBigDecimal().divide(new BigDecimal(1000000000));
218 }
219
220 /**
221 * Return the duration components.
222 *
223 * @return the individual time components of this duration
224 */
225 public Components getComponents() {
226 if (this.components == null) {
227 // This is idempotent, so no need to synchronize ...
228
229 // Calculate how many seconds, and don't lose any information ...
230 BigDecimal bigSeconds = new BigDecimal(this.durationInNanos).divide(new BigDecimal(1000000000));
231 // Calculate the minutes, and round to lose the seconds
232 int minutes = bigSeconds.intValue() / 60;
233 // Remove the minutes from the seconds, to just have the remainder of seconds
234 double dMinutes = minutes;
235 double seconds = bigSeconds.doubleValue() - dMinutes * 60;
236 // Now compute the number of full hours, and change 'minutes' to hold the remainding minutes
237 int hours = minutes / 60;
238 minutes = minutes - (hours * 60);
239 this.components = new Components(hours, minutes, seconds);
240 }
241 return this.components;
242 }
243
244 /**
245 * Get the duration value in the supplied unit of time.
246 *
247 * @param unit the unit of time for the returned value; may not be null
248 * @return the value of this duration in the supplied unit of time
249 */
250 public long getDuration( TimeUnit unit ) {
251 if (unit == null) throw new IllegalArgumentException();
252 return unit.convert(durationInNanos, TimeUnit.NANOSECONDS);
253 }
254
255 /**
256 * Writes the duration in a form containing hours, minutes, and seconds, including the fractional part of the seconds. The
257 * format is essentially <code>HHH:MM:SS.mmm,mmm</code>, where
258 * <dl>
259 * <dt>HHH</dt>
260 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
261 * <dt>MM</dt>
262 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
263 * <dt>SS</dt>
264 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
265 * <dt>mmm,mmm</dt>
266 * <dd>is the fractional part of seconds, written in at least millisecond precision and up to microsecond precision. The comma
267 * appears if more than 3 digits are used.
268 * </dl>
269 *
270 * @return a string representation of the duration
271 */
272 @Override
273 public String toString() {
274 // Insert a comma after the milliseconds, if there are enough digits ..
275 return this.getComponents().toString().replaceAll("(\\d{2}).(\\d{3})(\\d{1,3})", "$1.$2,$3");
276 }
277
278 /**
279 * The atomic components of this duration, broken down into whole hours, minutes and (fractional) seconds.
280 */
281 public class Components {
282
283 private final int hours;
284 private final int minutes;
285 private final double seconds;
286
287 protected Components( int hours,
288 int minutes,
289 double seconds ) {
290 this.hours = hours;
291 this.minutes = minutes;
292 this.seconds = seconds;
293 }
294
295 /**
296 * Get the whole hours in this duration.
297 *
298 * @return the hours
299 */
300 public int getHours() {
301 return hours;
302 }
303
304 /**
305 * Get the whole minutes in this duration.
306 *
307 * @return the minutes, from 0 to 59.
308 */
309 public int getMinutes() {
310 return minutes;
311 }
312
313 /**
314 * Get the duration's seconds component.
315 *
316 * @return the number of seconds, including fractional part.
317 */
318 public double getSeconds() {
319 return seconds;
320 }
321
322 /**
323 * Return the duration as a string in a form containing hours, minutes, and seconds, including the fractional part of the
324 * seconds. The format is essentially <code>HHH:MM:SS.mmm</code>, where
325 * <dl>
326 * <dt>HHH</dt>
327 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
328 * <dt>MM</dt>
329 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
330 * <dt>SS</dt>
331 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
332 * <dt>mmm</dt>
333 * <dd>is the fractional part of seconds, written with 3-6 digits (any trailing zeros are dropped)
334 * </dl>
335 *
336 * @return a string representation of the duration components
337 */
338 @Override
339 public String toString() {
340 // Format the string, and have at least 2 digits for the hours, minutes and whole seconds,
341 // and between 3 and 6 digits for the fractional part of the seconds...
342 String result = new DecimalFormat("######00").format(hours) + ':' + new DecimalFormat("00").format(minutes) + ':'
343 + new DecimalFormat("00.000###").format(seconds);
344 return result;
345 }
346 }
347
348 }