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