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 }