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 }