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
024 package microsoft.exchange.webservices.data.misc;
025
026 import microsoft.exchange.webservices.data.core.exception.misc.FormatException;
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 /**
031 * The Class TimeSpan.
032 */
033 public 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 }