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    }