1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.util; 27 28 import java.io.Serializable; 29 import javafx.beans.NamedArg; 30 31 /** 32 * <p> 33 * A class that defines a duration of time. Duration instances are immutable, 34 * and are therefore replaced rather than modified, similar to {@link java.math.BigDecimal}. 35 * Durations can be created using the constructor, or one of the static construction 36 * methods such as {@link #seconds} or {@link #minutes}. 37 * </p> 38 * @since JavaFX 2.0 39 */ 40 public class Duration implements Comparable<Duration>, Serializable { 41 /** 42 * A Duration of 0 (no time). 43 */ 44 public static final Duration ZERO = new Duration(0); 45 46 /** 47 * A Duration of 1 millisecond. 48 */ 49 public static final Duration ONE = new Duration(1); 50 51 /** 52 * An Infinite Duration. 53 */ 54 public static final Duration INDEFINITE = new Duration(Double.POSITIVE_INFINITY); 55 56 /** 57 * A Duration of some unknown amount of time. 58 */ 59 public static final Duration UNKNOWN = new Duration(Double.NaN); 60 61 /** 62 * Factory method that returns a Duration instance for a specified 63 * amount of time. The syntax is "[number][ms|s|m|h]". 64 * 65 * @param time A non-null string properly formatted. Leading or trailing 66 * spaces will not parse correctly. Throws a NullPointerException if 67 * time is null. 68 * @return a Duration which is represented by the <code>time</code> 69 */ 70 public static Duration valueOf(String time) { 71 int index = -1; 72 for (int i=0; i<time.length(); i++) { 73 char c = time.charAt(i); 74 if (!Character.isDigit(c) && c != '.' && c != '-') { 75 index = i; 76 break; 77 } 78 } 79 80 if (index == -1) { 81 // Never found the suffix! 82 throw new IllegalArgumentException("The time parameter must have a suffix of [ms|s|m|h]"); 83 } 84 85 double value = Double.parseDouble(time.substring(0, index)); 86 String suffix = time.substring(index); 87 if ("ms".equals(suffix)) { 88 return millis(value); 89 } else if ("s".equals(suffix)) { 90 return seconds(value); 91 } else if ("m".equals(suffix)) { 92 return minutes(value); 93 } else if ("h".equals(suffix)) { 94 return hours(value); 95 } else { 96 // Malformed suffix 97 throw new IllegalArgumentException("The time parameter must have a suffix of [ms|s|m|h]"); 98 } 99 } 100 101 /** 102 * Factory method that returns a Duration instance for a specified 103 * number of milliseconds. 104 * 105 * @param ms the number of milliseconds 106 * @return a Duration instance of the specified number of milliseconds 107 */ 108 public static Duration millis(double ms) { 109 if (ms == 0) { 110 return ZERO; 111 } else if (ms == 1) { 112 return ONE; 113 } else if (ms == Double.POSITIVE_INFINITY) { 114 return INDEFINITE; 115 } else if (Double.isNaN(ms)) { 116 return UNKNOWN; 117 } else { 118 return new Duration(ms); 119 } 120 } 121 122 /** 123 * Factory method that returns a Duration instance representing the specified 124 * number of seconds. 125 * 126 * @param s the number of seconds 127 * @return a Duration instance of the specified number of seconds 128 */ 129 public static Duration seconds(double s) { 130 if (s == 0) { 131 return ZERO; 132 } else if (s == Double.POSITIVE_INFINITY) { 133 return INDEFINITE; 134 } else if (Double.isNaN(s)) { 135 return UNKNOWN; 136 } else { 137 return new Duration(s * 1000.0); 138 } 139 } 140 141 /** 142 * Factory method that returns a Duration instance representing the specified 143 * number of minutes. 144 * 145 * @param m the number of minutes 146 * @return a Duration instance of the specified number of minutes 147 */ 148 public static Duration minutes(double m) { 149 if (m == 0) { 150 return ZERO; 151 } else if (m == Double.POSITIVE_INFINITY) { 152 return INDEFINITE; 153 } else if (Double.isNaN(m)) { 154 return UNKNOWN; 155 } else { 156 return new Duration(m * (1000.0 * 60.0)); 157 } 158 } 159 160 /** 161 * Factory method that returns a Duration instance representing the specified 162 * number of hours. 163 * 164 * @param h the number of hours 165 * @return a Duration instance representing the specified number of hours 166 */ 167 public static Duration hours(double h) { 168 if (h == 0) { 169 return ZERO; 170 } else if (h == Double.POSITIVE_INFINITY) { 171 return INDEFINITE; 172 } else if (Double.isNaN(h)) { 173 return UNKNOWN; 174 } else { 175 return new Duration(h * (1000.0 * 60.0 * 60.0)); 176 } 177 } 178 179 /** 180 * The value of this duration, in fractional milliseconds 181 */ 182 private final double millis; 183 184 /** 185 * Creates a new Duration with potentially fractional millisecond resolution. 186 * @param millis The number of milliseconds 187 */ 188 public Duration(@NamedArg("millis") double millis) { 189 this.millis = millis; 190 } 191 192 /** 193 * Returns the number of milliseconds in this period or Double.POSITIVE_INFINITY 194 * if the period is INDEFINITE or NaN if the period is UNKNOWN. 195 * @return the Duration in fractional milliseconds 196 */ 197 public double toMillis() { 198 return millis; 199 } 200 201 /** 202 * Returns the number of seconds in this period or Double.POSITIVE_INFINITY 203 * if the period is INDEFINITE or NaN if the period is UNKNOWN. 204 * @return the Duration in fractional seconds 205 */ 206 public double toSeconds() { 207 return millis / 1000.0; 208 } 209 210 /** 211 * Returns the number of minutes in this period or Double.POSITIVE_INFINITY 212 * if the period is INDEFINITE or NaN if the period is UNKNOWN. 213 * @return the Duration in fractional minutes 214 */ 215 public double toMinutes() { 216 return millis / (60 * 1000.0); 217 } 218 219 /** 220 * Returns the number of hours in this period or Double.POSITIVE_INFINITY 221 * if the period is INDEFINITE or NaN if the period is UNKNOWN. 222 * @return the Duration in fractional hours 223 */ 224 public double toHours() { 225 return millis / (60 * 60 * 1000.0); 226 } 227 228 /** 229 * Add this instance and another Duration instance to return a new Duration instance. 230 * If either instance is INDEFINITE, return INDEFINITE. 231 * If either instance is UNKNOWN, return UNKNOWN. 232 * This method does not change the value of the called Duration instance. 233 * 234 * @param other must not be null 235 * @return the result of adding this duration to the other duration. This is 236 * the same as millis + other.millis using double arithmetic 237 */ 238 public Duration add(Duration other) { 239 // Note that several of these functions assume that the value of millis in INDEFINITE 240 // is Double.POSITIVE_INFINITY. 241 return millis(millis + other.millis); 242 } 243 244 /** 245 * Subtract other Duration instance from this instance to return a new Duration instance. 246 * If either instance is UNKNOWN, return UNKNOWN. 247 * Otherwise, if either instance is INDEFINITE, return INDEFINITE. 248 * This method does not change the value of the called Duration instance. 249 * 250 * @param other must not be null 251 * @return the result of subtracting the other duration from this duration. This is 252 * the same as millis - other.millis using double arithmetic 253 */ 254 public Duration subtract(Duration other) { 255 return millis(millis - other.millis); 256 } 257 258 /** 259 * Multiply this instance with a number to return a new Duration instance. 260 * If either instance is INDEFINITE, return INDEFINITE. 261 * If either Duration instance is UNKNOWN, return UNKNOWN. 262 * This method does not change the value of the called Duration instance. 263 * 264 * @deprecated This method produces surprising results by not taking units into 265 * account. Use {@link #multiply(double)} instead. 266 * @param other must not be null 267 * @return the result of multiplying this duration with the other duration. This is 268 * the same as millis * other.millis using double arithmetic 269 */ 270 @Deprecated 271 public Duration multiply(Duration other) { 272 return millis(millis * other.millis); 273 } 274 275 /** 276 * Multiply this instance with a number representing millis and return a new Duration. 277 * If the called Duration instance is INDEFINITE, return INDEFINITE. 278 * If the called Duration instance is UNKNOWN, return UNKNOWN. 279 * This method does not change the value of the called Duration instance. 280 * 281 * @param n the amount to multiply by in fractional milliseconds 282 * @return the result of multiplying this duration with n. This is 283 * the same as millis * n using double arithmetic 284 */ 285 public Duration multiply(double n) { 286 return millis(millis * n); 287 } 288 289 /** 290 * Divide this instance by a number to return a new Duration instance. 291 * If the called Duration instance is INDEFINITE, return INDEFINITE. 292 * If the called Duration instance is UNKNOWN, return UNKNOWN. 293 * This method does not change the value of the called Duration instance. 294 * 295 * @param n the amount to divide by in fractional milliseconds 296 * @return the result of dividing this duration with n. This is 297 * the same as millis / n using double arithmetic 298 */ 299 public Duration divide(double n) { 300 return millis(millis / n); 301 } 302 303 /** 304 * Divide this instance by another Duration to return the ratio. 305 * If both instances are INDEFINITE, return NaN. 306 * If this instance is INDEFINITE, return POSITIVE_INFINITY 307 * If the other instance is INDEFINITE, return 0.0. 308 * This function does not change the value of the called Duration instance. 309 * 310 * @deprecated This method produces surprising results by not taking units into 311 * account. Use {@link #divide(double)} instead. 312 * @param other must not be null 313 * @return the result of dividing this duration by the other duration. This is 314 * the same as millis / other.millis using double arithmetic 315 */ 316 @Deprecated 317 public Duration divide(Duration other) { 318 return millis(millis / other.millis); 319 } 320 321 /** 322 * Return a new Duration instance which has a negative number of milliseconds 323 * from this instance. For example, <code>Duration.millis(50).negate()</code> returns 324 * a Duration of -50 milliseconds. 325 * If the called Duration instance is INDEFINITE, return INDEFINITE. 326 * This function does not change the value of the called Duration instance. 327 * 328 * @return the result of negating this duration. This is 329 * the same as -millis using double arithmetic 330 */ 331 public Duration negate() { 332 return millis(-millis); 333 } 334 335 /** 336 * Gets whether this Duration instance is Indefinite. A Duration is Indefinite 337 * if it equals Duration.INDEFINITE. 338 * @return true if this Duration is equivalent to Duration.INDEFINITE or Double.POSITIVE_INFINITY. 339 */ 340 public boolean isIndefinite() { 341 return millis == Double.POSITIVE_INFINITY; 342 } 343 344 /** 345 * Gets whether this Duration instance is Unknown. A Duration is Unknown 346 * if it equals Duration.UNKNOWN. 347 * @return true if this Duration is equivalent to Duration.UNKNOWN or Double.isNaN(millis) 348 */ 349 public boolean isUnknown() { 350 return Double.isNaN(millis); 351 } 352 353 /** 354 * Returns true if the specified duration is less than (<) this instance. 355 * INDEFINITE is treated as if it were positive infinity. 356 * 357 * @param other cannot be null 358 * @return true if millis < other.millis using double arithmetic 359 */ 360 public boolean lessThan(Duration other) { 361 return millis < other.millis; 362 } 363 364 /** 365 * Returns true if the specified duration is less than or equal to (<=) this instance. 366 * INDEFINITE is treated as if it were positive infinity. 367 * 368 * @param other cannot be null 369 * @return true if millis <= other.millis using double arithmetic 370 */ 371 public boolean lessThanOrEqualTo(Duration other) { 372 return millis <= other.millis; 373 } 374 375 /** 376 * Returns true if the specified duration is greater than (>) this instance. 377 * INDEFINITE is treated as if it were positive infinity. 378 * 379 * @param other cannot be null 380 * @return true if millis > other.millis using double arithmetic 381 */ 382 public boolean greaterThan(Duration other) { 383 return millis > other.millis; 384 } 385 386 /** 387 * Returns true if the specified duration is greater than or equal to (>=) this instance. 388 * INDEFINITE is treated as if it were positive infinity. 389 * 390 * @param other cannot be null 391 * @return true if millis >= other.millis using double arithmetic 392 */ 393 public boolean greaterThanOrEqualTo(Duration other) { 394 return millis >= other.millis; 395 } 396 397 /** 398 * Returns a string representation of this {@code Duration} object. 399 * @return a string representation of this {@code Duration} object. 400 */ 401 @Override public String toString() { 402 return isIndefinite() ? "INDEFINITE" : (isUnknown() ? "UNKNOWN" : millis + " ms"); 403 } 404 405 /** 406 * Compares durations represented by this object and the specified object. 407 * Returns a negative integer, zero, or a positive integer as this duration 408 * is less than, equal to, or greater than the specified duration. 409 * @param d the duration to be compared. 410 * @return a negative integer, zero, or a positive integer as this duration 411 * is less than, equal to, or greater than the specified duration. 412 */ 413 @Override public int compareTo(Duration d) { 414 // Reuse the Double.compare implementation 415 return Double.compare(millis, d.millis); 416 } 417 418 /** 419 * Indicates whether some other object is "equal to" this one. 420 * @param obj the reference object with which to compare. 421 * @return {@code true} if this object is equal to the {@code obj} argument; {@code false} otherwise. 422 */ 423 @Override public boolean equals(Object obj) { 424 // Rely on Java's handling of double == double 425 return obj == this || obj instanceof Duration && millis == ((Duration) obj).millis; 426 } 427 428 /** 429 * Returns a hash code for this {@code Duration} object. 430 * @return a hash code for this {@code Duration} object. 431 */ 432 @Override public int hashCode() { 433 // Uses the same implementation as Double.hashCode 434 long bits = Double.doubleToLongBits(millis); 435 return (int)(bits ^ (bits >>> 32)); 436 } 437 }