View Javadoc

1   /*
2    * TimeSpan.java
3    *
4    * Created on January 28, 2003, 11:09 AM
5    * ====================================================================
6    *
7    * The JavaRanch Software License, Version 1.0
8    *
9    * Copyright (c) 2003 JavaRanch. All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
12   * following conditions are met:
13   *
14   * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
15   * disclaimer.
16   *
17   * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
18   * disclaimer in the documentation and/or other materials provided with the distribution.
19   *
20   * 3. The name JavaRanch must not be used to endorse or promote products derived from this software without prior written
21   * permission.
22   *
23   * 4. Products derived from this software may not be called "JavaRanch" nor may "JavaRanch" appear in their names without
24   * prior written permission of JavaRanch.
25   *
26   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JAVARANCH OR ITS
28   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32   * POSSIBILITY OF SUCH DAMAGE. ====================================================================
33   *
34   */
35  
36  package com.melloware.jukes.util;
37  
38  import org.apache.commons.lang.StringUtils;
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  
42  /**
43   * The value of an instance of TimeSpan represents a period of time.
44   *
45   * TimeSpan can be used in several ways.
46   *
47   * To calculate the difference in time between two dates:
48   * <PRE>TimeSpan timespan = TimeSpan.subtract(date1, date2);</PRE>
49   *
50   * To add five days to a TimeSpan:
51   * <PRE>timspan.add(TimeSpanUnit.DAYS, 5);</PRE>
52   *
53   * To subtract another TimeSpan object from this one:
54   * <PRE>timspan.subtract(timespan2);</PRE>
55   *
56   * @author Thomas Paul
57   */
58  public class TimeSpan
59      implements Comparable,
60                 java.io.Serializable,
61                 Cloneable {
62  
63  	private static final Log LOG = LogFactory.getLog(TimeSpan.class);
64  	
65      /** Represents the Maximum TimeSpan value */
66      public static final TimeSpan MAX_VALUE = new TimeSpan(Long.MAX_VALUE);
67  
68      /** Represents the Minimum TimeSpan value */
69      public static final TimeSpan MIN_VALUE = new TimeSpan(Long.MIN_VALUE);
70  
71      /** Represents the TimeSpan with a value of zero */
72      public static final TimeSpan ZERO = new TimeSpan(0L);
73  
74      private long time = 0;
75  
76      /** Creates a new instance of TimeSpan based on the number of milliseconds
77      * entered.
78      *
79      * @param time the number of milliseconds for this TimeSpan.
80      *
81      */
82      public TimeSpan(long time) {
83          this.time = time;
84      }
85  
86      /** 
87       * Creates a new TimeSpan object based on the unit and value entered.
88       *
89       * @param unit the type of unit to use to create a TimeSpan instance.
90       * @param value the number of units to use to create a TimeSpan instance.
91       */
92      public TimeSpan(TimeSpanUnit unit, long value) {
93          this.time = TimeSpan.toMilliseconds(unit, value);
94      }
95  
96      /** Compares two TimeSpan objects.
97      *
98      * @param first first TimeSpan to use in the compare.
99      * @param second second TimeSpan to use in the compare.
100     *
101     * @return a negative integer, zero, or a positive integer as the first
102     * TimeSpan is less than, equal to, or greater than the
103     * second TimeSpan.
104     *
105     */
106     public static int compare(TimeSpan first, TimeSpan second) {
107         if (first.time == second.time) {
108             return 0;
109         }
110         if (first.time > second.time) {
111             return +1;
112         }
113         return -1;
114     }
115 
116     /** Subtracts two Date objects creating a new TimeSpan object.
117     *
118     * @param date1 Date to use as the base value.
119     * @param date2 Date to subtract from the base value.
120     *
121     * @return a TimeSpan object representing the difference bewteen the
122     * two Date objects.
123     *
124     */
125     public static TimeSpan subtract(java.util.Date date1, java.util.Date date2) {
126         return new TimeSpan(date1.getTime() - date2.getTime());
127     }
128 
129     /** Gets the number of days (truncated).
130     *
131     * @return the number of days.
132     */
133     public long getDays() {
134         return (((this.time / 1000) / 60) / 60) / 24;
135     }
136 
137     /** Gets the number of hours (truncated).
138     *
139     * @return the number of hours.
140     */
141     public long getHours() {
142         return ((this.time / 1000) / 60) / 60;
143     }
144 
145     /** Gets the number of milliseconds.
146     *
147     * @return the number of milliseconds.
148     */
149     public long getMilliseconds() {
150         return this.time;
151     }
152 
153     /** Gets the number of minutes (truncated).
154     *
155     * @return the number of minutes.
156     */
157     public long getMinutes() {
158         return (this.time / 1000) / 60;
159     }
160 
161     /**
162      * Returns a string for music formatting for album length.  So it would
163      * look like 48:03 or 74:15.
164      * @return the string value of the music duration
165      */
166     public String getMusicDuration() {
167         StringBuffer sb = new StringBuffer();
168         long millis = this.time;
169         if (millis < 0) {
170             sb.append('-');
171             millis = -millis;
172         }
173 
174         long day = millis / TimeSpanUnit.TimeSpanConstants.DAYS;
175 
176         if (day != 0) {
177             sb.append(day);
178             sb.append("d.");
179             millis = millis % TimeSpanUnit.TimeSpanConstants.DAYS;
180         }
181 
182         long hours = millis / TimeSpanUnit.TimeSpanConstants.HOURS;
183 
184         if (hours != 0) {
185             sb.append(hours);
186             millis = millis % TimeSpanUnit.TimeSpanConstants.HOURS;
187             sb.append(':');
188         }
189 
190         sb.append(StringUtils.leftPad(Long.toString(millis / TimeSpanUnit.TimeSpanConstants.MINUTES), 2, "0"));
191         millis = millis % TimeSpanUnit.TimeSpanConstants.MINUTES;
192         sb.append(':');
193         sb.append(StringUtils.leftPad(Long.toString(millis / TimeSpanUnit.TimeSpanConstants.SECONDS), 2, "0"));
194         return sb.toString();
195     }
196 
197     /** Gets the number of seconds (truncated).
198     *
199     * @return the number of seconds.
200     */
201     public long getSeconds() {
202         return this.time / 1000;
203     }
204 
205     /** Gets the number of days including fractional days.
206     *
207     * @return the number of days.
208     */
209     public double getTotalDays() {
210         return (((this.time / 1000.0d) / 60.0d) / 60.0d) / 24.0d;
211     }
212 
213     /** Gets the number of hours including fractional hours.
214     *
215     * @return the number of hours.
216     */
217     public double getTotalHours() {
218         return ((this.time / 1000.0d) / 60.0d) / 60.0d;
219     }
220 
221     /** Gets the number of minutes including fractional minutes.
222     *
223     * @return the number of minutes.
224     */
225     public double getTotalMinutes() {
226         return (this.time / 1000.0d) / 60.0d;
227     }
228 
229     /** Gets the number of seconds including fractional seconds.
230     *
231     * @return the number of seconds.
232     */
233     public double getTotalSeconds() {
234         return this.time / 1000.0d;
235     }
236 
237     /** Indicates whether the value of the TimeSpan is negative.
238     *
239     * @return <code>true</code> if the value of the TimeSpan is less
240     * than zero.
241     * <code>false</code> otherwise.
242     *
243     */
244     public boolean isNegative() {
245         return (this.compareTo(TimeSpan.ZERO) < 0) ? true : false;
246     }
247 
248     /** Indicates whether the value of the TimeSpan is positive.
249     *
250     * @return <code>true</code> if the value of the TimeSpan is greater
251     * than zero.
252     * <code>false</code> otherwise.
253     *
254     */
255     public boolean isPositive() {
256         return (this.compareTo(TimeSpan.ZERO) > 0) ? true : false;
257     }
258 
259     /** Indicates whether the value of the TimeSpan is zero.
260     *
261     * @return <code>true</code> if the value of the TimeSpan is equal to zero.
262     * <code>false</code> otherwise.
263     *
264     */
265     public boolean isZero() {
266         return this.equals(TimeSpan.ZERO);
267     }
268 
269     /** Adds a TimeSpan to this TimeSpan.
270     *
271     * @param timespan the TimeSpan to add to this TimeSpan.
272     */
273     public void add(TimeSpan timespan) {
274         add(TimeSpanUnit.MILLISECONDS, timespan.time);
275     }
276 
277     /** 
278      * Adds a number of units to this TimeSpan.
279      *
280      * @param unit the type of unit to add to this TimeSpan.
281      * @param value the number of units to add to this TimeSpan.
282      */
283     public void add(TimeSpanUnit unit, long value) {
284         this.time += TimeSpan.toMilliseconds(unit, value);
285     }
286 
287     /** Returns a clone of this TimeSpan.
288     *
289     * @return a clone of this TimeSpan.
290     */
291     public Object clone() {
292        try {
293 		return super.clone();
294 	   } catch (CloneNotSupportedException ex) {
295 		  LOG.error("CloneNotSupportedException", ex);
296 		  return null;
297 	   }
298     }
299 
300     /** Compares this object with the specified object for order. Returns a
301     * negative integer, zero, or a positive integer as this object is less
302     * than, equal to, or greater than the specified object. Comparison is
303     * based on the number of milliseconds in this TimeSpan.
304     *
305     * @param o the Object to be compared.
306     *
307     * @return a negative integer, zero, or a positive integer as this object
308     * is less than, equal to, or greater than the specified object.
309     *
310     * @throws ClassCastException if the specified object's type prevents it
311     * from being compared to this Object.
312     *
313     */
314     public int compareTo(Object o) {
315         TimeSpan compare = (TimeSpan)o;
316         if (this.time == compare.time) {
317             return 0;
318         }
319         if (this.time > compare.time) {
320             return +1;
321         }
322         return -1;
323     }
324 
325     /** Returns a TimeSpan whose value is the absolute value of this TimeSpan.
326     *
327     * @return a TimeSpan whose value is the absolute value of this TimeSpan.
328     */
329     public TimeSpan duration() {
330         return new TimeSpan(Math.abs(this.time));
331     }
332 
333     /** Indicates whether some other object is "equal to" this one.
334     * Comparison is based on the number of milliseconds in this TimeSpan.
335     *
336     * @param obj the reference object with which to compare.
337     *
338     * @return <code>true</code> if the obj argument is a TimeSpan object
339     * with the exact same number of milliseconds.
340     * <code>false</code> otherwise.
341     *
342     */
343     public boolean equals(Object obj) {
344         if (obj instanceof TimeSpan) {
345             TimeSpan compare = (TimeSpan)obj;
346             if (this.time == compare.time) {
347                 return true;
348             }
349         }
350         return false;
351     }
352 
353     /** Returns a hash code value for the object. This method is
354     * supported for the benefit of hashtables such as those provided by
355     * <code>java.util.Hashtable</code>. The method uses the same
356     * algorithm as found in the Long class.
357     *
358     * @return a hash code value for this object.
359     *
360     * @see java.lang.Object#equals(java.lang.Object)
361     * @see java.util.Hashtable
362     *
363     */
364     public int hashCode() {
365         return Long.valueOf(this.time).hashCode();
366     }
367 
368     /** Returns a TimeSpan whose value is the negated value of this TimeSpan.
369     *
370     * @return a TimeSpan whose value is the negated value of this TimeSpan.
371     */
372     public TimeSpan negate() {
373         return new TimeSpan(-this.time);
374     }
375 
376     /** Subtracts a TimeSpan from this TimeSpan.
377     *
378     * @param timespan the TimeSpan to subtract from this TimeSpan.
379     */
380     public void subtract(TimeSpan timespan) {
381         subtract(TimeSpanUnit.MILLISECONDS, timespan.time);
382     }
383 
384     /** 
385      * Subtracts a number of units from this TimeSpan.
386      *
387      * @param unit the type of unit to subtract from this TimeSpan.
388      * @param value the number of units to subtract from this TimeSpan.
389      */
390     public void subtract(TimeSpanUnit unit, long value) {
391         add(unit, -value);
392     }
393 
394     /** Returns a string representation of the object in the format
395     * "[-]d.hh:mm:ss.ff" where "-" is an optional sign for negative TimeSpan
396     * values, the "d" component is days, "hh" is hours, "mm" is minutes,
397     * "ss" is seconds, and "ff" is milliseconds
398     *
399     * @return a string containing the number of milliseconds.
400     *
401     */
402     public String toString() {
403         StringBuffer sb = new StringBuffer();
404         long millis = this.time;
405         if (millis < 0) {
406             sb.append('-');
407             millis = -millis;
408         }
409 
410         long day = millis / TimeSpanUnit.TimeSpanConstants.DAYS;
411 
412         if (day != 0) {
413             sb.append(day);
414             sb.append("d.");
415             millis = millis % TimeSpanUnit.TimeSpanConstants.DAYS;
416         }
417 
418         sb.append(millis / TimeSpanUnit.TimeSpanConstants.HOURS);
419         millis = millis % TimeSpanUnit.TimeSpanConstants.HOURS;
420         sb.append("h:");
421         sb.append(StringUtils.leftPad(Long.toString(millis / TimeSpanUnit.TimeSpanConstants.MINUTES), 2, "0"));
422         millis = millis % TimeSpanUnit.TimeSpanConstants.MINUTES;
423         sb.append("m:");
424         sb.append(StringUtils.leftPad(Long.toString(millis / TimeSpanUnit.TimeSpanConstants.SECONDS), 2, "0"));
425         sb.append('s');
426         millis = millis % TimeSpanUnit.TimeSpanConstants.SECONDS;
427         if (millis != 0) {
428             sb.append('.');
429             sb.append(millis);
430             sb.append("ms");
431         }
432         return sb.toString();
433     }
434 
435     private static long toMilliseconds(TimeSpanUnit unit, long value) {
436         return value * unit.getValue();
437     }
438 
439 	/**
440 	 * Gets the time.
441 	 * <p>
442 	 * @return Returns the time.
443 	 */
444 	public long getTime() {
445 		return this.time;
446 	}
447 
448 	/**
449 	 * Sets the time.
450 	 * <p>
451 	 * @param aTime The time to set.
452 	 */
453 	public void setTime(long aTime) {
454 		this.time = aTime;
455 	}
456 }