001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.common.math;
025
026 import java.math.BigDecimal;
027 import java.text.DecimalFormat;
028 import java.util.concurrent.TimeUnit;
029
030 /**
031 * A number representing an immutable duration of time. This is intended to be used in the same manner as other {@link Number}
032 * subclasses.
033 */
034 public class Duration extends Number implements Comparable<Duration> {
035
036 private static final long serialVersionUID = 1L;
037
038 private final long durationInNanos;
039 private Components components;
040
041 /**
042 * Create a duration given the number of nanoseconds.
043 *
044 * @param nanos the number of nanoseconds in the duration
045 */
046 public Duration( long nanos ) {
047 this(nanos, TimeUnit.NANOSECONDS);
048 }
049
050 /**
051 * Create a duration and the time unit.
052 *
053 * @param duration the duration in the supplied time units
054 * @param unit the time unit
055 */
056 public Duration( long duration,
057 TimeUnit unit ) {
058 this.durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
059 }
060
061 /**
062 * {@inheritDoc}
063 */
064 @Override
065 public double doubleValue() {
066 return this.durationInNanos;
067 }
068
069 /**
070 * {@inheritDoc}
071 */
072 @Override
073 public float floatValue() {
074 return this.durationInNanos;
075 }
076
077 /**
078 * {@inheritDoc}
079 */
080 @Override
081 public int intValue() {
082 return (int)this.durationInNanos;
083 }
084
085 /**
086 * {@inheritDoc}
087 */
088 @Override
089 public long longValue() {
090 return this.durationInNanos;
091 }
092
093 public BigDecimal toBigDecimal() {
094 return new BigDecimal(this.durationInNanos);
095 }
096
097 /**
098 * Add the supplied duration to this duration, and return the result.
099 *
100 * @param duration the duration to add to this object
101 * @param unit the unit of the duration being added; may not be null
102 * @return the total duration
103 */
104 public Duration add( long duration,
105 TimeUnit unit ) {
106 long durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
107 return new Duration(this.durationInNanos + durationInNanos);
108 }
109
110 /**
111 * Subtract the supplied duration from this duration, and return the result.
112 *
113 * @param duration the duration to subtract from this object
114 * @param unit the unit of the duration being subtracted; may not be null
115 * @return the total duration
116 */
117 public Duration subtract( long duration,
118 TimeUnit unit ) {
119 long durationInNanos = TimeUnit.NANOSECONDS.convert(duration, unit);
120 return new Duration(this.durationInNanos - durationInNanos);
121 }
122
123 /**
124 * Add the supplied duration to this duration, and return the result. A null value is treated as a duration of 0 nanoseconds.
125 *
126 * @param duration the duration to add to this object
127 * @return the total duration
128 */
129 public Duration add( Duration duration ) {
130 return new Duration(this.durationInNanos + (duration == null ? 0l : duration.longValue()));
131 }
132
133 /**
134 * Subtract the supplied duration from this duration, and return the result. A null value is treated as a duration of 0
135 * nanoseconds.
136 *
137 * @param duration the duration to subtract from this object
138 * @return the resulting duration
139 */
140 public Duration subtract( Duration duration ) {
141 return new Duration(this.durationInNanos - (duration == null ? 0l : duration.longValue()));
142 }
143
144 /**
145 * Multiply the duration by the supplied scale factor, and return the result.
146 *
147 * @param scale the factor by which the duration is to be scaled.
148 * @return the scaled duration
149 */
150 public Duration multiply( long scale ) {
151 return new Duration(this.durationInNanos * scale);
152 }
153
154 /**
155 * Divide the duration by the supplied number, and return the result.
156 *
157 * @param denominator the factor by which the duration is to be divided.
158 * @return the resulting duration
159 */
160 public Duration divide( long denominator ) {
161 return new Duration(this.durationInNanos / denominator);
162 }
163
164 /**
165 * Divide the duration by another duration to calculate the ratio.
166 *
167 * @param duration the duration that this duration is to be divided by; may not be null
168 * @return the resulting duration
169 */
170 public double divide( Duration duration ) {
171 return this.toBigDecimal().divide(duration.toBigDecimal()).doubleValue();
172 }
173
174 /**
175 * {@inheritDoc}
176 */
177 public int compareTo( Duration that ) {
178 if (that == null) return 1;
179 return this.durationInNanos < that.durationInNanos ? -1 : this.durationInNanos > that.durationInNanos ? 1 : 0;
180 }
181
182 /**
183 * Return the total duration in nanoseconds.
184 *
185 * @return the total duration in nanoseconds
186 */
187 public long getDuratinInNanoseconds() {
188 return this.durationInNanos;
189 }
190
191 /**
192 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
193 *
194 * @return the total duration in microseconds
195 */
196 public BigDecimal getDurationInMicroseconds() {
197 return this.toBigDecimal().divide(new BigDecimal(1000));
198 }
199
200 /**
201 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
202 *
203 * @return the total duration in microseconds
204 */
205 public BigDecimal getDurationInMilliseconds() {
206 return this.toBigDecimal().divide(new BigDecimal(1000000));
207 }
208
209 /**
210 * Return the total duration in microseconds, which may contain a fraction part for the sub-microsecond component.
211 *
212 * @return the total duration in microseconds
213 */
214 public BigDecimal getDurationInSeconds() {
215 return this.toBigDecimal().divide(new BigDecimal(1000000000));
216 }
217
218 /**
219 * Return the duration components.
220 *
221 * @return the individual time components of this duration
222 */
223 public Components getComponents() {
224 if (this.components == null) {
225 // Calculate how many seconds, and don't lose any information ...
226 BigDecimal bigSeconds = new BigDecimal(this.durationInNanos).divide(new BigDecimal(1000000000));
227 // Calculate the minutes, and round to lose the seconds
228 int minutes = bigSeconds.intValue() / 60;
229 // Remove the minutes from the seconds, to just have the remainder of seconds
230 double dMinutes = minutes;
231 double seconds = bigSeconds.doubleValue() - dMinutes * 60;
232 // Now compute the number of full hours, and change 'minutes' to hold the remainding minutes
233 int hours = minutes / 60;
234 minutes = minutes - (hours * 60);
235 this.components = new Components(hours, minutes, seconds);
236 }
237 return this.components;
238 }
239
240 /**
241 * Get the duration value in the supplied unit of time.
242 *
243 * @param unit the unit of time for the returned value; may not be null
244 * @return the value of this duration in the supplied unit of time
245 */
246 public long getDuration( TimeUnit unit ) {
247 if (unit == null) throw new IllegalArgumentException();
248 return unit.convert(durationInNanos, TimeUnit.NANOSECONDS);
249 }
250
251 /**
252 * Writes the duration in a form containing hours, minutes, and seconds, including the fractional part of the seconds. The
253 * format is essentially <code>HHH:MM:SS.mmm,mmm</code>, where
254 * <dl>
255 * <dt>HHH</dt>
256 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
257 * <dt>MM</dt>
258 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
259 * <dt>SS</dt>
260 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
261 * <dt>mmm,mmm</dt>
262 * <dd>is the fractional part of seconds, written in at least millisecond precision and up to microsecond precision. The comma
263 * appears if more than 3 digits are used.
264 * </dl>
265 *
266 * @return a string representation of the duration
267 */
268 @Override
269 public String toString() {
270 // Insert a comma after the milliseconds, if there are enough digits ..
271 return this.getComponents().toString().replaceAll("(\\d{2}).(\\d{3})(\\d{1,3})", "$1.$2,$3");
272 }
273
274 /**
275 * The atomic components of this duration, broken down into whole hours, minutes and (fractional) seconds.
276 */
277 public class Components {
278
279 private final int hours;
280 private final int minutes;
281 private final double seconds;
282
283 protected Components( int hours,
284 int minutes,
285 double seconds ) {
286 this.hours = hours;
287 this.minutes = minutes;
288 this.seconds = seconds;
289 }
290
291 /**
292 * Get the whole hours in this duration.
293 *
294 * @return the hours
295 */
296 public int getHours() {
297 return hours;
298 }
299
300 /**
301 * Get the whole minutes in this duration.
302 *
303 * @return the minutes, from 0 to 59.
304 */
305 public int getMinutes() {
306 return minutes;
307 }
308
309 /**
310 * Get the duration's seconds component.
311 *
312 * @return the number of seconds, including fractional part.
313 */
314 public double getSeconds() {
315 return seconds;
316 }
317
318 /**
319 * Return the duration as a string in a form containing hours, minutes, and seconds, including the fractional part of the
320 * seconds. The format is essentially <code>HHH:MM:SS.mmm</code>, where
321 * <dl>
322 * <dt>HHH</dt>
323 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
324 * <dt>MM</dt>
325 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
326 * <dt>SS</dt>
327 * <dd>is the number of hours written in at least 2 digits (e.g., "03")</dd>
328 * <dt>mmm</dt>
329 * <dd>is the fractional part of seconds, written with 3-6 digits (any trailing zeros are dropped)
330 * </dl>
331 *
332 * @return a string representation of the duration components
333 */
334 @Override
335 public String toString() {
336 // Format the string, and have at least 2 digits for the hours, minutes and whole seconds,
337 // and between 3 and 6 digits for the fractional part of the seconds...
338 String result = new DecimalFormat("######00").format(hours) + ':' + new DecimalFormat("00").format(minutes) + ':'
339 + new DecimalFormat("00.000###").format(seconds);
340 return result;
341 }
342 }
343
344 }