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 }