1 16 package org.joda.time.chrono; 17 18 import java.util.HashMap ; 19 import java.util.Locale ; 20 21 import org.joda.time.Chronology; 22 import org.joda.time.DateTimeConstants; 23 import org.joda.time.DateTimeField; 24 import org.joda.time.DateTimeZone; 25 import org.joda.time.DurationField; 26 import org.joda.time.IllegalFieldValueException; 27 import org.joda.time.Instant; 28 import org.joda.time.ReadablePartial; 29 import org.joda.time.field.BaseDateTimeField; 30 import org.joda.time.field.BaseDurationField; 31 import org.joda.time.format.DateTimeFormat; 32 33 42 public final class ZonedChronology extends AssembledChronology { 43 44 45 private static final long serialVersionUID = -1079258847191166848L; 46 47 55 public static ZonedChronology getInstance(Chronology base, DateTimeZone zone) { 56 if (base == null) { 57 throw new IllegalArgumentException ("Must supply a chronology"); 58 } 59 base = base.withUTC(); 60 if (base == null) { 61 throw new IllegalArgumentException ("UTC chronology must not be null"); 62 } 63 if (zone == null) { 64 throw new IllegalArgumentException ("DateTimeZone must not be null"); 65 } 66 return new ZonedChronology(base, zone); 67 } 68 69 static boolean useTimeArithmetic(DurationField field) { 70 return field != null && field.getUnitMillis() < DateTimeConstants.MILLIS_PER_HOUR * 12; 73 } 74 75 81 private ZonedChronology(Chronology base, DateTimeZone zone) { 82 super(base, zone); 83 } 84 85 public DateTimeZone getZone() { 86 return (DateTimeZone)getParam(); 87 } 88 89 public Chronology withUTC() { 90 return getBase(); 91 } 92 93 public Chronology withZone(DateTimeZone zone) { 94 if (zone == null) { 95 zone = DateTimeZone.getDefault(); 96 } 97 if (zone == getParam()) { 98 return this; 99 } 100 if (zone == DateTimeZone.UTC) { 101 return getBase(); 102 } 103 return new ZonedChronology(getBase(), zone); 104 } 105 106 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth, 107 int millisOfDay) 108 throws IllegalArgumentException 109 { 110 return localToUTC(getBase().getDateTimeMillis 111 (year, monthOfYear, dayOfMonth, millisOfDay)); 112 } 113 114 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth, 115 int hourOfDay, int minuteOfHour, 116 int secondOfMinute, int millisOfSecond) 117 throws IllegalArgumentException 118 { 119 return localToUTC(getBase().getDateTimeMillis 120 (year, monthOfYear, dayOfMonth, 121 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond)); 122 } 123 124 public long getDateTimeMillis(long instant, 125 int hourOfDay, int minuteOfHour, 126 int secondOfMinute, int millisOfSecond) 127 throws IllegalArgumentException 128 { 129 return localToUTC(getBase().getDateTimeMillis 130 (instant + getZone().getOffset(instant), 131 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond)); 132 } 133 134 138 private long localToUTC(long instant) { 139 DateTimeZone zone = getZone(); 140 int offset = zone.getOffsetFromLocal(instant); 141 instant -= offset; 142 if (offset != zone.getOffset(instant)) { 143 throw new IllegalArgumentException 144 ("Illegal instant due to time zone offset transition: " + 145 DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").print(new Instant(instant))); 146 } 147 return instant; 148 } 149 150 protected void assemble(Fields fields) { 151 HashMap converted = new HashMap (); 154 155 157 fields.eras = convertField(fields.eras, converted); 158 fields.centuries = convertField(fields.centuries, converted); 159 fields.years = convertField(fields.years, converted); 160 fields.months = convertField(fields.months, converted); 161 fields.weekyears = convertField(fields.weekyears, converted); 162 fields.weeks = convertField(fields.weeks, converted); 163 fields.days = convertField(fields.days, converted); 164 165 fields.halfdays = convertField(fields.halfdays, converted); 166 fields.hours = convertField(fields.hours, converted); 167 fields.minutes = convertField(fields.minutes, converted); 168 fields.seconds = convertField(fields.seconds, converted); 169 fields.millis = convertField(fields.millis, converted); 170 171 173 fields.year = convertField(fields.year, converted); 174 fields.yearOfEra = convertField(fields.yearOfEra, converted); 175 fields.yearOfCentury = convertField(fields.yearOfCentury, converted); 176 fields.centuryOfEra = convertField(fields.centuryOfEra, converted); 177 fields.era = convertField(fields.era, converted); 178 fields.dayOfWeek = convertField(fields.dayOfWeek, converted); 179 fields.dayOfMonth = convertField(fields.dayOfMonth, converted); 180 fields.dayOfYear = convertField(fields.dayOfYear, converted); 181 fields.monthOfYear = convertField(fields.monthOfYear, converted); 182 fields.weekOfWeekyear = convertField(fields.weekOfWeekyear, converted); 183 fields.weekyear = convertField(fields.weekyear, converted); 184 fields.weekyearOfCentury = convertField(fields.weekyearOfCentury, converted); 185 186 fields.millisOfSecond = convertField(fields.millisOfSecond, converted); 187 fields.millisOfDay = convertField(fields.millisOfDay, converted); 188 fields.secondOfMinute = convertField(fields.secondOfMinute, converted); 189 fields.secondOfDay = convertField(fields.secondOfDay, converted); 190 fields.minuteOfHour = convertField(fields.minuteOfHour, converted); 191 fields.minuteOfDay = convertField(fields.minuteOfDay, converted); 192 fields.hourOfDay = convertField(fields.hourOfDay, converted); 193 fields.hourOfHalfday = convertField(fields.hourOfHalfday, converted); 194 fields.clockhourOfDay = convertField(fields.clockhourOfDay, converted); 195 fields.clockhourOfHalfday = convertField(fields.clockhourOfHalfday, converted); 196 fields.halfdayOfDay = convertField(fields.halfdayOfDay, converted); 197 } 198 199 private DurationField convertField(DurationField field, HashMap converted) { 200 if (field == null || !field.isSupported()) { 201 return field; 202 } 203 if (converted.containsKey(field)) { 204 return (DurationField)converted.get(field); 205 } 206 ZonedDurationField zonedField = new ZonedDurationField(field, getZone()); 207 converted.put(field, zonedField); 208 return zonedField; 209 } 210 211 private DateTimeField convertField(DateTimeField field, HashMap converted) { 212 if (field == null || !field.isSupported()) { 213 return field; 214 } 215 if (converted.containsKey(field)) { 216 return (DateTimeField)converted.get(field); 217 } 218 ZonedDateTimeField zonedField = 219 new ZonedDateTimeField(field, getZone(), 220 convertField(field.getDurationField(), converted), 221 convertField(field.getRangeDurationField(), converted), 222 convertField(field.getLeapDurationField(), converted)); 223 converted.put(field, zonedField); 224 return zonedField; 225 } 226 227 236 public boolean equals(Object obj) { 237 if (this == obj) { 238 return true; 239 } 240 if (obj instanceof ZonedChronology == false) { 241 return false; 242 } 243 ZonedChronology chrono = (ZonedChronology) obj; 244 return 245 getBase().equals(chrono.getBase()) && 246 getZone().equals(chrono.getZone()); 247 } 248 249 255 public int hashCode() { 256 return 326565 + getZone().hashCode() * 11 + getBase().hashCode() * 7; 257 } 258 259 264 public String toString() { 265 return "ZonedChronology[" + getBase() + ", " + getZone().getID() + ']'; 266 } 267 268 276 static class ZonedDurationField extends BaseDurationField { 277 private static final long serialVersionUID = -485345310999208286L; 278 279 final DurationField iField; 280 final boolean iTimeField; 281 final DateTimeZone iZone; 282 283 ZonedDurationField(DurationField field, DateTimeZone zone) { 284 super(field.getType()); 285 if (!field.isSupported()) { 286 throw new IllegalArgumentException (); 287 } 288 iField = field; 289 iTimeField = useTimeArithmetic(field); 290 iZone = zone; 291 } 292 293 public boolean isPrecise() { 294 return iTimeField ? iField.isPrecise() : this.iZone.isFixed(); 295 } 296 297 public long getUnitMillis() { 298 return iField.getUnitMillis(); 299 } 300 301 public int getValue(long duration, long instant) { 302 return iField.getValue(duration, addOffset(instant)); 303 } 304 305 public long getValueAsLong(long duration, long instant) { 306 return iField.getValueAsLong(duration, addOffset(instant)); 307 } 308 309 public long getMillis(int value, long instant) { 310 return iField.getMillis(value, addOffset(instant)); 311 } 312 313 public long getMillis(long value, long instant) { 314 return iField.getMillis(value, addOffset(instant)); 315 } 316 317 public long add(long instant, int value) { 318 int offset = getOffsetToAdd(instant); 319 instant = iField.add(instant + offset, value); 320 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 321 } 322 323 public long add(long instant, long value) { 324 int offset = getOffsetToAdd(instant); 325 instant = iField.add(instant + offset, value); 326 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 327 } 328 329 public int getDifference(long minuendInstant, long subtrahendInstant) { 330 int offset = getOffsetToAdd(subtrahendInstant); 331 return iField.getDifference 332 (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), 333 subtrahendInstant + offset); 334 } 335 336 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { 337 int offset = getOffsetToAdd(subtrahendInstant); 338 return iField.getDifferenceAsLong 339 (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), 340 subtrahendInstant + offset); 341 } 342 343 private int getOffsetToAdd(long instant) { 344 int offset = this.iZone.getOffset(instant); 345 long sum = instant + offset; 346 if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { 348 throw new ArithmeticException ("Adding time zone offset caused overflow"); 349 } 350 return offset; 351 } 352 353 private int getOffsetFromLocalToSubtract(long instant) { 354 int offset = this.iZone.getOffsetFromLocal(instant); 355 long diff = instant - offset; 356 if ((instant ^ diff) < 0 && (instant ^ offset) < 0) { 358 throw new ArithmeticException ("Subtracting time zone offset caused overflow"); 359 } 360 return offset; 361 } 362 363 private long addOffset(long instant) { 364 int offset = this.iZone.getOffset(instant); 365 long sum = instant + offset; 366 if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { 368 throw new ArithmeticException ("Adding time zone offset caused overflow"); 369 } 370 return sum; 371 } 372 } 373 374 380 static final class ZonedDateTimeField extends BaseDateTimeField { 381 private static final long serialVersionUID = -3968986277775529794L; 382 383 final DateTimeField iField; 384 final DateTimeZone iZone; 385 final DurationField iDurationField; 386 final boolean iTimeField; 387 final DurationField iRangeDurationField; 388 final DurationField iLeapDurationField; 389 390 ZonedDateTimeField(DateTimeField field, 391 DateTimeZone zone, 392 DurationField durationField, 393 DurationField rangeDurationField, 394 DurationField leapDurationField) { 395 super(field.getType()); 396 if (!field.isSupported()) { 397 throw new IllegalArgumentException (); 398 } 399 iField = field; 400 iZone = zone; 401 iDurationField = durationField; 402 iTimeField = useTimeArithmetic(durationField); 403 iRangeDurationField = rangeDurationField; 404 iLeapDurationField = leapDurationField; 405 } 406 407 public boolean isLenient() { 408 return iField.isLenient(); 409 } 410 411 public int get(long instant) { 412 return iField.get(addOffset(instant)); 413 } 414 415 public String getAsText(long instant, Locale locale) { 416 return iField.getAsText(addOffset(instant), locale); 417 } 418 419 public String getAsShortText(long instant, Locale locale) { 420 return iField.getAsShortText(addOffset(instant), locale); 421 } 422 423 public String getAsText(int fieldValue, Locale locale) { 424 return iField.getAsText(fieldValue, locale); 425 } 426 427 public String getAsShortText(int fieldValue, Locale locale) { 428 return iField.getAsShortText(fieldValue, locale); 429 } 430 431 public long add(long instant, int value) { 432 int offset = getOffsetToAdd(instant); 433 instant = iField.add(instant + offset, value); 434 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 435 } 436 437 public long add(long instant, long value) { 438 int offset = getOffsetToAdd(instant); 439 instant = iField.add(instant + offset, value); 440 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 441 } 442 443 public long addWrapField(long instant, int value) { 444 int offset = getOffsetToAdd(instant); 445 instant = iField.addWrapField(instant + offset, value); 446 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 447 } 448 449 public long set(long instant, int value) { 450 long offset = getOffsetToAdd(instant); 451 452 instant = iField.set(instant + offset, value); 453 long offsetFromLocal = getOffsetFromLocalToSubtract(instant); 454 instant -= offsetFromLocal; 455 456 if (offset != offsetFromLocal) { 457 if (get(instant) != value) { 458 throw new IllegalFieldValueException 459 (iField.getType(), new Integer (value), null, null); 460 } 461 } 462 463 return instant; 464 } 465 466 public long set(long instant, String text, Locale locale) { 467 instant = iField.set(addOffset(instant), text, locale); 468 return instant - getOffsetFromLocalToSubtract(instant); 470 } 471 472 public int getDifference(long minuendInstant, long subtrahendInstant) { 473 int offset = getOffsetToAdd(subtrahendInstant); 474 return iField.getDifference 475 (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), 476 subtrahendInstant + offset); 477 } 478 479 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) { 480 int offset = getOffsetToAdd(subtrahendInstant); 481 return iField.getDifferenceAsLong 482 (minuendInstant + (iTimeField ? offset : getOffsetToAdd(minuendInstant)), 483 subtrahendInstant + offset); 484 } 485 486 public final DurationField getDurationField() { 487 return iDurationField; 488 } 489 490 public final DurationField getRangeDurationField() { 491 return iRangeDurationField; 492 } 493 494 public boolean isLeap(long instant) { 495 return iField.isLeap(addOffset(instant)); 496 } 497 498 public int getLeapAmount(long instant) { 499 return iField.getLeapAmount(addOffset(instant)); 500 } 501 502 public final DurationField getLeapDurationField() { 503 return iLeapDurationField; 504 } 505 506 public long roundFloor(long instant) { 507 int offset = getOffsetToAdd(instant); 508 instant = iField.roundFloor(instant + offset); 509 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 510 } 511 512 public long roundCeiling(long instant) { 513 int offset = getOffsetToAdd(instant); 514 instant = iField.roundCeiling(instant + offset); 515 return instant - (iTimeField ? offset : getOffsetFromLocalToSubtract(instant)); 516 } 517 518 public long remainder(long instant) { 519 return iField.remainder(addOffset(instant)); 520 } 521 522 public int getMinimumValue() { 523 return iField.getMinimumValue(); 524 } 525 526 public int getMinimumValue(long instant) { 527 return iField.getMinimumValue(addOffset(instant)); 528 } 529 530 public int getMinimumValue(ReadablePartial instant) { 531 return iField.getMinimumValue(instant); 532 } 533 534 public int getMinimumValue(ReadablePartial instant, int[] values) { 535 return iField.getMinimumValue(instant, values); 536 } 537 538 public int getMaximumValue() { 539 return iField.getMaximumValue(); 540 } 541 542 public int getMaximumValue(long instant) { 543 return iField.getMaximumValue(addOffset(instant)); 544 } 545 546 public int getMaximumValue(ReadablePartial instant) { 547 return iField.getMaximumValue(instant); 548 } 549 550 public int getMaximumValue(ReadablePartial instant, int[] values) { 551 return iField.getMaximumValue(instant, values); 552 } 553 554 public int getMaximumTextLength(Locale locale) { 555 return iField.getMaximumTextLength(locale); 556 } 557 558 public int getMaximumShortTextLength(Locale locale) { 559 return iField.getMaximumShortTextLength(locale); 560 } 561 562 private int getOffsetToAdd(long instant) { 563 int offset = this.iZone.getOffset(instant); 564 long sum = instant + offset; 565 if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { 567 throw new ArithmeticException ("Adding time zone offset caused overflow"); 568 } 569 return offset; 570 } 571 572 private int getOffsetFromLocalToSubtract(long instant) { 573 int offset = this.iZone.getOffsetFromLocal(instant); 574 long diff = instant - offset; 575 if ((instant ^ diff) < 0 && (instant ^ offset) < 0) { 577 throw new ArithmeticException ("Subtracting time zone offset caused overflow"); 578 } 579 return offset; 580 } 581 582 private long addOffset(long instant) { 583 int offset = this.iZone.getOffset(instant); 584 long sum = instant + offset; 585 if ((instant ^ sum) < 0 && (instant ^ offset) >= 0) { 587 throw new ArithmeticException ("Adding time zone offset caused overflow"); 588 } 589 return sum; 590 } 591 } 592 593 } 594 | Popular Tags |