1 /*
2  *  Copyright 2001-2013 Stephen Colebourne
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

16 package org.joda.time;
17
18 import java.lang.reflect.Method;
19 import java.text.DateFormatSymbols;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.LinkedHashMap;
23 import java.util.Locale;
24 import java.util.Map;
25 import java.util.concurrent.atomic.AtomicReference;
26
27 import org.joda.time.chrono.ISOChronology;
28
29 /**
30  * DateTimeUtils provide public utility methods for the date-time library.
31  * <p>
32  * DateTimeUtils uses shared static variables which are declared as volatile
33  * for thread-safety. These can be changed during the lifetime of the application
34  * however doing so is generally a bad idea.
35  *
36  * @author Stephen Colebourne
37  * @since 1.0
38  */

39 public class DateTimeUtils {
40
41     /** The singleton instance of the system millisecond provider. */
42     private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
43     /** The millisecond provider currently in use. */
44     private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
45     /**
46      * The default names.
47      * This is lazily initialized to reduce risks of race conditions at startup.
48      */

49     private static final AtomicReference<Map<String, DateTimeZone>> cZoneNames =
50                     new AtomicReference<Map<String,DateTimeZone>>();
51
52     /**
53      * Restrictive constructor
54      */

55     protected DateTimeUtils() {
56         super();
57     }
58
59     //-----------------------------------------------------------------------
60     /**
61      * Gets the current time in milliseconds.
62      * <p>
63      * By default this returns <code>System.currentTimeMillis()</code>.
64      * This may be changed using other methods in this class.
65      * 
66      * @return the current time in milliseconds from 1970-01-01T00:00:00Z
67      */

68     public static final long currentTimeMillis() {
69         return cMillisProvider.getMillis();
70     }
71
72     /**
73      * Resets the current time to return the system time.
74      * <p>
75      * This method changes the behaviour of {@link #currentTimeMillis()}.
76      * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
77      * 
78      * @throws SecurityException if the application does not have sufficient security rights
79      */

80     public static final void setCurrentMillisSystem() throws SecurityException {
81         checkPermission();
82         cMillisProvider = SYSTEM_MILLIS_PROVIDER;
83     }
84
85     /**
86      * Sets the current time to return a fixed millisecond time.
87      * <p>
88      * This method changes the behaviour of {@link #currentTimeMillis()}.
89      * Whenever the current time is queried, the same millisecond time will be returned.
90      * 
91      * @param fixedMillis  the fixed millisecond time to use
92      * @throws SecurityException if the application does not have sufficient security rights
93      */

94     public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
95         checkPermission();
96         cMillisProvider = new FixedMillisProvider(fixedMillis);
97     }
98
99     /**
100      * Sets the current time to return the system time plus an offset.
101      * <p>
102      * This method changes the behaviour of {@link #currentTimeMillis()}.
103      * Whenever the current time is queried, {@link System#currentTimeMillis()} is used
104      * and then offset by adding the millisecond value specified here.
105      * 
106      * @param offsetMillis  the fixed millisecond time to use
107      * @throws SecurityException if the application does not have sufficient security rights
108      */

109     public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException {
110         checkPermission();
111         if (offsetMillis == 0) {
112             cMillisProvider = SYSTEM_MILLIS_PROVIDER;
113         } else {
114             cMillisProvider = new OffsetMillisProvider(offsetMillis);
115         }
116     }
117
118     /**
119      * Sets the provider of the current time to class specified.
120      * <p>
121      * This method changes the behaviour of {@link #currentTimeMillis()}.
122      * Whenever the current time is queried, the specified class will be called.
123      * 
124      * @param millisProvider  the provider of the current time to use, not null
125      * @throws SecurityException if the application does not have sufficient security rights
126      * @since 2.0
127      */

128     public static final void setCurrentMillisProvider(MillisProvider millisProvider) throws SecurityException {
129         if (millisProvider == null) {
130             throw new IllegalArgumentException("The MillisProvider must not be null");
131         }
132         checkPermission();
133         cMillisProvider = millisProvider;
134     }
135
136     /**
137      * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
138      * 
139      * @throws SecurityException if the provider may not be changed
140      */

141     private static void checkPermission() throws SecurityException {
142         SecurityManager sm = System.getSecurityManager();
143         if (sm != null) {
144             sm.checkPermission(new JodaTimePermission("CurrentTime.setProvider"));
145         }
146     }
147
148     //-----------------------------------------------------------------------
149     /**
150      * Gets the millisecond instant from the specified instant object handling null.
151      * <p>
152      * If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
153      * will be returned. Otherwise, the millis from the object are returned.
154      * 
155      * @param instant  the instant to examine, null means now
156      * @return the time in milliseconds from 1970-01-01T00:00:00Z
157      */

158     public static final long getInstantMillis(ReadableInstant instant) {
159         if (instant == null) {
160             return DateTimeUtils.currentTimeMillis();
161         }
162         return instant.getMillis();
163     }
164
165     //-----------------------------------------------------------------------
166     /**
167      * Gets the chronology from the specified instant object handling null.
168      * <p>
169      * If the instant object is <code>null</code>, or the instant's chronology is
170      * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
171      * Otherwise, the chronology from the object is returned.
172      * 
173      * @param instant  the instant to examine, null means ISO in the default zone
174      * @return the chronology, never null
175      */

176     public static final Chronology getInstantChronology(ReadableInstant instant) {
177         if (instant == null) {
178             return ISOChronology.getInstance();
179         }
180         Chronology chrono = instant.getChronology();
181         if (chrono == null) {
182             return ISOChronology.getInstance();
183         }
184         return chrono;
185     }
186
187     //-----------------------------------------------------------------------
188     /**
189      * Gets the chronology from the specified instant based interval handling null.
190      * <p>
191      * The chronology is obtained from the start if that is not null, or from the
192      * end if the start is null. The result is additionally checked, and if still
193      * null then {@link ISOChronology#getInstance()} will be returned.
194      * 
195      * @param start  the instant to examine and use as the primary source of the chronology
196      * @param end  the instant to examine and use as the secondary source of the chronology
197      * @return the chronology, never null
198      */

199     public static final Chronology getIntervalChronology(ReadableInstant start, ReadableInstant end) {
200         Chronology chrono = null;
201         if (start != null) {
202             chrono = start.getChronology();
203         } else if (end != null) {
204             chrono = end.getChronology();
205         }
206         if (chrono == null) {
207             chrono = ISOChronology.getInstance();
208         }
209         return chrono;
210     }
211
212     //-----------------------------------------------------------------------
213     /**
214      * Gets the chronology from the specified interval object handling null.
215      * <p>
216      * If the interval object is <code>null</code>, or the interval's chronology is
217      * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
218      * Otherwise, the chronology from the object is returned.
219      * 
220      * @param interval  the interval to examine, null means ISO in the default zone
221      * @return the chronology, never null
222      */

223     public static final Chronology getIntervalChronology(ReadableInterval interval) {
224         if (interval == null) {
225             return ISOChronology.getInstance();
226         }
227         Chronology chrono = interval.getChronology();
228         if (chrono == null) {
229             return ISOChronology.getInstance();
230         }
231         return chrono;
232     }
233
234     //-----------------------------------------------------------------------
235     /**
236      * Gets the interval handling null.
237      * <p>
238      * If the interval is <code>null</code>, an interval representing now
239      * to now in the {@link ISOChronology#getInstance() ISOChronology}
240      * will be returned. Otherwise, the interval specified is returned.
241      * 
242      * @param interval  the interval to use, null means now to now
243      * @return the interval, never null
244      * @since 1.1
245      */

246     public static final ReadableInterval getReadableInterval(ReadableInterval interval) {
247         if (interval == null) {
248             long now = DateTimeUtils.currentTimeMillis();
249             interval = new Interval(now, now);
250         }
251         return interval;
252     }
253
254     //-----------------------------------------------------------------------
255     /**
256      * Gets the chronology handling null.
257      * <p>
258      * If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
259      * will be returned. Otherwise, the chronology is returned.
260      * 
261      * @param chrono  the chronology to use, null means ISO in the default zone
262      * @return the chronology, never null
263      */

264     public static final Chronology getChronology(Chronology chrono) {
265         if (chrono == null) {
266             return ISOChronology.getInstance();
267         }
268         return chrono;
269     }
270
271     //-----------------------------------------------------------------------
272     /**
273      * Gets the zone handling null.
274      * <p>
275      * If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
276      * will be returned. Otherwise, the zone specified is returned.
277      * 
278      * @param zone  the time zone to use, null means the default zone
279      * @return the time zone, never null
280      */

281     public static final DateTimeZone getZone(DateTimeZone zone) {
282         if (zone == null) {
283             return DateTimeZone.getDefault();
284         }
285         return zone;
286     }
287
288     //-----------------------------------------------------------------------
289     /**
290      * Gets the period type handling null.
291      * <p>
292      * If the zone is <code>null</code>, {@link PeriodType#standard()}
293      * will be returned. Otherwise, the type specified is returned.
294      * 
295      * @param type  the time zone to use, null means the standard type
296      * @return the type to use, never null
297      */

298     public static final PeriodType getPeriodType(PeriodType type) {
299         if (type == null) {
300             return PeriodType.standard();
301         }
302         return type;
303     }
304
305     //-----------------------------------------------------------------------
306     /**
307      * Gets the millisecond duration from the specified duration object handling null.
308      * <p>
309      * If the duration object is <code>null</code>, zero will be returned.
310      * Otherwise, the millis from the object are returned.
311      * 
312      * @param duration  the duration to examine, null means zero
313      * @return the duration in milliseconds
314      */

315     public static final long getDurationMillis(ReadableDuration duration) {
316         if (duration == null) {
317             return 0L;
318         }
319         return duration.getMillis();
320     }
321
322     //-----------------------------------------------------------------------
323     /**
324      * Checks whether the partial is contiguous.
325      * <p>
326      * A partial is contiguous if one field starts where another ends.
327      * <p>
328      * For example <code>LocalDate</code> is contiguous because DayOfMonth has
329      * the same range (Month) as the unit of the next field (MonthOfYear), and
330      * MonthOfYear has the same range (Year) as the unit of the next field (Year).
331      * <p>
332      * Similarly, <code>LocalTime</code> is contiguous, as it consists of
333      * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
334      * the names of each field 'join up').
335      * <p>
336      * However, a Year/HourOfDay partial is not contiguous because the range
337      * field Day is not equal to the next field Year.
338      * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
339      * the range Month is not equal to the next field Day.
340      * 
341      * @param partial  the partial to check
342      * @return true if the partial is contiguous
343      * @throws IllegalArgumentException if the partial is null
344      * @since 1.1
345      */

346     public static final boolean isContiguous(ReadablePartial partial) {
347         if (partial == null) {
348             throw new IllegalArgumentException("Partial must not be null");
349         }
350         DurationFieldType lastType = null;
351         for (int i = 0; i < partial.size(); i++) {
352             DateTimeField loopField = partial.getField(i);
353             if (i > 0) {
354                 if (loopField.getRangeDurationField() == null || loopField.getRangeDurationField().getType() != lastType) {
355                     return false;
356                 }
357             }
358             lastType = loopField.getDurationField().getType();
359         }
360         return true;
361     }
362
363     //-----------------------------------------------------------------------
364     /**
365      * Gets the {@link DateFormatSymbols} based on the given locale.
366      * <p>
367      * If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will
368      * be used in order to allow the use of locales defined as extensions.
369      * Otherwise, new DateFormatSymbols(locale) will be used.
370      * See JDK 6 {@link DateFormatSymbols} for further information.
371      * 
372      * @param locale  the {@link Locale} used to get the correct {@link DateFormatSymbols}
373      * @return the symbols
374      * @since 2.0
375      */

376     public static final DateFormatSymbols getDateFormatSymbols(Locale locale) {
377         try {
378             Method method = DateFormatSymbols.class.getMethod("getInstance"new Class[] {Locale.class});
379             return (DateFormatSymbols) method.invoke(nullnew Object[] {locale});
380         } catch (Exception ex) {
381             return new DateFormatSymbols(locale);
382         }
383     }
384
385     //-----------------------------------------------------------------------
386     /**
387      * Gets the default map of time zone names.
388      * <p>
389      * This can be changed by {@link #setDefaultTimeZoneNames}.
390      * <p>
391      * The default set of short time zone names is as follows:
392      * <ul>
393      * <li>UT - UTC
394      * <li>UTC - UTC
395      * <li>GMT - UTC
396      * <li>EST - America/New_York
397      * <li>EDT - America/New_York
398      * <li>CST - America/Chicago
399      * <li>CDT - America/Chicago
400      * <li>MST - America/Denver
401      * <li>MDT - America/Denver
402      * <li>PST - America/Los_Angeles
403      * <li>PDT - America/Los_Angeles
404      * </ul>
405      * 
406      * @return the unmodifiable map of abbreviations to zones, not null
407      * @since 2.2
408      */

409     public static final Map<String, DateTimeZone> getDefaultTimeZoneNames() {
410         Map<String, DateTimeZone> names = cZoneNames.get();
411         if (names == null) {
412             names = buildDefaultTimeZoneNames();
413             if (!cZoneNames.compareAndSet(null, names)) {
414                 names = cZoneNames.get();
415             }
416         }
417         return names;
418     }
419
420     /**
421      * Sets the default map of time zone names.
422      * <p>
423      * The map is copied before storage.
424      * 
425      * @param names  the map of abbreviations to zones, not null
426      * @since 2.2
427      */

428     public static final void setDefaultTimeZoneNames(Map<String, DateTimeZone> names) {
429         cZoneNames.set(Collections.unmodifiableMap(new HashMap<String, DateTimeZone>(names)));
430     }
431
432     private static Map<String, DateTimeZone> buildDefaultTimeZoneNames() {
433         // names from RFC-822 / JDK
434         // this is all very US-centric and dubious, but perhaps it will help some
435         Map<String, DateTimeZone> map = new LinkedHashMap<String, DateTimeZone>();
436         map.put("UT", DateTimeZone.UTC);
437         map.put("UTC", DateTimeZone.UTC);
438         map.put("GMT", DateTimeZone.UTC);
439         put(map, "EST""America/New_York");
440         put(map, "EDT""America/New_York");
441         put(map, "CST""America/Chicago");
442         put(map, "CDT""America/Chicago");
443         put(map, "MST""America/Denver");
444         put(map, "MDT""America/Denver");
445         put(map, "PST""America/Los_Angeles");
446         put(map, "PDT""America/Los_Angeles");
447         return Collections.unmodifiableMap(map);
448     }
449     private static void put(Map<String, DateTimeZone> map, String name, String id) {
450         try {
451             map.put(name, DateTimeZone.forID(id));
452         } catch (RuntimeException ex) {
453             // ignore
454         }
455     }
456     //-------------------------------------------------------------------------
457     /**
458      * Calculates the astronomical Julian Day for an instant.
459      * <p>
460      * The <a href="http://en.wikipedia.org/wiki/Julian_day">Julian day</a> is a well-known
461      * system of time measurement for scientific use by the astronomy community.
462      * It expresses the interval of time in days and fractions of a day since
463      * January 1, 4713 BC (Julian) Greenwich noon.
464      * <p>
465      * Each day starts at midday (not midnight) and time is expressed as a fraction.
466      * Thus the fraction 0.25 is 18:00. equal to one quarter of the day from midday to midday.
467      * <p>
468      * Note that this method has nothing to do with the day-of-year.
469      * 
470      * @param epochMillis  the epoch millis from 1970-01-01Z
471      * @return the astronomical Julian Day represented by the specified instant
472      * @since 2.2
473      */

474     public static final double toJulianDay(long epochMillis) {
475         // useful links
476         // http://en.wikipedia.org/wiki/Julian_day#cite_note-13 - Wikipedia
477         // http://aa.usno.navy.mil/data/docs/JulianDate.php" - USNO
478         // http://users.zoominternet.net/~matto/Java/Julian%20Date%20Converter.htm - Julian Date Converter by Matt Oltersdorf
479         // http://ssd.jpl.nasa.gov/tc.cgi#top - CalTech
480         double epochDay = epochMillis / 86400000d;
481         return epochDay + 2440587.5d;
482     }
483
484     /**
485      * Calculates the astronomical Julian Day Number for an instant.
486      * <p>
487      * The {@link #toJulianDay(long)} method calculates the astronomical Julian Day
488      * with a fraction based on days starting at midday.
489      * This method calculates the variant where days start at midnight.
490      * JDN 0 is used for the date equivalent to Monday January 1, 4713 BC (Julian).
491      * Thus these days start 12 hours before those of the fractional Julian Day.
492      * <p>
493      * Note that this method has nothing to do with the day-of-year.
494      * 
495      * @param epochMillis  the epoch millis from 1970-01-01Z
496      * @return the astronomical Julian Day represented by the specified instant
497      * @since 2.2
498      */

499     public static final long toJulianDayNumber(long epochMillis) {
500         return (long) Math.floor(toJulianDay(epochMillis) + 0.5d);
501     }
502
503     /**
504      * Creates a date-time from a Julian Day.
505      * <p>
506      * Returns the {@code DateTime} object equal to the specified Julian Day.
507      * 
508      * @param julianDay  the Julian Day
509      * @return the epoch millis from 1970-01-01Z
510      * @since 2.2
511      */

512     public static final long fromJulianDay(double julianDay) {
513         double epochDay = julianDay - 2440587.5d;
514         return (long) (epochDay * 86400000d);
515     }
516
517     //-----------------------------------------------------------------------
518     /**
519      * A millisecond provider, allowing control of the system clock.
520      * 
521      * @author Stephen Colebourne
522      * @since 2.0 (previously private)
523      */

524     public static interface MillisProvider {
525         /**
526          * Gets the current time.
527          * <p>
528          * Implementations of this method must be thread-safe.
529          * 
530          * @return the current time in milliseconds
531          */

532         long getMillis();
533     }
534
535     /**
536      * System millis provider.
537      */

538     static class SystemMillisProvider implements MillisProvider {
539         /**
540          * Gets the current time.
541          * @return the current time in millis
542          */

543         public long getMillis() {
544             return System.currentTimeMillis();
545         }
546     }
547
548     /**
549      * Fixed millisecond provider.
550      */

551     static class FixedMillisProvider implements MillisProvider {
552         /** The fixed millis value. */
553         private final long iMillis;
554         
555         /**
556          * Constructor.
557          * @param fixedMillis  the millis value
558          */

559         FixedMillisProvider(long fixedMillis) {
560             iMillis = fixedMillis;
561         }
562         
563         /**
564          * Gets the current time.
565          * @return the current time in millis
566          */

567         public long getMillis() {
568             return iMillis;
569         }
570     }
571
572     /**
573      * Offset from system millis provider.
574      */

575     static class OffsetMillisProvider implements MillisProvider {
576         /** The millis offset. */
577         private final long iMillis;
578         
579         /**
580          * Constructor.
581          * @param offsetMillis  the millis offset
582          */

583         OffsetMillisProvider(long offsetMillis) {
584             iMillis = offsetMillis;
585         }
586         
587         /**
588          * Gets the current time.
589          * @return the current time in millis
590          */

591         public long getMillis() {
592             return System.currentTimeMillis() + iMillis;
593         }
594     }
595
596 }
597