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(null, new 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