001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.misc; 025 026import microsoft.exchange.webservices.data.core.exception.misc.FormatException; 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029 030/** 031 * The Class TimeSpan. 032 */ 033public class TimeSpan implements Comparable<TimeSpan>, java.io.Serializable, Cloneable { 034 035 private static final Log LOG = LogFactory.getLog(TimeSpan.class); 036 037 /** 038 * Constant serialized ID used for compatibility. 039 */ 040 private static final long serialVersionUID = 1L; 041 042 /** 043 * The time. 044 */ 045 private long time = 0; 046 047 /** 048 * Constant for milliseconds unit and conversion. 049 */ 050 public static final int MILLISECONDS = 1; 051 052 /** 053 * Constant for seconds unit and conversion. 054 */ 055 public static final int SECONDS = MILLISECONDS * 1000; 056 057 /** 058 * Constant for minutes unit and conversion. 059 */ 060 public static final int MINUTES = SECONDS * 60; 061 062 /** 063 * Constant for hours unit and conversion. 064 */ 065 public static final int HOURS = MINUTES * 60; 066 067 /** 068 * Constant for days unit and conversion. 069 */ 070 public static final int DAYS = HOURS * 24; 071 072 /** 073 * Represents the Maximum TimeSpan value. 074 */ 075 public static final TimeSpan MAX_VALUE = new TimeSpan(Long.MAX_VALUE); 076 077 /** 078 * Represents the Minimum TimeSpan value. 079 */ 080 public static final TimeSpan MIN_VALUE = new TimeSpan(Long.MIN_VALUE); 081 082 /** 083 * Represents the TimeSpan with a value of zero. 084 */ 085 public static final TimeSpan ZERO = new TimeSpan(0L); 086 087 /** 088 * Creates a new instance of TimeSpan based on the number of milliseconds 089 * entered. 090 * 091 * @param time the number of milliseconds for this TimeSpan. 092 */ 093 public TimeSpan(long time) { 094 this.time = time; 095 } 096 097 /** 098 * Creates a new TimeSpan object based on the unit and value entered. 099 * 100 * @param units the type of unit to use to create a TimeSpan instance. 101 * @param value the number of units to use to create a TimeSpan instance. 102 */ 103 public TimeSpan(int units, long value) { 104 this.time = TimeSpan.toMilliseconds(units, value); 105 } 106 107 /* 108 * public static TimeSpan fromMinutes(int value) { int l = value*60*100; 109 * return l; } 110 */ 111 112 /** 113 * Subtracts two Date objects creating a new TimeSpan object. 114 * 115 * @param date1 Date to use as the base value. 116 * @param date2 Date to subtract from the base value. 117 * @return a TimeSpan object representing the difference bewteen the two 118 * Date objects. 119 */ 120 public static TimeSpan subtract(java.util.Date date1, 121 java.util.Date date2) { 122 return new TimeSpan(date1.getTime() - date2.getTime()); 123 } 124 125 /** 126 * Compares this object with the specified object for order. Returns a 127 * negative integer, zero, or a positive integer as this object is less 128 * than, equal to, or greater than the specified object. Comparison is based 129 * on the number of milliseconds in this TimeSpan. 130 * 131 * @param o the Object to be compared. 132 * @return a negative integer, zero, or a positive integer as this object is 133 * less than, equal to, or greater than the specified object. 134 */ 135 public int compareTo(TimeSpan o) { 136 TimeSpan compare = (TimeSpan) o; 137 if (this.time == compare.time) { 138 return 0; 139 } 140 if (this.time > compare.time) { 141 return +1; 142 } 143 return -1; 144 } 145 146 /** 147 * Indicates whether some other object is "equal to" this one. Comparison is 148 * based on the number of milliseconds in this TimeSpan. 149 * 150 * @param obj the reference object with which to compare. 151 * @return if the obj argument is a TimeSpan object with the exact same 152 * number of milliseconds. otherwise. 153 */ 154 public boolean equals(Object obj) { 155 if (obj instanceof TimeSpan) { 156 TimeSpan compare = (TimeSpan) obj; 157 if (this.time == compare.time) { 158 return true; 159 } 160 } 161 return false; 162 } 163 164 /** 165 * Returns a hash code value for the object. This method is supported for 166 * the benefit of hashtables such as those provided by 167 * <code>java.util.Hashtable</code>. The method uses the same algorithm as 168 * found in the Long class. 169 * 170 * @return a hash code value for this object. 171 * @see Object#equals(Object) 172 * @see java.util.Hashtable 173 */ 174 public int hashCode() { 175 return Long.valueOf(this.time).hashCode(); 176 } 177 178 /** 179 * Returns a string representation of the object in the format. 180 * "[-]d.hh:mm:ss.ff" where "-" is an optional sign for negative TimeSpan 181 * values, the "d" component is days, "hh" is hours, "mm" is minutes, "ss" 182 * is seconds, and "ff" is milliseconds 183 * 184 * @return a string containing the number of milliseconds. 185 */ 186 public String toString() { 187 StringBuffer sb = new StringBuffer(); 188 long millis = this.time; 189 if (millis < 0) { 190 sb.append("-"); 191 millis = -millis; 192 } 193 194 long day = millis / TimeSpan.DAYS; 195 196 if (day != 0) { 197 sb.append(day); 198 sb.append("d."); 199 millis = millis % TimeSpan.DAYS; 200 } 201 202 sb.append(millis / TimeSpan.HOURS); 203 millis = millis % TimeSpan.HOURS; 204 sb.append("h:"); 205 sb.append(millis / TimeSpan.MINUTES); 206 millis = millis % TimeSpan.MINUTES; 207 sb.append("m:"); 208 sb.append(millis / TimeSpan.SECONDS); 209 sb.append("s"); 210 millis = millis % TimeSpan.SECONDS; 211 if (millis != 0) { 212 sb.append("."); 213 sb.append(millis); 214 sb.append("ms"); 215 } 216 return sb.toString(); 217 } 218 219 /** 220 * Returns a clone of this TimeSpan. 221 * 222 * @return a clone of this TimeSpan. 223 */ 224 public Object clone() { 225 try { 226 return super.clone(); 227 } catch (CloneNotSupportedException e) { 228 LOG.error(e); 229 throw new InternalError(); 230 } 231 } 232 233 /** 234 * Indicates whether the value of the TimeSpan is positive. 235 * 236 * @return if the value of the TimeSpan is greater than 237 * zero. otherwise. 238 */ 239 public boolean isPositive() { 240 return this.compareTo(TimeSpan.ZERO) > 0 ? true : false; 241 } 242 243 /** 244 * Indicates whether the value of the TimeSpan is negative. 245 * 246 * @return if the value of the TimeSpan is less than zero. 247 * otherwise. 248 */ 249 public boolean isNegative() { 250 return this.compareTo(TimeSpan.ZERO) < 0 ? true : false; 251 } 252 253 /** 254 * Indicates whether the value of the TimeSpan is zero. 255 * 256 * @return if the value of the TimeSpan is equal to zero. 257 * otherwise. 258 */ 259 public boolean isZero() { 260 return this.equals(TimeSpan.ZERO); 261 } 262 263 /** 264 * Gets the number of milliseconds. 265 * 266 * @return the number of milliseconds. 267 */ 268 public long getMilliseconds() { 269 return (((this.time % TimeSpan.HOURS) % TimeSpan.MINUTES) % TimeSpan.MILLISECONDS) 270 / TimeSpan.MILLISECONDS; 271 } 272 273 /** 274 * Gets the number of milliseconds. 275 * 276 * @return the number of milliseconds. 277 */ 278 public long getTotalMilliseconds() { 279 return this.time; 280 } 281 282 /** 283 * Gets the number of seconds (truncated). 284 * 285 * @return the number of seconds. 286 */ 287 public long getSeconds() { 288 return ((this.time % TimeSpan.HOURS) % TimeSpan.MINUTES) / TimeSpan.SECONDS; 289 } 290 291 /** 292 * Gets the number of seconds including fractional seconds. 293 * 294 * @return the number of seconds. 295 */ 296 public double getTotalSeconds() { 297 return this.time / 1000.0d; 298 } 299 300 /** 301 * Gets the number of minutes (truncated). 302 * 303 * @return the number of minutes. 304 */ 305 public long getMinutes() { 306 return (this.time % TimeSpan.HOURS) / TimeSpan.MINUTES;// (this.time/1000)/60; 307 } 308 309 /** 310 * Gets the number of minutes including fractional minutes. 311 * 312 * @return the number of minutes. 313 */ 314 public double getTotalMinutes() { 315 return (this.time / 1000.0d) / 60.0d; 316 } 317 318 /** 319 * Gets the number of hours (truncated). 320 * 321 * @return the number of hours. 322 */ 323 public long getHours() { 324 return ((this.time / 1000) / 60) / 60; 325 } 326 327 /** 328 * Gets the number of hours including fractional hours. 329 * 330 * @return the number of hours. 331 */ 332 public double getTotalHours() { 333 return ((this.time / 1000.0d) / 60.0d) / 60.0d; 334 } 335 336 /** 337 * Gets the number of days (truncated). 338 * 339 * @return the number of days. 340 */ 341 public long getDays() { 342 return (((this.time / 1000) / 60) / 60) / 24; 343 } 344 345 /** 346 * Gets the number of days including fractional days. 347 * 348 * @return the number of days. 349 */ 350 public double getTotalDays() { 351 return (((this.time / 1000.0d) / 60.0d) / 60.0d) / 24.0d; 352 } 353 354 /** 355 * Adds a TimeSpan to this TimeSpan. 356 * 357 * @param timespan the TimeSpan to add to this TimeSpan. 358 */ 359 public void add(TimeSpan timespan) { 360 add(TimeSpan.MILLISECONDS, timespan.time); 361 } 362 363 /** 364 * Adds a number of units to this TimeSpan. 365 * 366 * @param units the type of unit to add to this TimeSpan. 367 * @param value the number of units to add to this TimeSpan. 368 */ 369 public void add(int units, long value) { 370 this.time += TimeSpan.toMilliseconds(units, value); 371 } 372 373 /** 374 * Compares two TimeSpan objects. 375 * 376 * @param first first TimeSpan to use in the compare. 377 * @param second second TimeSpan to use in the compare. 378 * @return a negative integer, zero, or a positive integer as the first 379 * TimeSpan is less than, equal to, or greater than the second 380 * TimeSpan. 381 */ 382 public static int compare(TimeSpan first, TimeSpan second) { 383 if (first.time == second.time) { 384 return 0; 385 } 386 if (first.time > second.time) { 387 return +1; 388 } 389 return -1; 390 } 391 392 /** 393 * Returns a TimeSpan whose value is the absolute value of this TimeSpan. 394 * 395 * @return a TimeSpan whose value is the absolute value of this TimeSpan. 396 */ 397 public TimeSpan duration() { 398 return new TimeSpan(Math.abs(this.time)); 399 } 400 401 /** 402 * Returns a TimeSpan whose value is the negated value of this TimeSpan. 403 * 404 * @return a TimeSpan whose value is the negated value of this TimeSpan. 405 */ 406 public TimeSpan negate() { 407 return new TimeSpan(-this.time); 408 } 409 410 /** 411 * Subtracts a TimeSpan from this TimeSpan. 412 * 413 * @param timespan the TimeSpan to subtract from this TimeSpan. 414 */ 415 public void subtract(TimeSpan timespan) { 416 subtract(TimeSpan.MILLISECONDS, timespan.time); 417 } 418 419 /** 420 * Subtracts a number of units from this TimeSpan. 421 * 422 * @param units the type of unit to subtract from this TimeSpan. 423 * @param value the number of units to subtract from this TimeSpan. 424 */ 425 public void subtract(int units, long value) { 426 add(units, -value); 427 } 428 429 /** 430 * To milliseconds. 431 * 432 * @param units the units 433 * @param value the value 434 * @return the long 435 */ 436 private static long toMilliseconds(int units, long value) { 437 long millis; 438 switch (units) { 439 case TimeSpan.MILLISECONDS: 440 case TimeSpan.SECONDS: 441 case TimeSpan.MINUTES: 442 case TimeSpan.HOURS: 443 case TimeSpan.DAYS: 444 millis = value * units; 445 break; 446 default: 447 throw new IllegalArgumentException("Unrecognized units: " + units); 448 } 449 return millis; 450 } 451 452 public static TimeSpan parse(String s) throws Exception { 453 String str = s.trim(); 454 String[] st1 = str.split("\\."); 455 int days = 0, millsec = 0, totMillSec = 0; 456 String data = str; 457 switch (st1.length) { 458 case 1: 459 data = str; 460 break; 461 case 2: 462 if (st1[0].split(":").length > 1) { 463 millsec = Integer.parseInt(st1[1]); 464 data = st1[0]; 465 } else { 466 days = Integer.parseInt(st1[0]); 467 data = st1[1]; 468 } 469 break; 470 case 3: 471 days = Integer.parseInt(st1[0]); 472 data = st1[1]; 473 millsec = Integer.parseInt(st1[2]); 474 break; 475 default: 476 throw new FormatException("Bad Format"); 477 478 } 479 String[] st = data.split(":"); 480 switch (st.length) { 481 case 1: 482 totMillSec = Integer.parseInt(str) * 24 * 60 * 60 * 1000; 483 break; 484 case 2: 485 totMillSec = (Integer.parseInt(st[0]) * 60 * 60 * 1000) + (Integer.parseInt(st[1]) * 60 * 1000); 486 break; 487 case 3: 488 totMillSec = (Integer.parseInt(st[0]) * 60 * 60 * 1000) + (Integer.parseInt(st[1]) * 60 * 1000) + ( 489 Integer.parseInt(st[2]) * 1000); 490 break; 491 case 4: 492 totMillSec = 493 (Integer.parseInt(st[0]) * 24 * 60 * 60 * 1000) + (Integer.parseInt(st[1]) * 60 * 60 * 1000) + ( 494 Integer.parseInt(st[2]) * 60 * 1000) + (Integer.parseInt(st[3]) * 1000); 495 break; 496 default: 497 throw new FormatException("Bad Format/Overflow"); 498 } 499 totMillSec += (days * 24 * 60 * 60 * 1000) + millsec; 500 return new TimeSpan(totMillSec); 501 } 502 503}