001    /*
002     *  Copyright 2001-2012 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.Collections;
021    import java.util.HashMap;
022    import java.util.LinkedHashMap;
023    import java.util.Locale;
024    import java.util.Map;
025    
026    import org.joda.time.chrono.ISOChronology;
027    
028    /**
029     * DateTimeUtils provide public utility methods for the date-time library.
030     * <p>
031     * DateTimeUtils is thread-safe although shared static variables are used.
032     *
033     * @author Stephen Colebourne
034     * @since 1.0
035     */
036    public class DateTimeUtils {
037    
038        /** The singleton instance of the system millisecond provider. */
039        private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
040        /** The millisecond provider currently in use. */
041        private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
042        /** The millisecond provider currently in use. */
043        private static volatile Map<String, DateTimeZone> cZoneNames;
044        static {
045            // names from RFC-822 / JDK
046            // this is all very US-centric and dubious, but perhaps it will help some
047            Map<String, DateTimeZone> map = new LinkedHashMap<String, DateTimeZone>();
048            map.put("UT", DateTimeZone.UTC);
049            map.put("UTC", DateTimeZone.UTC);
050            map.put("GMT", DateTimeZone.UTC);
051            put(map, "EST", "America/New_York");
052            put(map, "EDT", "America/New_York");
053            put(map, "CST", "America/Chicago");
054            put(map, "CDT", "America/Chicago");
055            put(map, "MST", "America/Denver");
056            put(map, "MDT", "America/Denver");
057            put(map, "PST", "America/Los_Angeles");
058            put(map, "PDT", "America/Los_Angeles");
059            cZoneNames = Collections.unmodifiableMap(map);
060        }
061        private static void put(Map<String, DateTimeZone> map, String name, String id) {
062            try {
063                map.put(name, DateTimeZone.forID(id));
064            } catch (RuntimeException ex) {
065                // ignore
066            }
067        }
068    
069        /**
070         * Restrictive constructor
071         */
072        protected DateTimeUtils() {
073            super();
074        }
075    
076        //-----------------------------------------------------------------------
077        /**
078         * Gets the current time in milliseconds.
079         * <p>
080         * By default this returns <code>System.currentTimeMillis()</code>.
081         * This may be changed using other methods in this class.
082         * 
083         * @return the current time in milliseconds from 1970-01-01T00:00:00Z
084         */
085        public static final long currentTimeMillis() {
086            return cMillisProvider.getMillis();
087        }
088    
089        /**
090         * Resets the current time to return the system time.
091         * <p>
092         * This method changes the behaviour of {@link #currentTimeMillis()}.
093         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
094         * 
095         * @throws SecurityException if the application does not have sufficient security rights
096         */
097        public static final void setCurrentMillisSystem() throws SecurityException {
098            checkPermission();
099            cMillisProvider = SYSTEM_MILLIS_PROVIDER;
100        }
101    
102        /**
103         * Sets the current time to return a fixed millisecond time.
104         * <p>
105         * This method changes the behaviour of {@link #currentTimeMillis()}.
106         * Whenever the current time is queried, the same millisecond time will be returned.
107         * 
108         * @param fixedMillis  the fixed millisecond time to use
109         * @throws SecurityException if the application does not have sufficient security rights
110         */
111        public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
112            checkPermission();
113            cMillisProvider = new FixedMillisProvider(fixedMillis);
114        }
115    
116        /**
117         * Sets the current time to return the system time plus an offset.
118         * <p>
119         * This method changes the behaviour of {@link #currentTimeMillis()}.
120         * Whenever the current time is queried, {@link System#currentTimeMillis()} is used
121         * and then offset by adding the millisecond value specified here.
122         * 
123         * @param offsetMillis  the fixed millisecond time to use
124         * @throws SecurityException if the application does not have sufficient security rights
125         */
126        public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException {
127            checkPermission();
128            if (offsetMillis == 0) {
129                cMillisProvider = SYSTEM_MILLIS_PROVIDER;
130            } else {
131                cMillisProvider = new OffsetMillisProvider(offsetMillis);
132            }
133        }
134    
135        /**
136         * Sets the provider of the current time to class specified.
137         * <p>
138         * This method changes the behaviour of {@link #currentTimeMillis()}.
139         * Whenever the current time is queried, the specified class will be called.
140         * 
141         * @param millisProvider  the provider of the current time to use, not null
142         * @throws SecurityException if the application does not have sufficient security rights
143         * @since 2.0
144         */
145        public static final void setCurrentMillisProvider(MillisProvider millisProvider) throws SecurityException {
146            if (millisProvider == null) {
147                throw new IllegalArgumentException("The MillisProvider must not be null");
148            }
149            checkPermission();
150            cMillisProvider = millisProvider;
151        }
152    
153        /**
154         * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
155         * 
156         * @throws SecurityException if the provider may not be changed
157         */
158        private static void checkPermission() throws SecurityException {
159            SecurityManager sm = System.getSecurityManager();
160            if (sm != null) {
161                sm.checkPermission(new JodaTimePermission("CurrentTime.setProvider"));
162            }
163        }
164    
165        //-----------------------------------------------------------------------
166        /**
167         * Gets the millisecond instant from the specified instant object handling null.
168         * <p>
169         * If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
170         * will be returned. Otherwise, the millis from the object are returned.
171         * 
172         * @param instant  the instant to examine, null means now
173         * @return the time in milliseconds from 1970-01-01T00:00:00Z
174         */
175        public static final long getInstantMillis(ReadableInstant instant) {
176            if (instant == null) {
177                return DateTimeUtils.currentTimeMillis();
178            }
179            return instant.getMillis();
180        }
181    
182        //-----------------------------------------------------------------------
183        /**
184         * Gets the chronology from the specified instant object handling null.
185         * <p>
186         * If the instant object is <code>null</code>, or the instant's chronology is
187         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
188         * Otherwise, the chronology from the object is returned.
189         * 
190         * @param instant  the instant to examine, null means ISO in the default zone
191         * @return the chronology, never null
192         */
193        public static final Chronology getInstantChronology(ReadableInstant instant) {
194            if (instant == null) {
195                return ISOChronology.getInstance();
196            }
197            Chronology chrono = instant.getChronology();
198            if (chrono == null) {
199                return ISOChronology.getInstance();
200            }
201            return chrono;
202        }
203    
204        //-----------------------------------------------------------------------
205        /**
206         * Gets the chronology from the specified instant based interval handling null.
207         * <p>
208         * The chronology is obtained from the start if that is not null, or from the
209         * end if the start is null. The result is additionally checked, and if still
210         * null then {@link ISOChronology#getInstance()} will be returned.
211         * 
212         * @param start  the instant to examine and use as the primary source of the chronology
213         * @param end  the instant to examine and use as the secondary source of the chronology
214         * @return the chronology, never null
215         */
216        public static final Chronology getIntervalChronology(ReadableInstant start, ReadableInstant end) {
217            Chronology chrono = null;
218            if (start != null) {
219                chrono = start.getChronology();
220            } else if (end != null) {
221                chrono = end.getChronology();
222            }
223            if (chrono == null) {
224                chrono = ISOChronology.getInstance();
225            }
226            return chrono;
227        }
228    
229        //-----------------------------------------------------------------------
230        /**
231         * Gets the chronology from the specified interval object handling null.
232         * <p>
233         * If the interval object is <code>null</code>, or the interval's chronology is
234         * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
235         * Otherwise, the chronology from the object is returned.
236         * 
237         * @param interval  the interval to examine, null means ISO in the default zone
238         * @return the chronology, never null
239         */
240        public static final Chronology getIntervalChronology(ReadableInterval interval) {
241            if (interval == null) {
242                return ISOChronology.getInstance();
243            }
244            Chronology chrono = interval.getChronology();
245            if (chrono == null) {
246                return ISOChronology.getInstance();
247            }
248            return chrono;
249        }
250    
251        //-----------------------------------------------------------------------
252        /**
253         * Gets the interval handling null.
254         * <p>
255         * If the interval is <code>null</code>, an interval representing now
256         * to now in the {@link ISOChronology#getInstance() ISOChronology}
257         * will be returned. Otherwise, the interval specified is returned.
258         * 
259         * @param interval  the interval to use, null means now to now
260         * @return the interval, never null
261         * @since 1.1
262         */
263        public static final ReadableInterval getReadableInterval(ReadableInterval interval) {
264            if (interval == null) {
265                long now = DateTimeUtils.currentTimeMillis();
266                interval = new Interval(now, now);
267            }
268            return interval;
269        }
270    
271        //-----------------------------------------------------------------------
272        /**
273         * Gets the chronology handling null.
274         * <p>
275         * If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
276         * will be returned. Otherwise, the chronology is returned.
277         * 
278         * @param chrono  the chronology to use, null means ISO in the default zone
279         * @return the chronology, never null
280         */
281        public static final Chronology getChronology(Chronology chrono) {
282            if (chrono == null) {
283                return ISOChronology.getInstance();
284            }
285            return chrono;
286        }
287    
288        //-----------------------------------------------------------------------
289        /**
290         * Gets the zone handling null.
291         * <p>
292         * If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
293         * will be returned. Otherwise, the zone specified is returned.
294         * 
295         * @param zone  the time zone to use, null means the default zone
296         * @return the time zone, never null
297         */
298        public static final DateTimeZone getZone(DateTimeZone zone) {
299            if (zone == null) {
300                return DateTimeZone.getDefault();
301            }
302            return zone;
303        }
304    
305        //-----------------------------------------------------------------------
306        /**
307         * Gets the period type handling null.
308         * <p>
309         * If the zone is <code>null</code>, {@link PeriodType#standard()}
310         * will be returned. Otherwise, the type specified is returned.
311         * 
312         * @param type  the time zone to use, null means the standard type
313         * @return the type to use, never null
314         */
315        public static final PeriodType getPeriodType(PeriodType type) {
316            if (type == null) {
317                return PeriodType.standard();
318            }
319            return type;
320        }
321    
322        //-----------------------------------------------------------------------
323        /**
324         * Gets the millisecond duration from the specified duration object handling null.
325         * <p>
326         * If the duration object is <code>null</code>, zero will be returned.
327         * Otherwise, the millis from the object are returned.
328         * 
329         * @param duration  the duration to examine, null means zero
330         * @return the duration in milliseconds
331         */
332        public static final long getDurationMillis(ReadableDuration duration) {
333            if (duration == null) {
334                return 0L;
335            }
336            return duration.getMillis();
337        }
338    
339        //-----------------------------------------------------------------------
340        /**
341         * Checks whether the partial is contiguous.
342         * <p>
343         * A partial is contiguous if one field starts where another ends.
344         * <p>
345         * For example <code>LocalDate</code> is contiguous because DayOfMonth has
346         * the same range (Month) as the unit of the next field (MonthOfYear), and
347         * MonthOfYear has the same range (Year) as the unit of the next field (Year).
348         * <p>
349         * Similarly, <code>LocalTime</code> is contiguous, as it consists of
350         * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
351         * the names of each field 'join up').
352         * <p>
353         * However, a Year/HourOfDay partial is not contiguous because the range
354         * field Day is not equal to the next field Year.
355         * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
356         * the range Month is not equal to the next field Day.
357         * 
358         * @param partial  the partial to check
359         * @return true if the partial is contiguous
360         * @throws IllegalArgumentException if the partial is null
361         * @since 1.1
362         */
363        public static final boolean isContiguous(ReadablePartial partial) {
364            if (partial == null) {
365                throw new IllegalArgumentException("Partial must not be null");
366            }
367            DurationFieldType lastType = null;
368            for (int i = 0; i < partial.size(); i++) {
369                DateTimeField loopField = partial.getField(i);
370                if (i > 0) {
371                    if (loopField.getRangeDurationField().getType() != lastType) {
372                        return false;
373                    }
374                }
375                lastType = loopField.getDurationField().getType();
376            }
377            return true;
378        }
379    
380        //-----------------------------------------------------------------------
381        /**
382         * Gets the {@link DateFormatSymbols} based on the given locale.
383         * <p>
384         * If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will
385         * be used in order to allow the use of locales defined as extensions.
386         * Otherwise, new DateFormatSymbols(locale) will be used.
387         * See JDK 6 {@link DateFormatSymbols} for further information.
388         * 
389         * @param locale  the {@link Locale} used to get the correct {@link DateFormatSymbols}
390         * @return the symbols
391         * @since 2.0
392         */
393        public static final DateFormatSymbols getDateFormatSymbols(Locale locale) {
394            try {
395                Method method = DateFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class});
396                return (DateFormatSymbols) method.invoke(null, new Object[] {locale});
397            } catch (Exception ex) {
398                return new DateFormatSymbols(locale);
399            }
400        }
401    
402        //-----------------------------------------------------------------------
403        /**
404         * Gets the default map of time zone names.
405         * <p>
406         * This can be changed by {@link #setDefaultTimeZoneNames}.
407         * 
408         * @return the unmodifiable map of abbreviations to zones, not null
409         * @since 2.2
410         */
411        public static final Map<String, DateTimeZone> getDefaultTimeZoneNames() {
412            return cZoneNames;
413        }
414    
415        /**
416         * Sets the default map of time zone names.
417         * <p>
418         * The map is copied before storage.
419         * 
420         * @param names  the map of abbreviations to zones, not null
421         * @since 2.2
422         */
423        public static final void setDefaultTimeZoneNames(Map<String, DateTimeZone> names) {
424            cZoneNames = Collections.unmodifiableMap(new HashMap<String, DateTimeZone>(names));
425        }
426    
427        //-------------------------------------------------------------------------
428        /**
429         * Calculates the astronomical Julian Day for an instant.
430         * <p>
431         * The <a href="http://en.wikipedia.org/wiki/Julian_day">Julian day</a> is a well-known
432         * system of time measurement for scientific use by the astronomy community.
433         * It expresses the interval of time in days and fractions of a day since
434         * January 1, 4713 BC (Julian) Greenwich noon.
435         * <p>
436         * Each day starts at midday (not midnight) and time is expressed as a fraction.
437         * Thus the fraction 0.25 is 18:00. equal to one quarter of the day from midday to midday.
438         * <p>
439         * Note that this method has nothing to do with the day-of-year.
440         * 
441         * @param epochMillis  the epoch millis from 1970-01-01Z
442         * @return the astronomical Julian Day represented by the specified instant
443         * @since 2.2
444         */
445        public static final double toJulianDay(long epochMillis) {
446            // useful links
447            // http://en.wikipedia.org/wiki/Julian_day#cite_note-13 - Wikipedia
448            // http://aa.usno.navy.mil/data/docs/JulianDate.php" - USNO
449            // http://users.zoominternet.net/~matto/Java/Julian%20Date%20Converter.htm - Julian Date Converter by Matt Oltersdorf
450            // http://ssd.jpl.nasa.gov/tc.cgi#top - CalTech
451            double epochDay = epochMillis / 86400000d;
452            return epochDay + 2440587.5d;
453        }
454    
455        /**
456         * Calculates the astronomical Julian Day Number for an instant.
457         * <p>
458         * The {@link #toJulianDay(long)} method calculates the astronomical Julian Day
459         * with a fraction based on days starting at midday.
460         * This method calculates the variant where days start at midnight.
461         * JDN 0 is used for the date equivalent to Monday January 1, 4713 BC (Julian).
462         * Thus these days start 12 hours before those of the fractional Julian Day.
463         * <p>
464         * Note that this method has nothing to do with the day-of-year.
465         * 
466         * @param epochMillis  the epoch millis from 1970-01-01Z
467         * @return the astronomical Julian Day represented by the specified instant
468         * @since 2.2
469         */
470        public static final long toJulianDayNumber(long epochMillis) {
471            return (long) Math.floor(toJulianDay(epochMillis) + 0.5d);
472        }
473    
474        /**
475         * Creates a date-time from a Julian Day.
476         * <p>
477         * Returns the {@code DateTime} object equal to the specified Julian Day.
478         * 
479         * @param julianDay  the Julian Day
480         * @return the epoch millis from 1970-01-01Z
481         * @since 2.2
482         */
483        public static final long fromJulianDay(double julianDay) {
484            double epochDay = julianDay - 2440587.5d;
485            return (long) (epochDay * 86400000d);
486        }
487    
488        //-----------------------------------------------------------------------
489        /**
490         * A millisecond provider, allowing control of the system clock.
491         * 
492         * @author Stephen Colebourne
493         * @since 2.0 (previously private)
494         */
495        public static interface MillisProvider {
496            /**
497             * Gets the current time.
498             * <p>
499             * Implementations of this method must be thread-safe.
500             * 
501             * @return the current time in milliseconds
502             */
503            long getMillis();
504        }
505    
506        /**
507         * System millis provider.
508         */
509        static class SystemMillisProvider implements MillisProvider {
510            /**
511             * Gets the current time.
512             * @return the current time in millis
513             */
514            public long getMillis() {
515                return System.currentTimeMillis();
516            }
517        }
518    
519        /**
520         * Fixed millisecond provider.
521         */
522        static class FixedMillisProvider implements MillisProvider {
523            /** The fixed millis value. */
524            private final long iMillis;
525            
526            /**
527             * Constructor.
528             * @param offsetMillis  the millis offset
529             */
530            FixedMillisProvider(long fixedMillis) {
531                iMillis = fixedMillis;
532            }
533            
534            /**
535             * Gets the current time.
536             * @return the current time in millis
537             */
538            public long getMillis() {
539                return iMillis;
540            }
541        }
542    
543        /**
544         * Offset from system millis provider.
545         */
546        static class OffsetMillisProvider implements MillisProvider {
547            /** The millis offset. */
548            private final long iMillis;
549            
550            /**
551             * Constructor.
552             * @param offsetMillis  the millis offset
553             */
554            OffsetMillisProvider(long offsetMillis) {
555                iMillis = offsetMillis;
556            }
557            
558            /**
559             * Gets the current time.
560             * @return the current time in millis
561             */
562            public long getMillis() {
563                return System.currentTimeMillis() + iMillis;
564            }
565        }
566    
567    }