001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.time; 018 019import java.util.Locale; 020import java.util.Locale.Category; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023import org.apache.wicket.util.string.StringValue; 024import org.apache.wicket.util.string.StringValueConversionException; 025import org.apache.wicket.util.thread.ICode; 026import org.slf4j.Logger; 027 028 029/** 030 * A <code>Duration</code> is an immutable length of time stored as a number of milliseconds. 031 * Various factory and conversion methods are available for convenience. 032 * <p> 033 * These static factory methods allow easy construction of value objects using either long values 034 * like <code>seconds(2034)</code> or <code>hours(3)</code>: 035 * <p> 036 * <ul> 037 * <li><code>Duration.milliseconds(long)</code> 038 * <li><code>Duration.seconds(int)</code> 039 * <li><code>Duration.minutes(int)</code> 040 * <li><code>Duration.hours(int)</code> 041 * <li><code>Duration.days(int)</code> 042 * </ul> 043 * <p> 044 * ...or double-precision floating point values like <code>days(3.2)</code>: 045 * <p> 046 * <ul> 047 * <li><code>Duration.milliseconds(double)</code> 048 * <li><code>Duration.seconds(double)</code> 049 * <li><code>Duration.minutes(double)</code> 050 * <li><code>Duration.hours(double)</code> 051 * <li><code>Duration.days(double)</code> 052 * </ul> 053 * <p> 054 * In the case of <code>milliseconds(double)</code>, the value will be rounded off to the nearest 055 * integral millisecond using <code>Math.round()</code>. 056 * <p> 057 * The precise number of milliseconds represented by a <code>Duration</code> object can be retrieved 058 * by calling the <code>getMilliseconds</code> method. The value of a <code>Duration</code> object 059 * in a given unit like days or hours can be retrieved by calling one of the following unit methods, 060 * each of which returns a double-precision floating point number: 061 * <p> 062 * <ul> 063 * <li><code>seconds()</code> 064 * <li><code>minutes()</code> 065 * <li><code>hours()</code> 066 * <li><code>days()</code> 067 * </ul> 068 * <p> 069 * Values can be added and subtracted using the <code>add(Duration)</code> and 070 * <code>subtract(Duration)</code> methods, each of which returns a new immutable 071 * <code>Duration</code> object. 072 * <p> 073 * <code>String</code> values can be converted to <code>Duration</code> objects using the static 074 * <code>valueOf</code> factory methods. The <code>String</code> format is the opposite of the one 075 * created by <code>toString()</code>, which converts a <code>Duration</code> object to a readable 076 * form, such as "3.2 hours" or "32.5 minutes". Valid units are: milliseconds, seconds, minutes 077 * hours and days. Correct English plural forms are used in creating <code>String</code> values and 078 * are parsed as well. The <code>Locale</code> is respected and "," will be used instead of "." in 079 * the Eurozone. 080 * <p> 081 * The benchmark method will "benchmark" a <code>Runnable</code> or an {@link ICode} implementing 082 * object, returning a <code>Duration</code> object that represents the amount of time elapsed in 083 * running the code. 084 * <p> 085 * Finally, the <code>sleep</code> method will sleep for the value of a <code>Duration</code>. 086 * 087 * @author Jonathan Locke 088 * @since 1.2.6 089 * 090 * @deprecated Since Wicket 9 this class is obsolete and no more used. It will be removed in Wicket 10. Use {@link java.time.Duration} instead 091 */ 092@Deprecated 093public class Duration extends AbstractTimeValue 094{ 095 private static final long serialVersionUID = 1L; 096 097 /** Constant for maximum duration. */ 098 public static final Duration MAXIMUM = milliseconds(Long.MAX_VALUE); 099 100 /** Constant for no duration. */ 101 public static final Duration NONE = milliseconds(0); 102 103 /** Constant for one day. */ 104 public static final Duration ONE_DAY = days(1); 105 106 /** Constant for one hour. */ 107 public static final Duration ONE_HOUR = hours(1); 108 109 /** Constant for on minute. */ 110 public static final Duration ONE_MINUTE = minutes(1); 111 112 /** Constant for one second. */ 113 public static final Duration ONE_SECOND = seconds(1); 114 115 /** Constant for one week. */ 116 public static final Duration ONE_WEEK = days(7); 117 118 /** pattern to match strings */ 119 private static final Pattern pattern = Pattern.compile( 120 "([0-9]+([.,][0-9]+)?)\\s+(millisecond|second|minute|hour|day)s?", Pattern.CASE_INSENSITIVE); 121 122 /** 123 * Benchmark the given command. 124 * 125 * @param code 126 * an <code>ICode</code> 127 * @param log 128 * optional logger to use with errors and exceptions 129 * @return the <code>Time</code> value it took to run the code 130 */ 131 public static Duration benchmark(final ICode code, final Logger log) 132 { 133 // Get time before running code 134 final Time start = Time.now(); 135 136 // Run the code 137 code.run(log); 138 139 // Return the difference 140 return Time.now().subtract(start); 141 } 142 143 /** 144 * Benchmark the given command. 145 * 146 * @param code 147 * a <code>Runnable</code> 148 * @return the <code>Time</code> value it took to run the code 149 */ 150 public static Duration benchmark(final Runnable code) 151 { 152 // Get time before running code 153 final Time start = Time.now(); 154 155 // Run code 156 code.run(); 157 158 // Return the difference 159 return Time.now().subtract(start); 160 } 161 162 /** 163 * Retrieves the <code>Duration</code> based on days. 164 * 165 * @param days 166 * days <code>double</code> value 167 * @return the <code>Duration</code> based on days 168 */ 169 public static Duration days(final double days) 170 { 171 return hours(24.0 * days); 172 } 173 174 /** 175 * Retrieves the <code>Duration</code> based on days. 176 * 177 * @param days 178 * days <code>int</code> value 179 * @return the <code>Duration</code> based on days 180 */ 181 public static Duration days(final int days) 182 { 183 return hours(24 * days); 184 } 185 186 /** 187 * Calculates the amount of time elapsed since start time. 188 * 189 * @param start 190 * the start <code>Time</code> 191 * @return the elapsed period as a <code>Duration</code> 192 * @throws IllegalStateException 193 * if start <code>Time</code> is in the future 194 */ 195 public static Duration elapsed(final Time start) 196 { 197 return start.elapsedSince(); 198 } 199 200 /** 201 * Retrieves the <code>Duration</code> based on hours. 202 * 203 * @param hours 204 * hours <code>double</code> value 205 * @return the <code>Duration</code> based on hours 206 */ 207 public static Duration hours(final double hours) 208 { 209 return minutes(60.0 * hours); 210 } 211 212 /** 213 * Retrieves the <code>Duration</code> based on hours. 214 * 215 * @param hours 216 * hours <code>int</code> value 217 * @return the <code>Duration</code> based on hours 218 */ 219 public static Duration hours(final int hours) 220 { 221 return minutes(60 * hours); 222 } 223 224 /** 225 * Retrieves the <code>Duration</code> based on milliseconds. 226 * 227 * @param milliseconds 228 * milliseconds <code>double</code> value 229 * @return the <code>Duration</code> based on milliseconds 230 */ 231 public static Duration milliseconds(final double milliseconds) 232 { 233 return milliseconds(Math.round(milliseconds)); 234 } 235 236 /** 237 * Retrieves the <code>Duration</code> based on milliseconds. 238 * 239 * @param milliseconds 240 * milliseconds <code>long</code> value 241 * @return the <code>Duration</code> based on milliseconds 242 */ 243 public static Duration milliseconds(final long milliseconds) 244 { 245 return new Duration(milliseconds); 246 } 247 248 /** 249 * Retrieves the <code>Duration</code> based on minutes. 250 * 251 * @param minutes 252 * minutes <code>double</code> value 253 * @return the <code>Duration</code> based on minutes 254 */ 255 public static Duration minutes(final double minutes) 256 { 257 return seconds(60.0 * minutes); 258 } 259 260 /** 261 * Retrieves the <code>Duration</code> based on minutes. 262 * 263 * @param minutes 264 * minutes <code>int</code> value 265 * @return the <code>Duration</code> based on minutes 266 */ 267 public static Duration minutes(final int minutes) 268 { 269 return seconds(60 * minutes); 270 } 271 272 /** 273 * Retrieves the <code>Duration</code> based on seconds. 274 * 275 * @param seconds 276 * seconds <code>double</code> value 277 * @return the <code>Duration</code> based on seconds 278 */ 279 public static Duration seconds(final double seconds) 280 { 281 return milliseconds(seconds * 1000.0); 282 } 283 284 /** 285 * Retrieves the <code>Duration</code> based on seconds. 286 * 287 * @param seconds 288 * seconds <code>int</code> value 289 * @return the <code>Duration</code> based on seconds 290 */ 291 public static Duration seconds(final int seconds) 292 { 293 return milliseconds(seconds * 1000L); 294 } 295 296 /** 297 * Retrieves the given <code>long</code> as a <code>Duration</code>. 298 * 299 * @param time 300 * the duration <code>long</code> value in milliseconds 301 * @return the <code>Duration</code> value 302 */ 303 public static Duration valueOf(final long time) 304 { 305 return new Duration(time); 306 } 307 308 /** 309 * Converts the given <code>String</code> to a new <code>Duration</code> object. The string can 310 * take the form of a floating point number followed by a number of milliseconds, seconds, 311 * minutes, hours or days. For example "6 hours" or "3.4 days". Parsing is case-insensitive. 312 * 313 * @param string 314 * a <code>String</code> to parse 315 * @return the <code>Duration</code> value of the given <code>String</code> 316 * @throws StringValueConversionException 317 */ 318 public static Duration valueOf(final String string) throws StringValueConversionException 319 { 320 return valueOf(string, Locale.getDefault(Locale.Category.FORMAT)); 321 } 322 323 /** 324 * Converts the given <code>String</code> to a new <code>Duration</code> object. The string can 325 * take the form of a floating point number followed by a number of milliseconds, seconds, 326 * minutes, hours or days. For example "6 hours" or "3.4 days". Parsing is case-insensitive. 327 * 328 * @param string 329 * a <code>String</code> to parse 330 * @param locale 331 * the <code>Locale</code> used for parsing 332 * @return the <code>Duration</code> value of the given <code>String</code> 333 * @throws StringValueConversionException 334 */ 335 public static Duration valueOf(final String string, final Locale locale) 336 throws StringValueConversionException 337 { 338 final Matcher matcher = pattern.matcher(string); 339 340 if (matcher.matches()) 341 { 342 final double value = StringValue.valueOf(matcher.group(1), locale).toDouble(); 343 final String units = matcher.group(3); 344 345 if (units.equalsIgnoreCase("millisecond")) 346 { 347 return milliseconds(value); 348 } 349 else if (units.equalsIgnoreCase("second")) 350 { 351 return seconds(value); 352 } 353 else if (units.equalsIgnoreCase("minute")) 354 { 355 return minutes(value); 356 } 357 else if (units.equalsIgnoreCase("hour")) 358 { 359 return hours(value); 360 } 361 else if (units.equalsIgnoreCase("day")) 362 { 363 return days(value); 364 } 365 else 366 { 367 throw new StringValueConversionException("Unrecognized units: " + string); 368 } 369 } 370 else 371 { 372 throw new StringValueConversionException("Unable to parse duration: " + string); 373 } 374 } 375 376 /** 377 * Private constructor forces use of static factory methods. 378 * 379 * @param milliseconds 380 * number of milliseconds in this <code>Duration</code> 381 */ 382 protected Duration(final long milliseconds) 383 { 384 super(milliseconds); 385 } 386 387 /** 388 * Adds a given <code>Duration</code> to this <code>Duration</code>. 389 * 390 * @param duration 391 * the <code>Duration</code> to add 392 * @return the sum of the <code>Duration</code>s 393 */ 394 public Duration add(final Duration duration) 395 { 396 return valueOf(getMilliseconds() + duration.getMilliseconds()); 397 } 398 399 /** 400 * Retrieves the number of days of the current <code>Duration</code>. 401 * 402 * @return number of days of the current <code>Duration</code> 403 */ 404 public final double days() 405 { 406 return hours() / 24.0; 407 } 408 409 /** 410 * Retrieves the number of hours of the current <code>Duration</code>. 411 * 412 * @return number of hours of the current <code>Duration</code> 413 */ 414 public final double hours() 415 { 416 return minutes() / 60.0; 417 } 418 419 /** 420 * Retrieves the number of minutes of the current <code>Duration</code>. 421 * 422 * @return number of minutes of the current <code>Duration</code> 423 */ 424 public final double minutes() 425 { 426 return seconds() / 60.0; 427 } 428 429 /** 430 * Retrieves the number of seconds of the current <code>Duration</code>. 431 * 432 * @return number of seconds of the current <code>Duration</code> 433 */ 434 public final double seconds() 435 { 436 return getMilliseconds() / 1000.0; 437 } 438 439 /** 440 * Sleeps for the current <code>Duration</code>. 441 */ 442 public final void sleep() 443 { 444 if (getMilliseconds() > 0) 445 { 446 try 447 { 448 Thread.sleep(getMilliseconds()); 449 } 450 catch (InterruptedException e) 451 { 452 // Ignored 453 } 454 } 455 } 456 457 /** 458 * Subtracts a given <code>Duration</code> from this <code>Duration</code>. 459 * 460 * @param that 461 * the <code>Duration</code> to subtract 462 * @return this <code>Duration</code> minus that <code>Duration</code> 463 */ 464 public Duration subtract(final Duration that) 465 { 466 return valueOf(getMilliseconds() - that.getMilliseconds()); 467 } 468 469 /** 470 * Wait for this duration on the given monitor 471 * 472 * @param object 473 * The monitor to wait on 474 */ 475 public void wait(final Object object) 476 { 477 try 478 { 479 object.wait(getMilliseconds()); 480 } 481 catch (InterruptedException e) 482 { 483 throw new RuntimeException(e); 484 } 485 } 486 487 /** 488 * Retrieves the <code>String</code> representation of this <code>Duration</code> in days, 489 * hours, minutes, seconds or milliseconds, as appropriate. Uses the default <code>Locale</code> 490 * . 491 * 492 * @return a <code>String</code> representation 493 */ 494 @Override 495 public String toString() 496 { 497 return toString(Locale.getDefault(Category.FORMAT)); 498 } 499 500 /** 501 * Retrieves the <code>String</code> representation of this <code>Duration</code> in days, 502 * hours, minutes, seconds or milliseconds, as appropriate. 503 * 504 * @param locale 505 * a <code>Locale</code> 506 * @return a <code>String</code> representation 507 */ 508 public String toString(final Locale locale) 509 { 510 if (getMilliseconds() >= 0) 511 { 512 if (days() >= 1.0) 513 { 514 return unitString(days(), "day", locale); 515 } 516 517 if (hours() >= 1.0) 518 { 519 return unitString(hours(), "hour", locale); 520 } 521 522 if (minutes() >= 1.0) 523 { 524 return unitString(minutes(), "minute", locale); 525 } 526 527 if (seconds() >= 1.0) 528 { 529 return unitString(seconds(), "second", locale); 530 } 531 532 return unitString(getMilliseconds(), "millisecond", locale); 533 } 534 else 535 { 536 return "N/A"; 537 } 538 } 539 540 /** 541 * Builds a {@link java.time.Duration} out of a wicket {@link Duration}. 542 * 543 * @return returns a {@link java.time.Duration} 544 */ 545 public java.time.Duration toJavaDuration() 546 { 547 return java.time.Duration.ofMillis(getMilliseconds()); 548 } 549 550 /** 551 * Converts a value to a unit-suffixed value, taking care of English singular/plural suffix. 552 * 553 * @param value 554 * a <code>double</code> value to format 555 * @param units 556 * the units to apply singular or plural suffix to 557 * @param locale 558 * the <code>Locale</code> 559 * @return a <code>String</code> representation 560 */ 561 private String unitString(final double value, final String units, final Locale locale) 562 { 563 return StringValue.valueOf(value, locale) + " " + units + ((value > 1.0) ? "s" : ""); 564 } 565}