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 }