View Javadoc

1   /*
2    *  Copyright 2001-2012 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  
26  import org.joda.time.chrono.ISOChronology;
27  
28  /**
29   * DateTimeUtils provide public utility methods for the date-time library.
30   * <p>
31   * DateTimeUtils is thread-safe although shared static variables are used.
32   *
33   * @author Stephen Colebourne
34   * @since 1.0
35   */
36  public class DateTimeUtils {
37  
38      /** The singleton instance of the system millisecond provider. */
39      private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
40      /** The millisecond provider currently in use. */
41      private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
42      /** The millisecond provider currently in use. */
43      private static volatile Map<String, DateTimeZone> cZoneNames;
44      static {
45          // names from RFC-822 / JDK
46          // this is all very US-centric and dubious, but perhaps it will help some
47          Map<String, DateTimeZone> map = new LinkedHashMap<String, DateTimeZone>();
48          map.put("UT", DateTimeZone.UTC);
49          map.put("UTC", DateTimeZone.UTC);
50          map.put("GMT", DateTimeZone.UTC);
51          put(map, "EST", "America/New_York");
52          put(map, "EDT", "America/New_York");
53          put(map, "CST", "America/Chicago");
54          put(map, "CDT", "America/Chicago");
55          put(map, "MST", "America/Denver");
56          put(map, "MDT", "America/Denver");
57          put(map, "PST", "America/Los_Angeles");
58          put(map, "PDT", "America/Los_Angeles");
59          cZoneNames = Collections.unmodifiableMap(map);
60      }
61      private static void put(Map<String, DateTimeZone> map, String name, String id) {
62          try {
63              map.put(name, DateTimeZone.forID(id));
64          } catch (RuntimeException ex) {
65              // ignore
66          }
67      }
68  
69      /**
70       * Restrictive constructor
71       */
72      protected DateTimeUtils() {
73          super();
74      }
75  
76      //-----------------------------------------------------------------------
77      /**
78       * Gets the current time in milliseconds.
79       * <p>
80       * By default this returns <code>System.currentTimeMillis()</code>.
81       * This may be changed using other methods in this class.
82       * 
83       * @return the current time in milliseconds from 1970-01-01T00:00:00Z
84       */
85      public static final long currentTimeMillis() {
86          return cMillisProvider.getMillis();
87      }
88  
89      /**
90       * Resets the current time to return the system time.
91       * <p>
92       * This method changes the behaviour of {@link #currentTimeMillis()}.
93       * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
94       * 
95       * @throws SecurityException if the application does not have sufficient security rights
96       */
97      public static final void setCurrentMillisSystem() throws SecurityException {
98          checkPermission();
99          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 }