001 /*
002 * Copyright 2001-2010 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.Locale;
021
022 import org.joda.time.chrono.ISOChronology;
023
024 /**
025 * DateTimeUtils provide public utility methods for the date-time library.
026 * <p>
027 * DateTimeUtils is thread-safe although shared static variables are used.
028 *
029 * @author Stephen Colebourne
030 * @since 1.0
031 */
032 public class DateTimeUtils {
033
034 /** The singleton instance of the system millisecond provider. */
035 private static final SystemMillisProvider SYSTEM_MILLIS_PROVIDER = new SystemMillisProvider();
036 /** The millisecond provider currently in use. */
037 private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;
038
039 /**
040 * Restrictive constructor
041 */
042 protected DateTimeUtils() {
043 super();
044 }
045
046 //-----------------------------------------------------------------------
047 /**
048 * Gets the current time in milliseconds.
049 * <p>
050 * By default this returns <code>System.currentTimeMillis()</code>.
051 * This may be changed using other methods in this class.
052 *
053 * @return the current time in milliseconds from 1970-01-01T00:00:00Z
054 */
055 public static final long currentTimeMillis() {
056 return cMillisProvider.getMillis();
057 }
058
059 /**
060 * Resets the current time to return the system time.
061 * <p>
062 * This method changes the behaviour of {@link #currentTimeMillis()}.
063 * Whenever the current time is queried, {@link System#currentTimeMillis()} is used.
064 *
065 * @throws SecurityException if the application does not have sufficient security rights
066 */
067 public static final void setCurrentMillisSystem() throws SecurityException {
068 checkPermission();
069 cMillisProvider = SYSTEM_MILLIS_PROVIDER;
070 }
071
072 /**
073 * Sets the current time to return a fixed millisecond time.
074 * <p>
075 * This method changes the behaviour of {@link #currentTimeMillis()}.
076 * Whenever the current time is queried, the same millisecond time will be returned.
077 *
078 * @param fixedMillis the fixed millisecond time to use
079 * @throws SecurityException if the application does not have sufficient security rights
080 */
081 public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
082 checkPermission();
083 cMillisProvider = new FixedMillisProvider(fixedMillis);
084 }
085
086 /**
087 * Sets the current time to return the system time plus an offset.
088 * <p>
089 * This method changes the behaviour of {@link #currentTimeMillis()}.
090 * Whenever the current time is queried, {@link System#currentTimeMillis()} is used
091 * and then offset by adding the millisecond value specified here.
092 *
093 * @param offsetMillis the fixed millisecond time to use
094 * @throws SecurityException if the application does not have sufficient security rights
095 */
096 public static final void setCurrentMillisOffset(long offsetMillis) throws SecurityException {
097 checkPermission();
098 if (offsetMillis == 0) {
099 cMillisProvider = SYSTEM_MILLIS_PROVIDER;
100 } else {
101 cMillisProvider = new OffsetMillisProvider(offsetMillis);
102 }
103 }
104
105 /**
106 * Sets the provider of the current time to class specified.
107 * <p>
108 * This method changes the behaviour of {@link #currentTimeMillis()}.
109 * Whenever the current time is queried, the specified class will be called.
110 *
111 * @param millisProvider the provider of the current time to use, not null
112 * @throws SecurityException if the application does not have sufficient security rights
113 * @since 2.0
114 */
115 public static final void setCurrentMillisProvider(MillisProvider millisProvider) throws SecurityException {
116 if (millisProvider == null) {
117 throw new IllegalArgumentException("The MillisProvider must not be null");
118 }
119 checkPermission();
120 cMillisProvider = millisProvider;
121 }
122
123 /**
124 * Checks whether the provider may be changed using permission 'CurrentTime.setProvider'.
125 *
126 * @throws SecurityException if the provider may not be changed
127 */
128 private static void checkPermission() throws SecurityException {
129 SecurityManager sm = System.getSecurityManager();
130 if (sm != null) {
131 sm.checkPermission(new JodaTimePermission("CurrentTime.setProvider"));
132 }
133 }
134
135 //-----------------------------------------------------------------------
136 /**
137 * Gets the millisecond instant from the specified instant object handling null.
138 * <p>
139 * If the instant object is <code>null</code>, the {@link #currentTimeMillis()}
140 * will be returned. Otherwise, the millis from the object are returned.
141 *
142 * @param instant the instant to examine, null means now
143 * @return the time in milliseconds from 1970-01-01T00:00:00Z
144 */
145 public static final long getInstantMillis(ReadableInstant instant) {
146 if (instant == null) {
147 return DateTimeUtils.currentTimeMillis();
148 }
149 return instant.getMillis();
150 }
151
152 //-----------------------------------------------------------------------
153 /**
154 * Gets the chronology from the specified instant object handling null.
155 * <p>
156 * If the instant object is <code>null</code>, or the instant's chronology is
157 * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
158 * Otherwise, the chronology from the object is returned.
159 *
160 * @param instant the instant to examine, null means ISO in the default zone
161 * @return the chronology, never null
162 */
163 public static final Chronology getInstantChronology(ReadableInstant instant) {
164 if (instant == null) {
165 return ISOChronology.getInstance();
166 }
167 Chronology chrono = instant.getChronology();
168 if (chrono == null) {
169 return ISOChronology.getInstance();
170 }
171 return chrono;
172 }
173
174 //-----------------------------------------------------------------------
175 /**
176 * Gets the chronology from the specified instant based interval handling null.
177 * <p>
178 * The chronology is obtained from the start if that is not null, or from the
179 * end if the start is null. The result is additionally checked, and if still
180 * null then {@link ISOChronology#getInstance()} will be returned.
181 *
182 * @param start the instant to examine and use as the primary source of the chronology
183 * @param end the instant to examine and use as the secondary source of the chronology
184 * @return the chronology, never null
185 */
186 public static final Chronology getIntervalChronology(ReadableInstant start, ReadableInstant end) {
187 Chronology chrono = null;
188 if (start != null) {
189 chrono = start.getChronology();
190 } else if (end != null) {
191 chrono = end.getChronology();
192 }
193 if (chrono == null) {
194 chrono = ISOChronology.getInstance();
195 }
196 return chrono;
197 }
198
199 //-----------------------------------------------------------------------
200 /**
201 * Gets the chronology from the specified interval object handling null.
202 * <p>
203 * If the interval object is <code>null</code>, or the interval's chronology is
204 * <code>null</code>, {@link ISOChronology#getInstance()} will be returned.
205 * Otherwise, the chronology from the object is returned.
206 *
207 * @param interval the interval to examine, null means ISO in the default zone
208 * @return the chronology, never null
209 */
210 public static final Chronology getIntervalChronology(ReadableInterval interval) {
211 if (interval == null) {
212 return ISOChronology.getInstance();
213 }
214 Chronology chrono = interval.getChronology();
215 if (chrono == null) {
216 return ISOChronology.getInstance();
217 }
218 return chrono;
219 }
220
221 //-----------------------------------------------------------------------
222 /**
223 * Gets the interval handling null.
224 * <p>
225 * If the interval is <code>null</code>, an interval representing now
226 * to now in the {@link ISOChronology#getInstance() ISOChronology}
227 * will be returned. Otherwise, the interval specified is returned.
228 *
229 * @param interval the interval to use, null means now to now
230 * @return the interval, never null
231 * @since 1.1
232 */
233 public static final ReadableInterval getReadableInterval(ReadableInterval interval) {
234 if (interval == null) {
235 long now = DateTimeUtils.currentTimeMillis();
236 interval = new Interval(now, now);
237 }
238 return interval;
239 }
240
241 //-----------------------------------------------------------------------
242 /**
243 * Gets the chronology handling null.
244 * <p>
245 * If the chronology is <code>null</code>, {@link ISOChronology#getInstance()}
246 * will be returned. Otherwise, the chronology is returned.
247 *
248 * @param chrono the chronology to use, null means ISO in the default zone
249 * @return the chronology, never null
250 */
251 public static final Chronology getChronology(Chronology chrono) {
252 if (chrono == null) {
253 return ISOChronology.getInstance();
254 }
255 return chrono;
256 }
257
258 //-----------------------------------------------------------------------
259 /**
260 * Gets the zone handling null.
261 * <p>
262 * If the zone is <code>null</code>, {@link DateTimeZone#getDefault()}
263 * will be returned. Otherwise, the zone specified is returned.
264 *
265 * @param zone the time zone to use, null means the default zone
266 * @return the time zone, never null
267 */
268 public static final DateTimeZone getZone(DateTimeZone zone) {
269 if (zone == null) {
270 return DateTimeZone.getDefault();
271 }
272 return zone;
273 }
274
275 //-----------------------------------------------------------------------
276 /**
277 * Gets the period type handling null.
278 * <p>
279 * If the zone is <code>null</code>, {@link PeriodType#standard()}
280 * will be returned. Otherwise, the type specified is returned.
281 *
282 * @param type the time zone to use, null means the standard type
283 * @return the type to use, never null
284 */
285 public static final PeriodType getPeriodType(PeriodType type) {
286 if (type == null) {
287 return PeriodType.standard();
288 }
289 return type;
290 }
291
292 //-----------------------------------------------------------------------
293 /**
294 * Gets the millisecond duration from the specified duration object handling null.
295 * <p>
296 * If the duration object is <code>null</code>, zero will be returned.
297 * Otherwise, the millis from the object are returned.
298 *
299 * @param duration the duration to examine, null means zero
300 * @return the duration in milliseconds
301 */
302 public static final long getDurationMillis(ReadableDuration duration) {
303 if (duration == null) {
304 return 0L;
305 }
306 return duration.getMillis();
307 }
308
309 //-----------------------------------------------------------------------
310 /**
311 * Checks whether the partial is contiguous.
312 * <p>
313 * A partial is contiguous if one field starts where another ends.
314 * <p>
315 * For example <code>LocalDate</code> is contiguous because DayOfMonth has
316 * the same range (Month) as the unit of the next field (MonthOfYear), and
317 * MonthOfYear has the same range (Year) as the unit of the next field (Year).
318 * <p>
319 * Similarly, <code>LocalTime</code> is contiguous, as it consists of
320 * MillisOfSecond, SecondOfMinute, MinuteOfHour and HourOfDay (note how
321 * the names of each field 'join up').
322 * <p>
323 * However, a Year/HourOfDay partial is not contiguous because the range
324 * field Day is not equal to the next field Year.
325 * Similarly, a DayOfWeek/DayOfMonth partial is not contiguous because
326 * the range Month is not equal to the next field Day.
327 *
328 * @param partial the partial to check
329 * @return true if the partial is contiguous
330 * @throws IllegalArgumentException if the partial is null
331 * @since 1.1
332 */
333 public static final boolean isContiguous(ReadablePartial partial) {
334 if (partial == null) {
335 throw new IllegalArgumentException("Partial must not be null");
336 }
337 DurationFieldType lastType = null;
338 for (int i = 0; i < partial.size(); i++) {
339 DateTimeField loopField = partial.getField(i);
340 if (i > 0) {
341 if (loopField.getRangeDurationField().getType() != lastType) {
342 return false;
343 }
344 }
345 lastType = loopField.getDurationField().getType();
346 }
347 return true;
348 }
349
350 //-----------------------------------------------------------------------
351 /**
352 * Gets the {@link DateFormatSymbols} based on the given locale.
353 * <p>
354 * If JDK 6 or newer is being used, DateFormatSymbols.getInstance(locale) will
355 * be used in order to allow the use of locales defined as extensions.
356 * Otherwise, new DateFormatSymbols(locale) will be used.
357 * See JDK 6 {@link DateFormatSymbols} for further information.
358 *
359 * @param locale the {@link Locale} used to get the correct {@link DateFormatSymbols}
360 * @return the symbols
361 * @since 2.0
362 */
363 public static final DateFormatSymbols getDateFormatSymbols(Locale locale) {
364 try {
365 Method method = DateFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class});
366 return (DateFormatSymbols) method.invoke(null, new Object[] {locale});
367 } catch (Exception ex) {
368 return new DateFormatSymbols(locale);
369 }
370 }
371
372 //-----------------------------------------------------------------------
373 /**
374 * A millisecond provider, allowing control of the system clock.
375 *
376 * @author Stephen Colebourne
377 * @since 2.0 (previously private)
378 */
379 public static interface MillisProvider {
380 /**
381 * Gets the current time.
382 * <p>
383 * Implementations of this method must be thread-safe.
384 *
385 * @return the current time in milliseconds
386 */
387 long getMillis();
388 }
389
390 /**
391 * System millis provider.
392 */
393 static class SystemMillisProvider implements MillisProvider {
394 /**
395 * Gets the current time.
396 * @return the current time in millis
397 */
398 public long getMillis() {
399 return System.currentTimeMillis();
400 }
401 }
402
403 /**
404 * Fixed millisecond provider.
405 */
406 static class FixedMillisProvider implements MillisProvider {
407 /** The fixed millis value. */
408 private final long iMillis;
409
410 /**
411 * Constructor.
412 * @param offsetMillis the millis offset
413 */
414 FixedMillisProvider(long fixedMillis) {
415 iMillis = fixedMillis;
416 }
417
418 /**
419 * Gets the current time.
420 * @return the current time in millis
421 */
422 public long getMillis() {
423 return iMillis;
424 }
425 }
426
427 /**
428 * Offset from system millis provider.
429 */
430 static class OffsetMillisProvider implements MillisProvider {
431 /** The millis offset. */
432 private final long iMillis;
433
434 /**
435 * Constructor.
436 * @param offsetMillis the millis offset
437 */
438 OffsetMillisProvider(long offsetMillis) {
439 iMillis = offsetMillis;
440 }
441
442 /**
443 * Gets the current time.
444 * @return the current time in millis
445 */
446 public long getMillis() {
447 return System.currentTimeMillis() + iMillis;
448 }
449 }
450
451 }