001: /*
002: * $Id: TimeOfDay.java 459990 2006-03-25 16:35:57Z dashorst $ $Revision:
003: * 1.4 $ $Date: 2006-03-25 17:35:57 +0100 (Sat, 25 Mar 2006) $
004: *
005: * ==============================================================================
006: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
007: * use this file except in compliance with the License. You may obtain a copy of
008: * the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015: * License for the specific language governing permissions and limitations under
016: * the License.
017: */
018: package wicket.util.time;
019:
020: import java.text.ParseException;
021: import java.util.Calendar;
022:
023: import wicket.util.lang.EnumeratedType;
024:
025: /**
026: * An immutable time of day value represented as milliseconds since the most
027: * recent midnight.
028: * <p>
029: * Values can be constructed using various factory methods:
030: * <ul>
031: * <li>valueOf(long) where long is milliseconds since midnight
032: * <li>valueOf(String) where the string is in h.mma format
033: * <li>valueOf(Calendar, String) where the string is in h.mma format
034: * <li>valueOf(Duration) where duration is time since midnight
035: * <li>valueOf(Time) where time is some point in time today
036: * <li>valueOf(Calendar, Time) where time is some point in time today
037: * <li>militaryTime(int hour, int minute, int second) for 24 hour time
038: * <li>time(int hour, int minute, Meridian) where Meridian is AM or PM
039: * <li>time(int hour, int minute, int second, Meridian) where Meridian is AM or
040: * PM
041: * <li>now() to construct the current time of day
042: * <li>now(Calendar) to construct the current time of day using a given
043: * calendar
044: * </ul>
045: * <p>
046: * If an attempt is made to construct an illegal time of day value (one that is
047: * greater than 24 hours worth of milliseconds), an IllegalArgumentException
048: * will be thrown.
049: * <p>
050: * Military hours, minutes and seconds of the time of day can be retrieved by
051: * calling hour(), minute() and second().
052: * <p>
053: * The next occurrence of a given time of day can be retrieved by calling next()
054: * or next(Calendar).
055: *
056: * @author Jonathan Locke
057: */
058: public final class TimeOfDay extends AbstractTime {
059: private static final long serialVersionUID = 1L;
060:
061: /** Constant for AM time. */
062: public static final Meridian AM = new Meridian("AM");
063:
064: /** Constant for midnight. */
065: public static final TimeOfDay MIDNIGHT = time(12, 0, AM);
066:
067: /** Constant for PM time. */
068: public static final Meridian PM = new Meridian("PM");
069:
070: /** Constant for noon. */
071: public static final TimeOfDay NOON = time(12, 0, PM);
072:
073: /** Typesafe AM/PM enumeration. */
074: public static final class Meridian extends EnumeratedType {
075: private static final long serialVersionUID = 1L;
076:
077: /**
078: * Construct.
079: *
080: * @param name
081: * the meridian name (value)
082: */
083: Meridian(final String name) {
084: super (name);
085: }
086: }
087:
088: /**
089: * Gets a time of day value on a 24 hour clock.
090: *
091: * @param hour
092: * The hour (0-23)
093: * @param minute
094: * The minute (0-59)
095: * @param second
096: * The second (0-59)
097: * @return The time of day
098: */
099: public static TimeOfDay militaryTime(final int hour,
100: final int minute, final int second) {
101: if ((hour > 23) || (hour < 0)) {
102: throw new IllegalArgumentException("Hour " + hour
103: + " is not valid");
104: }
105:
106: if ((minute > 59) || (minute < 0)) {
107: throw new IllegalArgumentException("Minute " + minute
108: + " is not valid");
109: }
110:
111: if ((second > 59) || (second < 0)) {
112: throw new IllegalArgumentException("Second " + second
113: + " is not valid");
114: }
115:
116: return valueOf(Duration.hours(hour).add(
117: Duration.minutes(minute)).add(Duration.seconds(second)));
118: }
119:
120: /**
121: * Gets the time of day it is now.
122: *
123: * @return The time of day it is now
124: */
125: public static TimeOfDay now() {
126: return valueOf(Time.now());
127: }
128:
129: /**
130: * Gets the time of day it is now on the given calendar.
131: *
132: * @param calendar
133: * The calendar to use
134: * @return The time of day it is now on the given calendar
135: */
136: public static TimeOfDay now(final Calendar calendar) {
137: return valueOf(calendar, Time.now());
138: }
139:
140: /**
141: * Gets a time of day on a 12 hour clock.
142: *
143: * @param hour
144: * The hour (1-12)
145: * @param minute
146: * The minute (0-59)
147: * @param second
148: * The second (0-59)
149: * @param meridian
150: * AM/PM
151: * @return The time value
152: */
153: public static TimeOfDay time(final int hour, final int minute,
154: final int second, final Meridian meridian) {
155: if (meridian == PM) {
156: if (hour == 12) {
157: return militaryTime(12, minute, second);
158: } else {
159: return militaryTime(hour + 12, minute, second);
160: }
161: } else {
162: if (hour == 12) {
163: return militaryTime(0, minute, second);
164: } else {
165: return militaryTime(hour, minute, second);
166: }
167: }
168: }
169:
170: /**
171: * Gets a time of day on a 12 hour clock.
172: *
173: * @param hour
174: * The hour (1-12)
175: * @param minute
176: * The minute (0-59)
177: * @param meridian
178: * AM/PM
179: * @return The time value
180: */
181: public static TimeOfDay time(final int hour, final int minute,
182: final Meridian meridian) {
183: return time(hour, minute, 0, meridian);
184: }
185:
186: /**
187: * Converts to TimeOfDay instance.
188: *
189: * @param calendar
190: * The calendar to use when parsing time string
191: * @param time
192: * A string in h.mma format
193: * @return The time of day on the given calendar
194: * @throws ParseException
195: */
196: public static TimeOfDay valueOf(final Calendar calendar,
197: final String time) throws ParseException {
198: synchronized (timeFormat) {
199: synchronized (calendar) {
200: timeFormat.setCalendar(calendar);
201: return new TimeOfDay(timeFormat.parse(time).getTime());
202: }
203: }
204: }
205:
206: /**
207: * Converts to TimeOfDay instance.
208: *
209: * @param calendar
210: * The calendar to use when converting time value
211: * @param time
212: * The time to convert to a time of day
213: * @return The time of day for this time
214: */
215: public static TimeOfDay valueOf(final Calendar calendar,
216: final Time time) {
217: return militaryTime(time.getHour(calendar), time
218: .getMinute(calendar), time.getSecond(calendar));
219: }
220:
221: /**
222: * Converts to TimeOfDay instance.
223: *
224: * @param duration
225: * The duration
226: * @return The time of day for the duration since midnight
227: */
228: public static TimeOfDay valueOf(final Duration duration) {
229: return new TimeOfDay(duration.getMilliseconds());
230: }
231:
232: /**
233: * Converts to TimeOfDay instance.
234: *
235: * @param time
236: * The time in milliseconds today
237: * @return The time of day
238: */
239: public static TimeOfDay valueOf(final long time) {
240: return new TimeOfDay(time);
241: }
242:
243: /**
244: * Converts to TimeOfDay instance.
245: *
246: * @param time
247: * A string in h.mma format
248: * @return The time of day on the given calendar
249: * @throws ParseException
250: */
251: public static TimeOfDay valueOf(final String time)
252: throws ParseException {
253: return valueOf(localtime, time);
254: }
255:
256: /**
257: * Converts to TimeOfDay instance.
258: *
259: * @param time
260: * Time to convert to time of day
261: * @return The time of day in the current timezone
262: */
263: public static TimeOfDay valueOf(final Time time) {
264: return valueOf(AbstractTime.localtime, time);
265: }
266:
267: /**
268: * Private utility constructor forces use of static factory methods.
269: *
270: * @param time
271: * Time today in milliseconds
272: */
273: private TimeOfDay(final long time) {
274: super (time);
275:
276: // A time of day value must be less than 1 day of milliseconds
277: if (Duration.valueOf(time).greaterThan(Duration.ONE_DAY)) {
278: throw new IllegalArgumentException("Time " + this
279: + " is not a time of day value");
280: }
281: }
282:
283: /**
284: * Gets the hour of the day.
285: *
286: * @return The hour of the day (0-23)
287: */
288: public int hour() {
289: return toHours(getMilliseconds());
290: }
291:
292: /**
293: * Gets the minute.
294: *
295: * @return The minute (0-59)
296: */
297: public int minute() {
298: return toMinutes(getMilliseconds()) % 60;
299: }
300:
301: /**
302: * Gets the next occurrence of this time of day in localtime.
303: *
304: * @return The next occurrence of this time of day in localtime
305: */
306: public Time next() {
307: return next(AbstractTime.localtime);
308: }
309:
310: /**
311: * Gets the next occurence of this time of day on the given calendar.
312: *
313: * @param calendar
314: * The calendar to use
315: * @return The next occurrence of this time of day on the given calendar
316: */
317: public Time next(final Calendar calendar) {
318: // Get this time of day today
319: final Time timeToday = Time.valueOf(calendar, this );
320:
321: // If it has already passed
322: if (timeToday.before(Time.now())) {
323: // Return the time tomorrow
324: calendar.add(Calendar.DATE, 1);
325: return Time.valueOf(calendar, this );
326: } else {
327: // Time hasn't happened yet today
328: return timeToday;
329: }
330: }
331:
332: /**
333: * Gets the second.
334: *
335: * @return The second (0-59)
336: */
337: public int second() {
338: return toSeconds(getMilliseconds()) % 60;
339: }
340:
341: /**
342: * @see Object#toString()
343: */
344: public String toString() {
345: final int second = second();
346: return "" + hour() + ":" + minute()
347: + (second != 0 ? ":" + second : "");
348: }
349:
350: /**
351: * Gets miliseconds as hours.
352: *
353: * @param milliseconds
354: * miliseconds to convert
355: * @return converted input
356: */
357: private int toHours(final long milliseconds) {
358: return toMinutes(milliseconds) / 60;
359: }
360:
361: /**
362: * Gets miliseconds as minutes.
363: *
364: * @param milliseconds
365: * miliseconds to convert
366: * @return converted input
367: */
368: private int toMinutes(final long milliseconds) {
369: return toSeconds(milliseconds) / 60;
370: }
371:
372: /**
373: * Gets miliseconds as seconds.
374: *
375: * @param milliseconds
376: * miliseconds to convert
377: * @return converted input
378: */
379: private int toSeconds(final long milliseconds) {
380: return (int) (milliseconds / 1000);
381: }
382: }
|