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 org.joda.time.chrono.ISOChronology;
019    
020    /**
021     * DateTimeUtils provide public utility methods for the date-time library.
022     * <p>
023     * DateTimeUtils is thread-safe although shared static variables are used.
024     *
025     * @author Stephen Colebourne
026     * @since 1.0
027     */
028    public class DateTimeUtils {
029    
030        /** The singleton instance of the system millisecond provider. */
031        private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
032        /** The millisecond provider currently in use. */
033        private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
034    
035        /**
036         * Restrictive constructor
037         */
038        protected DateTimeUtils() {
039            super();
040        }
041    
042        //-----------------------------------------------------------------------
043        /**
044         * Gets the current time in milliseconds.
045         * <p>
046         * By default this returns <code>System.currentTimeMillis()</code>.
047         * This may be changed using other methods in this class.
048         * 
049         * @return the current time in milliseconds from 1970-01-01T00:00:00Z
050         */
051        public static final long currentTimeMillis() {
052            return cMillisProvider.getMillis();
053        }
054    
055        /**
056         * Resets the current time to return the system time.
057         * <p>
058         * This method changes the behaviour of {@link #currentTimeMillis()}.
059         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
060         * 
061         * @throws SecurityException if the application does not have sufficient security rights
062         */
063        public static final void setCurrentMillisSystem() throws SecurityException {
064            checkPermission();
065            cMillisProvider = SYSTEM_MILLIS_PROVIDER;
066        }
067    
068        /**
069         * Sets the current time to return a fixed millisecond time.
070         * <p>
071         * This method changes the behaviour of {@link #currentTimeMillis()}.
072         * Whenever the current time is queried, the same millisecond time will be returned.
073         * 
074         * @param fixedMillis  the fixed millisecond time to use
075         * @throws SecurityException if the application does not have sufficient security rights
076         */
077        public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
078            checkPermission();
079            cMillisProvider = new FixedMillisProvider(fixedMillis);
080        }
081    
082        /**
083         * Sets the current time to return the system time plus an offset.
084         * <p>
085         * This method changes the behaviour of {@link #currentTimeMillis()}.
086         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used
087         * and then offset by adding the millisecond value specified here.
088         * 
089         * @param offsetMillis  the fixed millisecond time to use
090         * @throws SecurityException if the application does not have sufficient security rights
091         */
092        public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException {
093            checkPermission();
094            if (offsetMillis == 0) {
095                cMillisProvider = SYSTEM_MILLIS_PROVIDER;
096            } else {
097                cMillisProvider = new OffsetMillisProvider(offsetMillis);
098            }
099        }
100    
101        /**
102         * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
103         * 
104         * @throws SecurityException if the provider may not be changed
105         */
106        private static void checkPermission() throws SecurityException {
107            SecurityManager sm = System.getSecurityManager();
108            if (sm != null) {
109                sm.checkPermission(new JodaTimePermission("CurrentTime.setProvider"));
110            }
111        }
112    
113        //-----------------------------------------------------------------------
114        /**
115         * Gets the millisecond instant from the specified instant object handling null.
116         * <p>
117         * If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
118         * will be returned. Otherwise, the millis from the object are returned.
119         * 
120         * @param instant  the instant to examine, null means now
121         * @return the time in milliseconds from 1970-01-01T00:00:00Z
122         */
123        public static final long getInstantMillis(ReadableInstant instant) {
124            if (instant == null) {
125                return DateTimeUtils.currentTimeMillis();
126            }
127            return instant.getMillis();
128        }
129    
130        //-----------------------------------------------------------------------
131        /**
132         * Gets the chronology from the specified instant object handling null.
133         * <p>
134         * If the instant object is <code>null</code>, or the instant's chronology is
135         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
136         * Otherwise, the chronology from the object is returned.
137         * 
138         * @param instant  the instant to examine, null means ISO in the default zone
139         * @return the chronology, never null
140         */
141        public static final Chronology getInstantChronology(ReadableInstant instant) {
142            if (instant == null) {
143                return ISOChronology.getInstance();
144            }
145            Chronology chrono = instant.getChronology();
146            if (chrono == null) {
147                return ISOChronology.getInstance();
148            }
149            return chrono;
150        }
151    
152        //-----------------------------------------------------------------------
153        /**
154         * Gets the chronology from the specified instant based interval handling null.
155         * <p>
156         * The chronology is obtained from the start if that is not null, or from the
157         * end if the start is null. The result is additionally checked, and if still
158         * null then {@link ISOChronology#getInstance()} will be returned.
159         * 
160         * @param start  the instant to examine and use as the primary source of the chronology
161         * @param end  the instant to examine and use as the secondary source of the chronology
162         * @return the chronology, never null
163         */
164        public static final Chronology getIntervalChronology(ReadableInstant start, ReadableInstant end) {
165            Chronology chrono = null;
166            if (start != null) {
167                chrono = start.getChronology();
168            } else if (end != null) {
169                chrono = end.getChronology();
170            }
171            if (chrono == null) {
172                chrono = ISOChronology.getInstance();
173            }
174            return chrono;
175        }
176    
177        //-----------------------------------------------------------------------
178        /**
179         * Gets the chronology from the specified interval object handling null.
180         * <p>
181         * If the interval object is <code>null</code>, or the interval's chronology is
182         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
183         * Otherwise, the chronology from the object is returned.
184         * 
185         * @param interval  the interval to examine, null means ISO in the default zone
186         * @return the chronology, never null
187         */
188        public static final Chronology getIntervalChronology(ReadableInterval interval) {
189            if (interval == null) {
190                return ISOChronology.getInstance();
191            }
192            Chronology chrono = interval.getChronology();
193            if (chrono == null) {
194                return ISOChronology.getInstance();
195            }
196            return chrono;
197        }
198    
199        //-----------------------------------------------------------------------
200        /**
201         * Gets the interval handling null.
202         * <p>
203         * If the interval is <code>null</code>, an interval representing now
204         * to now in the {@link ISOChronology#getInstance() ISOChronology}
205         * will be returned. Otherwise, the interval specified is returned.
206         * 
207         * @param interval  the interval to use, null means now to now
208         * @return the interval, never null
209         * @since 1.1
210         */
211        public static final ReadableInterval getReadableInterval(ReadableInterval interval) {
212            if (interval == null) {
213                long now = DateTimeUtils.currentTimeMillis();
214                interval = new Interval(now, now);
215            }
216            return interval;
217        }
218    
219        //-----------------------------------------------------------------------
220        /**
221         * Gets the chronology handling null.
222         * <p>
223         * If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
224         * will be returned. Otherwise, the chronology is returned.
225         * 
226         * @param chrono  the chronology to use, null means ISO in the default zone
227         * @return the chronology, never null
228         */
229        public static final Chronology getChronology(Chronology chrono) {
230            if (chrono == null) {
231                return ISOChronology.getInstance();
232            }
233            return chrono;
234        }
235    
236        //-----------------------------------------------------------------------
237        /**
238         * Gets the zone handling null.
239         * <p>
240         * If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
241         * will be returned. Otherwise, the zone specified is returned.
242         * 
243         * @param zone  the time zone to use, null means the default zone
244         * @return the time zone, never null
245         */
246        public static final DateTimeZone getZone(DateTimeZone zone) {
247            if (zone == null) {
248                return DateTimeZone.getDefault();
249            }
250            return zone;
251        }
252    
253        //-----------------------------------------------------------------------
254        /**
255         * Gets the period type handling null.
256         * <p>
257         * If the zone is <code>null</code>, {@link PeriodType#standard()}
258         * will be returned. Otherwise, the type specified is returned.
259         * 
260         * @param type  the time zone to use, null means the standard type
261         * @return the type to use, never null
262         */
263        public static final PeriodType getPeriodType(PeriodType type) {
264            if (type == null) {
265                return PeriodType.standard();
266            }
267            return type;
268        }
269    
270        //-----------------------------------------------------------------------
271        /**
272         * Gets the millisecond duration from the specified duration object handling null.
273         * <p>
274         * If the duration object is <code>null</code>, zero will be returned.
275         * Otherwise, the millis from the object are returned.
276         * 
277         * @param duration  the duration to examine, null means zero
278         * @return the duration in milliseconds
279         */
280        public static final long getDurationMillis(ReadableDuration duration) {
281            if (duration == null) {
282                return 0L;
283            }
284            return duration.getMillis();
285        }
286    
287        //-----------------------------------------------------------------------
288        /**
289         * Checks whether the partial is contiguous.
290         * <p>
291         * A partial is contiguous if one field starts where another ends.
292         * <p>
293         * For example <code>LocalDate</code> is contiguous because DayOfMonth has
294         * the same range (Month) as the unit of the next field (MonthOfYear), and
295         * MonthOfYear has the same range (Year) as the unit of the next field (Year).
296         * <p>
297         * Similarly, <code>LocalTime</code> is contiguous, as it consists of
298         * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
299         * the names of each field 'join up').
300         * <p>
301         * However, a Year/HourOfDay partial is not contiguous because the range
302         * field Day is not equal to the next field Year.
303         * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
304         * the range Month is not equal to the next field Day.
305         * 
306         * @param partial  the partial to check
307         * @return true if the partial is contiguous
308         * @throws IllegalArgumentException if the partial is null
309         * @since 1.1
310         */
311        public static final boolean isContiguous(ReadablePartial partial) {
312            if (partial == null) {
313                throw new IllegalArgumentException("Partial must not be null");
314            }
315            DurationFieldType lastType = null;
316            for (int i = 0; i < partial.size(); i++) {
317                DateTimeField loopField = partial.getField(i);
318                if (i > 0) {
319                    if (loopField.getRangeDurationField().getType() != lastType) {
320                        return false;
321                    }
322                }
323                lastType = loopField.getDurationField().getType();
324            }
325            return true;
326        }
327    
328        //-----------------------------------------------------------------------
329        /**
330         * Base class defining a millisecond provider.
331         */
332        abstract static class MillisProvider {
333            /**
334             * Gets the current time.
335             * @return the current time in millis
336             */
337            abstract long getMillis();
338        }
339    
340        /**
341         * System millis provider.
342         */
343        static class SystemMillisProvider extends MillisProvider {
344            /**
345             * Gets the current time.
346             * @return the current time in millis
347             */
348            long getMillis() {
349                return System.currentTimeMillis();
350            }
351        }
352    
353        /**
354         * Fixed millisecond provider.
355         */
356        static class FixedMillisProvider extends MillisProvider {
357            /** The fixed millis value. */
358            private final long iMillis;
359            
360            /**
361             * Constructor.
362             * @param offsetMillis  the millis offset
363             */
364            FixedMillisProvider(long fixedMillis) {
365                iMillis = fixedMillis;
366            }
367            
368            /**
369             * Gets the current time.
370             * @return the current time in millis
371             */
372            long getMillis() {
373                return iMillis;
374            }
375        }
376    
377        /**
378         * Offset from system millis provider.
379         */
380        static class OffsetMillisProvider extends MillisProvider {
381            /** The millis offset. */
382            private final long iMillis;
383            
384            /**
385             * Constructor.
386             * @param offsetMillis  the millis offset
387             */
388            OffsetMillisProvider(long offsetMillis) {
389                iMillis = offsetMillis;
390            }
391            
392            /**
393             * Gets the current time.
394             * @return the current time in millis
395             */
396            long getMillis() {
397                return System.currentTimeMillis() + iMillis;
398            }
399        }
400    
401    }