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 */
016package org.joda.time;
017
018import 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 */
028public 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}