001    /*
002     *  Copyright 2001-2010 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.lang.reflect.Method;
019    import java.text.DateFormatSymbols;
020    import java.util.Locale;
021    
022    import org.joda.time.chrono.ISOChronology;
023    
024    /**
025     * DateTimeUtils provide public utility methods for the date-time library.
026     * <p>
027     * DateTimeUtils is thread-safe although shared static variables are used.
028     *
029     * @author Stephen Colebourne
030     * @since 1.0
031     */
032    public class DateTimeUtils {
033    
034        /** The singleton instance of the system millisecond provider. */
035        private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
036        /** The millisecond provider currently in use. */
037        private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
038    
039        /**
040         * Restrictive constructor
041         */
042        protected DateTimeUtils() {
043            super();
044        }
045    
046        //-----------------------------------------------------------------------
047        /**
048         * Gets the current time in milliseconds.
049         * <p>
050         * By default this returns <code>System.currentTimeMillis()</code>.
051         * This may be changed using other methods in this class.
052         * 
053         * @return the current time in milliseconds from 1970-01-01T00:00:00Z
054         */
055        public static final long currentTimeMillis() {
056            return cMillisProvider.getMillis();
057        }
058    
059        /**
060         * Resets the current time to return the system time.
061         * <p>
062         * This method changes the behaviour of {@link #currentTimeMillis()}.
063         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
064         * 
065         * @throws SecurityException if the application does not have sufficient security rights
066         */
067        public static final void setCurrentMillisSystem() throws SecurityException {
068            checkPermission();
069            cMillisProvider = SYSTEM_MILLIS_PROVIDER;
070        }
071    
072        /**
073         * Sets the current time to return a fixed millisecond time.
074         * <p>
075         * This method changes the behaviour of {@link #currentTimeMillis()}.
076         * Whenever the current time is queried, the same millisecond time will be returned.
077         * 
078         * @param fixedMillis  the fixed millisecond time to use
079         * @throws SecurityException if the application does not have sufficient security rights
080         */
081        public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
082            checkPermission();
083            cMillisProvider = new FixedMillisProvider(fixedMillis);
084        }
085    
086        /**
087         * Sets the current time to return the system time plus an offset.
088         * <p>
089         * This method changes the behaviour of {@link #currentTimeMillis()}.
090         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used
091         * and then offset by adding the millisecond value specified here.
092         * 
093         * @param offsetMillis  the fixed millisecond time to use
094         * @throws SecurityException if the application does not have sufficient security rights
095         */
096        public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException {
097            checkPermission();
098            if (offsetMillis == 0) {
099                cMillisProvider = SYSTEM_MILLIS_PROVIDER;
100            } else {
101                cMillisProvider = new OffsetMillisProvider(offsetMillis);
102            }
103        }
104    
105        /**
106         * Sets the provider of the current time to class specified.
107         * <p>
108         * This method changes the behaviour of {@link #currentTimeMillis()}.
109         * Whenever the current time is queried, the specified class will be called.
110         * 
111         * @param millisProvider  the provider of the current time to use, not null
112         * @throws SecurityException if the application does not have sufficient security rights
113         * @since 2.0
114         */
115        public static final void setCurrentMillisProvider(MillisProvider millisProvider) throws SecurityException {
116            if (millisProvider == null) {
117                throw new IllegalArgumentException("The MillisProvider must not be null");
118            }
119            checkPermission();
120            cMillisProvider = millisProvider;
121        }
122    
123        /**
124         * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
125         * 
126         * @throws SecurityException if the provider may not be changed
127         */
128        private static void checkPermission() throws SecurityException {
129            SecurityManager sm = System.getSecurityManager();
130            if (sm != null) {
131                sm.checkPermission(new JodaTimePermission("CurrentTime.setProvider"));
132            }
133        }
134    
135        //-----------------------------------------------------------------------
136        /**
137         * Gets the millisecond instant from the specified instant object handling null.
138         * <p>
139         * If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
140         * will be returned. Otherwise, the millis from the object are returned.
141         * 
142         * @param instant  the instant to examine, null means now
143         * @return the time in milliseconds from 1970-01-01T00:00:00Z
144         */
145        public static final long getInstantMillis(ReadableInstant instant) {
146            if (instant == null) {
147                return DateTimeUtils.currentTimeMillis();
148            }
149            return instant.getMillis();
150        }
151    
152        //-----------------------------------------------------------------------
153        /**
154         * Gets the chronology from the specified instant object handling null.
155         * <p>
156         * If the instant object is <code>null</code>, or the instant's chronology is
157         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
158         * Otherwise, the chronology from the object is returned.
159         * 
160         * @param instant  the instant to examine, null means ISO in the default zone
161         * @return the chronology, never null
162         */
163        public static final Chronology getInstantChronology(ReadableInstant instant) {
164            if (instant == null) {
165                return ISOChronology.getInstance();
166            }
167            Chronology chrono = instant.getChronology();
168            if (chrono == null) {
169                return ISOChronology.getInstance();
170            }
171            return chrono;
172        }
173    
174        //-----------------------------------------------------------------------
175        /**
176         * Gets the chronology from the specified instant based interval handling null.
177         * <p>
178         * The chronology is obtained from the start if that is not null, or from the
179         * end if the start is null. The result is additionally checked, and if still
180         * null then {@link ISOChronology#getInstance()} will be returned.
181         * 
182         * @param start  the instant to examine and use as the primary source of the chronology
183         * @param end  the instant to examine and use as the secondary source of the chronology
184         * @return the chronology, never null
185         */
186        public static final Chronology getIntervalChronology(ReadableInstant start, ReadableInstant end) {
187            Chronology chrono = null;
188            if (start != null) {
189                chrono = start.getChronology();
190            } else if (end != null) {
191                chrono = end.getChronology();
192            }
193            if (chrono == null) {
194                chrono = ISOChronology.getInstance();
195            }
196            return chrono;
197        }
198    
199        //-----------------------------------------------------------------------
200        /**
201         * Gets the chronology from the specified interval object handling null.
202         * <p>
203         * If the interval object is <code>null</code>, or the interval's chronology is
204         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
205         * Otherwise, the chronology from the object is returned.
206         * 
207         * @param interval  the interval to examine, null means ISO in the default zone
208         * @return the chronology, never null
209         */
210        public static final Chronology getIntervalChronology(ReadableInterval interval) {
211            if (interval == null) {
212                return ISOChronology.getInstance();
213            }
214            Chronology chrono = interval.getChronology();
215            if (chrono == null) {
216                return ISOChronology.getInstance();
217            }
218            return chrono;
219        }
220    
221        //-----------------------------------------------------------------------
222        /**
223         * Gets the interval handling null.
224         * <p>
225         * If the interval is <code>null</code>, an interval representing now
226         * to now in the {@link ISOChronology#getInstance() ISOChronology}
227         * will be returned. Otherwise, the interval specified is returned.
228         * 
229         * @param interval  the interval to use, null means now to now
230         * @return the interval, never null
231         * @since 1.1
232         */
233        public static final ReadableInterval getReadableInterval(ReadableInterval interval) {
234            if (interval == null) {
235                long now = DateTimeUtils.currentTimeMillis();
236                interval = new Interval(now, now);
237            }
238            return interval;
239        }
240    
241        //-----------------------------------------------------------------------
242        /**
243         * Gets the chronology handling null.
244         * <p>
245         * If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
246         * will be returned. Otherwise, the chronology is returned.
247         * 
248         * @param chrono  the chronology to use, null means ISO in the default zone
249         * @return the chronology, never null
250         */
251        public static final Chronology getChronology(Chronology chrono) {
252            if (chrono == null) {
253                return ISOChronology.getInstance();
254            }
255            return chrono;
256        }
257    
258        //-----------------------------------------------------------------------
259        /**
260         * Gets the zone handling null.
261         * <p>
262         * If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
263         * will be returned. Otherwise, the zone specified is returned.
264         * 
265         * @param zone  the time zone to use, null means the default zone
266         * @return the time zone, never null
267         */
268        public static final DateTimeZone getZone(DateTimeZone zone) {
269            if (zone == null) {
270                return DateTimeZone.getDefault();
271            }
272            return zone;
273        }
274    
275        //-----------------------------------------------------------------------
276        /**
277         * Gets the period type handling null.
278         * <p>
279         * If the zone is <code>null</code>, {@link PeriodType#standard()}
280         * will be returned. Otherwise, the type specified is returned.
281         * 
282         * @param type  the time zone to use, null means the standard type
283         * @return the type to use, never null
284         */
285        public static final PeriodType getPeriodType(PeriodType type) {
286            if (type == null) {
287                return PeriodType.standard();
288            }
289            return type;
290        }
291    
292        //-----------------------------------------------------------------------
293        /**
294         * Gets the millisecond duration from the specified duration object handling null.
295         * <p>
296         * If the duration object is <code>null</code>, zero will be returned.
297         * Otherwise, the millis from the object are returned.
298         * 
299         * @param duration  the duration to examine, null means zero
300         * @return the duration in milliseconds
301         */
302        public static final long getDurationMillis(ReadableDuration duration) {
303            if (duration == null) {
304                return 0L;
305            }
306            return duration.getMillis();
307        }
308    
309        //-----------------------------------------------------------------------
310        /**
311         * Checks whether the partial is contiguous.
312         * <p>
313         * A partial is contiguous if one field starts where another ends.
314         * <p>
315         * For example <code>LocalDate</code> is contiguous because DayOfMonth has
316         * the same range (Month) as the unit of the next field (MonthOfYear), and
317         * MonthOfYear has the same range (Year) as the unit of the next field (Year).
318         * <p>
319         * Similarly, <code>LocalTime</code> is contiguous, as it consists of
320         * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
321         * the names of each field 'join up').
322         * <p>
323         * However, a Year/HourOfDay partial is not contiguous because the range
324         * field Day is not equal to the next field Year.
325         * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
326         * the range Month is not equal to the next field Day.
327         * 
328         * @param partial  the partial to check
329         * @return true if the partial is contiguous
330         * @throws IllegalArgumentException if the partial is null
331         * @since 1.1
332         */
333        public static final boolean isContiguous(ReadablePartial partial) {
334            if (partial == null) {
335                throw new IllegalArgumentException("Partial must not be null");
336            }
337            DurationFieldType lastType = null;
338            for (int i = 0; i < partial.size(); i++) {
339                DateTimeField loopField = partial.getField(i);
340                if (i > 0) {
341                    if (loopField.getRangeDurationField().getType() != lastType) {
342                        return false;
343                    }
344                }
345                lastType = loopField.getDurationField().getType();
346            }
347            return true;
348        }
349    
350        //-----------------------------------------------------------------------
351        /**
352         * Gets the {@link DateFormatSymbols} based on the given locale.
353         * <p>
354         * If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will
355         * be used in order to allow the use of locales defined as extensions.
356         * Otherwise, new DateFormatSymbols(locale) will be used.
357         * See JDK 6 {@link DateFormatSymbols} for further information.
358         * 
359         * @param locale  the {@link Locale} used to get the correct {@link DateFormatSymbols}
360         * @return the symbols
361         * @since 2.0
362         */
363        public static final DateFormatSymbols getDateFormatSymbols(Locale locale) {
364            try {
365                Method method = DateFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class});
366                return (DateFormatSymbols) method.invoke(null, new Object[] {locale});
367            } catch (Exception ex) {
368                return new DateFormatSymbols(locale);
369            }
370        }
371    
372        //-----------------------------------------------------------------------
373        /**
374         * A millisecond provider, allowing control of the system clock.
375         * 
376         * @author Stephen Colebourne
377         * @since 2.0 (previously private)
378         */
379        public static interface MillisProvider {
380            /**
381             * Gets the current time.
382             * <p>
383             * Implementations of this method must be thread-safe.
384             * 
385             * @return the current time in milliseconds
386             */
387            long getMillis();
388        }
389    
390        /**
391         * System millis provider.
392         */
393        static class SystemMillisProvider implements MillisProvider {
394            /**
395             * Gets the current time.
396             * @return the current time in millis
397             */
398            public long getMillis() {
399                return System.currentTimeMillis();
400            }
401        }
402    
403        /**
404         * Fixed millisecond provider.
405         */
406        static class FixedMillisProvider implements MillisProvider {
407            /** The fixed millis value. */
408            private final long iMillis;
409            
410            /**
411             * Constructor.
412             * @param offsetMillis  the millis offset
413             */
414            FixedMillisProvider(long fixedMillis) {
415                iMillis = fixedMillis;
416            }
417            
418            /**
419             * Gets the current time.
420             * @return the current time in millis
421             */
422            public long getMillis() {
423                return iMillis;
424            }
425        }
426    
427        /**
428         * Offset from system millis provider.
429         */
430        static class OffsetMillisProvider implements MillisProvider {
431            /** The millis offset. */
432            private final long iMillis;
433            
434            /**
435             * Constructor.
436             * @param offsetMillis  the millis offset
437             */
438            OffsetMillisProvider(long offsetMillis) {
439                iMillis = offsetMillis;
440            }
441            
442            /**
443             * Gets the current time.
444             * @return the current time in millis
445             */
446            public long getMillis() {
447                return System.currentTimeMillis() + iMillis;
448            }
449        }
450    
451    }