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 }