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