]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/impl/duration/Period.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / impl / duration / Period.java
1 /*\r
2 ******************************************************************************\r
3 * Copyright (C) 2007, International Business Machines Corporation and   *\r
4 * others. All Rights Reserved.                                               *\r
5 ******************************************************************************\r
6 */\r
7 \r
8 package com.ibm.icu.impl.duration;\r
9 \r
10 import com.ibm.icu.impl.duration.impl.DataRecord.ETimeLimit;\r
11 \r
12 /**\r
13  * Represents an approximate duration in multiple TimeUnits.  Each unit,\r
14  * if set, has a count (which can be fractional and must be non-negative).\r
15  * In addition Period can either represent the duration as being into the past\r
16  * or future, and as being more or less than the defined value.\r
17  * <p>\r
18  * Use a PeriodFormatter to convert a Period to a String.  \r
19  * <p>\r
20  * Periods are immutable.  Mutating operations return the new \r
21  * result leaving the original unchanged.\r
22  * <p>\r
23  * Example:<pre>\r
24  * Period p1 = Period.at(3, WEEK).and(2, DAY).inFuture();\r
25  * Period p2 = p1.and(12, HOUR);</pre>\r
26  */\r
27 public final class Period {\r
28   final byte timeLimit;\r
29   final boolean inFuture;\r
30   final int[] counts;\r
31 \r
32   /**\r
33    * Constructs a Period representing a duration of\r
34    * count units extending into the past.\r
35    * @param count the number of units, must be non-negative\r
36    * @param unit the unit\r
37    * @return the new Period\r
38    */\r
39   public static Period at(float count, TimeUnit unit) {\r
40     checkCount(count);\r
41     return new Period(ETimeLimit.NOLIMIT, false, count, unit);\r
42   }\r
43 \r
44   /**\r
45    * Constructs a Period representing a duration more than\r
46    * count units extending into the past.\r
47    * @param count the number of units. must be non-negative\r
48    * @param unit the unit\r
49    * @return the new Period\r
50    */\r
51   public static Period moreThan(float count, TimeUnit unit) {\r
52     checkCount(count);\r
53     return new Period(ETimeLimit.MT, false, count, unit);\r
54   }\r
55 \r
56   /**\r
57    * Constructs a Period representing a duration\r
58    * less than count units extending into the past.\r
59    * @param count the number of units. must be non-negative\r
60    * @param unit the unit\r
61    * @return the new Period\r
62    */\r
63   public static Period lessThan(float count, TimeUnit unit) {\r
64     checkCount(count);\r
65     return new Period(ETimeLimit.LT, false, count, unit);\r
66   }\r
67 \r
68   /**\r
69    * Set the given unit to have the given count.  Marks the\r
70    * unit as having been set.  This can be used to set\r
71    * multiple units, or to reset a unit to have a new count.\r
72    * This does <b>not</b> add the count to an existing count\r
73    * for this unit.\r
74    *\r
75    * @param count the number of units.  must be non-negative\r
76    * @param unit the unit\r
77    * @return the new Period\r
78    */\r
79   public Period and(float count, TimeUnit unit) {\r
80     checkCount(count);\r
81     return setTimeUnitValue(unit, count);\r
82   }\r
83 \r
84   /**\r
85    * Mark the given unit as not being set.\r
86    *\r
87    * @param unit the unit to unset\r
88    * @return the new Period\r
89    */\r
90   public Period omit(TimeUnit unit) {\r
91     return setTimeUnitInternalValue(unit, 0);\r
92   }\r
93   \r
94   /**\r
95    * Mark the duration as being at the defined duration.\r
96    *\r
97    * @return the new Period\r
98    */\r
99   public Period at() {\r
100     return setTimeLimit(ETimeLimit.NOLIMIT);\r
101   }\r
102 \r
103   /**\r
104    * Mark the duration as being more than the defined duration.\r
105    *\r
106    * @return the new Period\r
107    */\r
108   public Period moreThan() {\r
109     return setTimeLimit(ETimeLimit.MT);\r
110   }\r
111 \r
112   /**\r
113    * Mark the duration as being less than the defined duration.\r
114    *\r
115    * @return the new Period\r
116    */\r
117   public Period lessThan() {\r
118     return setTimeLimit(ETimeLimit.LT);\r
119   }\r
120 \r
121   /**\r
122    * Mark the time as being in the future.\r
123    *\r
124    * @return the new Period\r
125    */\r
126   public Period inFuture() {\r
127     return setFuture(true);\r
128   }\r
129 \r
130   /**\r
131    * Mark the duration as extending into the past.\r
132    *\r
133    * @return the new Period\r
134    */\r
135   public Period inPast() {\r
136     return setFuture(false);\r
137   }\r
138 \r
139   /**\r
140    * Mark the duration as extending into the future if\r
141    * future is true, and into the past otherwise.\r
142    *\r
143    * @param future true if the time is in the future\r
144    * @return the new Period\r
145    */\r
146   public Period inFuture(boolean future) {\r
147     return setFuture(future);\r
148   }\r
149 \r
150   /**\r
151    * Mark the duration as extending into the past if\r
152    * past is true, and into the future otherwise.\r
153    *\r
154    * @param past true if the time is in the past\r
155    * @return the new Period\r
156    */\r
157   public Period inPast(boolean past) {\r
158     return setFuture(!past);\r
159   }\r
160 \r
161   /**\r
162    * Returns true if any unit is set.\r
163    * @return true if any unit is set\r
164    */\r
165   public boolean isSet() {\r
166     for (int i = 0; i < counts.length; ++i) {\r
167       if (counts[i] != 0) {\r
168         return true;\r
169       }\r
170     }\r
171     return false;\r
172   }\r
173 \r
174   /**\r
175    * Returns true if the given unit is set.\r
176    * @param unit the unit to test\r
177    * @return true if the given unit is set.\r
178    */\r
179   public boolean isSet(TimeUnit unit) {\r
180     return counts[unit.ordinal] > 0;\r
181   }\r
182 \r
183   /**\r
184    * Returns the count for the specified unit.  If the\r
185    * unit is not set, returns 0.\r
186    * @param unit the unit to test\r
187    * @return the count\r
188    */\r
189   public float getCount(TimeUnit unit) {\r
190     int ord = unit.ordinal;\r
191     if (counts[ord] == 0) {\r
192       return 0;\r
193     }\r
194     return (counts[ord] - 1)/1000f;\r
195   }\r
196 \r
197   /**\r
198    * Returns true if this represents a \r
199    * duration into the future.\r
200    * @return true if this represents a \r
201    * duration into the future.\r
202    */\r
203   public boolean isInFuture() {\r
204     return inFuture;\r
205   }\r
206 \r
207   /**\r
208    * Returns true if this represents a \r
209    * duration into the past\r
210    * @return true if this represents a \r
211    * duration into the past\r
212    */\r
213   public boolean isInPast  () {\r
214     return !inFuture;\r
215   }\r
216 \r
217   /**\r
218    * Returns true if this represents a duration in\r
219    * excess of the defined duration.\r
220    * @return true if this represents a duration in\r
221    * excess of the defined duration.\r
222    */\r
223   public boolean isMoreThan() {\r
224     return timeLimit == ETimeLimit.MT;\r
225   }\r
226 \r
227   /**\r
228    * Returns true if this represents a duration\r
229    * less than the defined duration.\r
230    * @return true if this represents a duration\r
231    * less than the defined duration.\r
232    */\r
233   public boolean isLessThan() {\r
234     return timeLimit == ETimeLimit.LT;\r
235   }\r
236 \r
237   /** \r
238    * Returns true if rhs extends Period and\r
239    * the two Periods are equal.\r
240    * @param rhs the object to compare to\r
241    * @return true if rhs is a Period and is equal to this\r
242    */\r
243   public boolean equals(Object rhs) {\r
244     try {\r
245       return equals((Period)rhs);\r
246     }\r
247     catch (ClassCastException e) {\r
248       return false;\r
249     }\r
250   }\r
251 \r
252   /**\r
253    * Returns true if the same units are defined with\r
254    * the same counts, both extend into the future or both into the\r
255    * past, and if the limits (at, more than, less than) are the same.\r
256    * Note that this means that a period of 1000ms and a period of 1sec\r
257    * will not compare equal.\r
258    *\r
259    * @param rhs the period to compare to\r
260    * @return true if the two periods are equal\r
261    */\r
262   public boolean equals(Period rhs) {\r
263     if (rhs != null &&\r
264         this.timeLimit == rhs.timeLimit &&\r
265         this.inFuture == rhs.inFuture) {\r
266       for (int i = 0; i < counts.length; ++i) {\r
267         if (counts[i] != rhs.counts[i]) {\r
268           return false;\r
269         }\r
270       }\r
271       return true;\r
272     }\r
273     return false;\r
274   }\r
275 \r
276   /** \r
277    * Returns the hashCode. \r
278    * @return the hashCode\r
279    */\r
280   public int hashCode() {\r
281     int hc = (timeLimit << 1) | (inFuture ? 1 : 0);\r
282     for (int i = 0; i < counts.length; ++i) {\r
283       hc = (hc << 2) ^ counts[i];\r
284     }\r
285     return hc;\r
286   }\r
287 \r
288   /**\r
289    * Private constructor used by static factory methods.\r
290    */\r
291   private Period(int limit, boolean future, float count, TimeUnit unit) {\r
292     this.timeLimit = (byte) limit;\r
293     this.inFuture = future;\r
294     this.counts = new int[TimeUnit.units.length];\r
295     this.counts[unit.ordinal] = (int)(count * 1000) + 1;\r
296   }\r
297 \r
298   /**\r
299    * Package private constructor used by setters and factory.\r
300    */\r
301   Period(int timeLimit, boolean inFuture, int[] counts) {\r
302     this.timeLimit = (byte) timeLimit;\r
303     this.inFuture = inFuture;\r
304     this.counts = counts;\r
305   }\r
306 \r
307   /**\r
308    * Set the unit's internal value, converting from float to int.\r
309    */\r
310   private Period setTimeUnitValue(TimeUnit unit, float value) {\r
311     if (value < 0) {\r
312       throw new IllegalArgumentException("value: " + value);\r
313     }\r
314     return setTimeUnitInternalValue(unit, (int)(value * 1000) + 1);\r
315   }\r
316 \r
317   /** \r
318    * Sets the period to have the provided value, 1/1000 of the\r
319    * unit plus 1.  Thus unset values are '0', 1' is the set value '0',\r
320    * 2 is the set value '1/1000', 3 is the set value '2/1000' etc.\r
321    * @param p the period to change\r
322    * @param value the int value as described above.\r
323    * @eturn the new Period object.\r
324    */\r
325   private Period setTimeUnitInternalValue(TimeUnit unit, int value) {\r
326     int ord = unit.ordinal;\r
327     if (counts[ord] != value) {\r
328       int[] newCounts = new int[counts.length];\r
329       for (int i = 0; i < counts.length; ++i) {\r
330         newCounts[i] = counts[i];\r
331       }\r
332       newCounts[ord] = value;\r
333       return new Period(timeLimit, inFuture, newCounts);\r
334     }\r
335     return this;\r
336   }\r
337 \r
338   /**\r
339    * Sets whether this defines a future time.\r
340    * @param future true if the time is in the future\r
341    * @return  the new Period\r
342    */\r
343   private Period setFuture(boolean future) {\r
344     if (this.inFuture != future) {\r
345       return new Period(timeLimit, future, counts);\r
346     }\r
347     return this;\r
348   }\r
349 \r
350   /**\r
351    * Sets whether this is more than, less than, or\r
352    * 'about' the specified time.\r
353    * @param limit the kind of limit\r
354    * @return the new Period\r
355    */\r
356   private Period setTimeLimit(byte limit) {\r
357     if (this.timeLimit != limit) {\r
358       return new Period(limit, inFuture, counts);\r
359 \r
360     }\r
361     return this;\r
362   }\r
363 \r
364   /**\r
365    * Validate count.\r
366    */\r
367   private static void checkCount(float count) {\r
368     if (count < 0) {\r
369       throw new IllegalArgumentException("count (" + count + \r
370                                          ") cannot be negative");\r
371     }\r
372   }\r
373 }\r