View Javadoc

1   /*
2    * $Id: DurationFormat.java [15-May-2004]
3    *
4    * Copyright (c) 2004, Ben Fortuna
5    * All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 	o Redistributions of source code must retain the above copyright
12   * notice, this list of conditions and the following disclaimer.
13   *
14   * 	o Redistributions in binary form must reproduce the above copyright
15   * notice, this list of conditions and the following disclaimer in the
16   * documentation and/or other materials provided with the distribution.
17   *
18   * 	o Neither the name of Ben Fortuna nor the names of any other contributors
19   * may be used to endorse or promote products derived from this software
20   * without specific prior written permission.
21   *
22   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25   * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   */
34  package net.fortuna.ical4j.util;
35  
36  import java.util.StringTokenizer;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  
41  /***
42   * Defines the format used for all iCalendar durations.
43   *
44   * @author benfortuna
45   */
46  public final class DurationFormat {
47  
48      private static final long MILLIS_PER_SECOND = 1000;
49  
50      private static final long MILLIS_PER_MINUTE = 60000;
51  
52      private static final long MILLIS_PER_HOUR = 3600000;
53  
54      private static final long MILLIS_PER_DAY = 86400000;
55  
56      private static final long MILLIS_PER_WEEK = 604800000;
57  
58      private static Log log = LogFactory.getLog(DurationFormat.class);
59  
60      private static DurationFormat instance = new DurationFormat();
61  
62      /***
63       * Constructor made private to enforce singleton.
64       */
65      private DurationFormat() {
66      }
67  
68      /***
69       * @return Returns the instance.
70       */
71      public static DurationFormat getInstance() {
72          return instance;
73      }
74  
75      /***
76       * Parse an iCalendar duration (dur-val) string.
77       *
78       * @param aString
79       *            a string representation of a duration
80       * @return a duration in milliseconds
81       */
82      public long parse(final String aString) {
83  
84          long duration = 0;
85  
86          boolean negative = false;
87  
88          String token = null;
89          String prevToken = null;
90  
91          for (StringTokenizer t = new StringTokenizer(aString, "+-PWDTHMS", true);
92              t.hasMoreTokens();) {
93  
94              prevToken = token;
95  
96              token = t.nextToken();
97  
98              if ("+".equals(token)) {
99                  negative = false;
100             }
101             else if ("-".equals(token)) {
102                 negative = true;
103             }
104             else if ("P".equals(token)) {
105                 // does nothing..
106                 log.debug("Redundant [P] token ignored.");
107             }
108             else if ("W".equals(token)) {
109 
110                 int weeks = Integer.parseInt(prevToken);
111 
112                 duration += weeks * MILLIS_PER_WEEK;
113             }
114             else if ("D".equals(token)) {
115 
116                 int days = Integer.parseInt(prevToken);
117 
118                 duration += days * MILLIS_PER_DAY;
119             }
120             else if ("T".equals(token)) {
121                 // does nothing..
122                 log.debug("Redundant [T] token ignored.");
123             }
124             else if ("H".equals(token)) {
125 
126                 int hours = Integer.parseInt(prevToken);
127 
128                 duration += hours * MILLIS_PER_HOUR;
129             }
130             else if ("M".equals(token)) {
131 
132                 int minutes = Integer.parseInt(prevToken);
133 
134                 duration += minutes * MILLIS_PER_MINUTE;
135             }
136             else if ("S".equals(token)) {
137 
138                 int seconds = Integer.parseInt(prevToken);
139 
140                 duration += seconds * MILLIS_PER_SECOND;
141             }
142         }
143 
144         if (negative) { return -duration; }
145 
146         return duration;
147     }
148 
149     /***
150      * Returns a string representation of a duration.
151      *
152      * @param duration
153      *            a duration in milliseconds
154      * @return a string
155      */
156     public String format(final long duration) {
157 
158         StringBuffer b = new StringBuffer();
159 
160         long remainder = Math.abs(duration);
161 
162         if (duration < 0) {
163             b.append('-');
164         }
165 
166         b.append('P');
167 
168         if (remainder >= MILLIS_PER_WEEK) {
169             b.append(remainder / MILLIS_PER_WEEK);
170             b.append('W');
171         }
172         else {
173 
174             if (remainder >= MILLIS_PER_DAY) {
175                 b.append(remainder / MILLIS_PER_DAY);
176                 b.append('D');
177 
178                 remainder = remainder % MILLIS_PER_DAY;
179             }
180 
181             if (remainder > 0) {
182                 b.append('T');
183             }
184 
185             if (remainder >= MILLIS_PER_HOUR) {
186                 b.append(remainder / MILLIS_PER_HOUR);
187                 b.append('H');
188 
189                 remainder = remainder % MILLIS_PER_HOUR;
190             }
191 
192             if (remainder >= MILLIS_PER_MINUTE) {
193                 b.append(remainder / MILLIS_PER_MINUTE);
194                 b.append('M');
195 
196                 remainder = remainder % MILLIS_PER_MINUTE;
197             }
198 
199             if (remainder >= MILLIS_PER_SECOND) {
200                 b.append(remainder / MILLIS_PER_SECOND);
201                 b.append('S');
202             }
203         }
204 
205         return b.toString();
206     }
207 }