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.io.IOException; 019 import java.io.ObjectInputStream; 020 import java.io.ObjectOutputStream; 021 import java.io.Serializable; 022 import java.util.Locale; 023 024 import org.joda.convert.FromString; 025 import org.joda.convert.ToString; 026 import org.joda.time.base.BaseDateTime; 027 import org.joda.time.chrono.ISOChronology; 028 import org.joda.time.field.AbstractReadableInstantFieldProperty; 029 import org.joda.time.field.FieldUtils; 030 import org.joda.time.format.DateTimeFormatter; 031 import org.joda.time.format.ISODateTimeFormat; 032 033 /** 034 * MutableDateTime is the standard implementation of a modifiable datetime class. 035 * It holds the datetime as milliseconds from the Java epoch of 1970-01-01T00:00:00Z. 036 * <p> 037 * This class uses a Chronology internally. The Chronology determines how the 038 * millisecond instant value is converted into the date time fields. 039 * The default Chronology is <code>ISOChronology</code> which is the agreed 040 * international standard and compatible with the modern Gregorian calendar. 041 * <p> 042 * Each individual field can be accessed in two ways: 043 * <ul> 044 * <li><code>getHourOfDay()</code> 045 * <li><code>hourOfDay().get()</code> 046 * </ul> 047 * The second technique also provides access to other useful methods on the 048 * field: 049 * <ul> 050 * <li>get numeric value 051 * <li>set numeric value 052 * <li>add to numeric value 053 * <li>add to numeric value wrapping with the field 054 * <li>get text value 055 * <li>get short text value 056 * <li>set text value 057 * <li>field maximum value 058 * <li>field minimum value 059 * </ul> 060 * 061 * <p> 062 * MutableDateTime is mutable and not thread-safe, unless concurrent threads 063 * are not invoking mutator methods. 064 * 065 * @author Guy Allard 066 * @author Brian S O'Neill 067 * @author Stephen Colebourne 068 * @author Mike Schrag 069 * @since 1.0 070 * @see DateTime 071 */ 072 public class MutableDateTime 073 extends BaseDateTime 074 implements ReadWritableDateTime, Cloneable, Serializable { 075 076 /** Serialization version */ 077 private static final long serialVersionUID = 2852608688135209575L; 078 079 /** Rounding is disabled */ 080 public static final int ROUND_NONE = 0; 081 /** Rounding mode as described by {@link DateTimeField#roundFloor} */ 082 public static final int ROUND_FLOOR = 1; 083 /** Rounding mode as described by {@link DateTimeField#roundCeiling} */ 084 public static final int ROUND_CEILING = 2; 085 /** Rounding mode as described by {@link DateTimeField#roundHalfFloor} */ 086 public static final int ROUND_HALF_FLOOR = 3; 087 /** Rounding mode as described by {@link DateTimeField#roundHalfCeiling} */ 088 public static final int ROUND_HALF_CEILING = 4; 089 /** Rounding mode as described by {@link DateTimeField#roundHalfEven} */ 090 public static final int ROUND_HALF_EVEN = 5; 091 092 /** The field to round on */ 093 private DateTimeField iRoundingField; 094 /** The mode of rounding */ 095 private int iRoundingMode; 096 097 //----------------------------------------------------------------------- 098 /** 099 * Obtains a {@code MutableDateTime} set to the current system millisecond time 100 * using <code>ISOChronology</code> in the default time zone. 101 * 102 * @return the current date-time, not null 103 * @since 2.0 104 */ 105 public static MutableDateTime now() { 106 return new MutableDateTime(); 107 } 108 109 /** 110 * Obtains a {@code MutableDateTime} set to the current system millisecond time 111 * using <code>ISOChronology</code> in the specified time zone. 112 * 113 * @param zone the time zone, not null 114 * @return the current date-time, not null 115 * @since 2.0 116 */ 117 public static MutableDateTime now(DateTimeZone zone) { 118 if (zone == null) { 119 throw new NullPointerException("Zone must not be null"); 120 } 121 return new MutableDateTime(zone); 122 } 123 124 /** 125 * Obtains a {@code MutableDateTime} set to the current system millisecond time 126 * using the specified chronology. 127 * 128 * @param chronology the chronology, not null 129 * @return the current date-time, not null 130 * @since 2.0 131 */ 132 public static MutableDateTime now(Chronology chronology) { 133 if (chronology == null) { 134 throw new NullPointerException("Chronology must not be null"); 135 } 136 return new MutableDateTime(chronology); 137 } 138 139 //----------------------------------------------------------------------- 140 /** 141 * Parses a {@code MutableDateTime} from the specified string. 142 * <p> 143 * This uses {@link ISODateTimeFormat#dateTimeParser()}. 144 * 145 * @param str the string to parse, not null 146 * @since 2.0 147 */ 148 @FromString 149 public static MutableDateTime parse(String str) { 150 return parse(str, ISODateTimeFormat.dateTimeParser().withOffsetParsed()); 151 } 152 153 /** 154 * Parses a {@code MutableDateTime} from the specified string using a formatter. 155 * 156 * @param str the string to parse, not null 157 * @param formatter the formatter to use, not null 158 * @since 2.0 159 */ 160 public static MutableDateTime parse(String str, DateTimeFormatter formatter) { 161 return formatter.parseDateTime(str).toMutableDateTime(); 162 } 163 164 //----------------------------------------------------------------------- 165 /** 166 * Constructs an instance set to the current system millisecond time 167 * using <code>ISOChronology</code> in the default time zone. 168 * 169 * @see #now() 170 */ 171 public MutableDateTime() { 172 super(); 173 } 174 175 /** 176 * Constructs an instance set to the current system millisecond time 177 * using <code>ISOChronology</code> in the specified time zone. 178 * <p> 179 * If the specified time zone is null, the default zone is used. 180 * 181 * @param zone the time zone, null means default zone 182 * @see #now(DateTimeZone) 183 */ 184 public MutableDateTime(DateTimeZone zone) { 185 super(zone); 186 } 187 188 /** 189 * Constructs an instance set to the current system millisecond time 190 * using the specified chronology. 191 * <p> 192 * If the chronology is null, <code>ISOChronology</code> 193 * in the default time zone is used. 194 * 195 * @param chronology the chronology, null means ISOChronology in default zone 196 * @see #now(Chronology) 197 */ 198 public MutableDateTime(Chronology chronology) { 199 super(chronology); 200 } 201 202 //----------------------------------------------------------------------- 203 /** 204 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 205 * using <code>ISOChronology</code> in the default time zone. 206 * 207 * @param instant the milliseconds from 1970-01-01T00:00:00Z 208 */ 209 public MutableDateTime(long instant) { 210 super(instant); 211 } 212 213 /** 214 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 215 * using <code>ISOChronology</code> in the specified time zone. 216 * <p> 217 * If the specified time zone is null, the default zone is used. 218 * 219 * @param instant the milliseconds from 1970-01-01T00:00:00Z 220 * @param zone the time zone, null means default zone 221 */ 222 public MutableDateTime(long instant, DateTimeZone zone) { 223 super(instant, zone); 224 } 225 226 /** 227 * Constructs an instance set to the milliseconds from 1970-01-01T00:00:00Z 228 * using the specified chronology. 229 * <p> 230 * If the chronology is null, <code>ISOChronology</code> 231 * in the default time zone is used. 232 * 233 * @param instant the milliseconds from 1970-01-01T00:00:00Z 234 * @param chronology the chronology, null means ISOChronology in default zone 235 */ 236 public MutableDateTime(long instant, Chronology chronology) { 237 super(instant, chronology); 238 } 239 240 //----------------------------------------------------------------------- 241 /** 242 * Constructs an instance from an Object that represents a datetime. 243 * <p> 244 * If the object implies a chronology (such as GregorianCalendar does), 245 * then that chronology will be used. Otherwise, ISO default is used. 246 * Thus if a GregorianCalendar is passed in, the chronology used will 247 * be GJ, but if a Date is passed in the chronology will be ISO. 248 * <p> 249 * The recognised object types are defined in 250 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 251 * include ReadableInstant, String, Calendar and Date. 252 * 253 * @param instant the datetime object, null means now 254 * @throws IllegalArgumentException if the instant is invalid 255 */ 256 public MutableDateTime(Object instant) { 257 super(instant, (Chronology) null); 258 } 259 260 /** 261 * Constructs an instance from an Object that represents a datetime, 262 * forcing the time zone to that specified. 263 * <p> 264 * If the object implies a chronology (such as GregorianCalendar does), 265 * then that chronology will be used, but with the time zone adjusted. 266 * Otherwise, ISO is used in the specified time zone. 267 * If the specified time zone is null, the default zone is used. 268 * Thus if a GregorianCalendar is passed in, the chronology used will 269 * be GJ, but if a Date is passed in the chronology will be ISO. 270 * <p> 271 * The recognised object types are defined in 272 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 273 * include ReadableInstant, String, Calendar and Date. 274 * 275 * @param instant the datetime object, null means now 276 * @param zone the time zone, null means default time zone 277 * @throws IllegalArgumentException if the instant is invalid 278 */ 279 public MutableDateTime(Object instant, DateTimeZone zone) { 280 super(instant, zone); 281 } 282 283 /** 284 * Constructs an instance from an Object that represents a datetime, 285 * using the specified chronology. 286 * <p> 287 * If the chronology is null, ISO in the default time zone is used. 288 * Any chronology implied by the object (such as GregorianCalendar does) 289 * is ignored. 290 * <p> 291 * The recognised object types are defined in 292 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 293 * include ReadableInstant, String, Calendar and Date. 294 * 295 * @param instant the datetime object, null means now 296 * @param chronology the chronology, null means ISOChronology in default zone 297 * @throws IllegalArgumentException if the instant is invalid 298 */ 299 public MutableDateTime(Object instant, Chronology chronology) { 300 super(instant, DateTimeUtils.getChronology(chronology)); 301 } 302 303 //----------------------------------------------------------------------- 304 /** 305 * Constructs an instance from datetime field values 306 * using <code>ISOChronology</code> in the default time zone. 307 * 308 * @param year the year 309 * @param monthOfYear the month of the year 310 * @param dayOfMonth the day of the month 311 * @param hourOfDay the hour of the day 312 * @param minuteOfHour the minute of the hour 313 * @param secondOfMinute the second of the minute 314 * @param millisOfSecond the millisecond of the second 315 */ 316 public MutableDateTime( 317 int year, 318 int monthOfYear, 319 int dayOfMonth, 320 int hourOfDay, 321 int minuteOfHour, 322 int secondOfMinute, 323 int millisOfSecond) { 324 super(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); 325 } 326 327 /** 328 * Constructs an instance from datetime field values 329 * using <code>ISOChronology</code> in the specified time zone. 330 * <p> 331 * If the specified time zone is null, the default zone is used. 332 * 333 * @param year the year 334 * @param monthOfYear the month of the year 335 * @param dayOfMonth the day of the month 336 * @param hourOfDay the hour of the day 337 * @param minuteOfHour the minute of the hour 338 * @param secondOfMinute the second of the minute 339 * @param millisOfSecond the millisecond of the second 340 * @param zone the time zone, null means default time zone 341 */ 342 public MutableDateTime( 343 int year, 344 int monthOfYear, 345 int dayOfMonth, 346 int hourOfDay, 347 int minuteOfHour, 348 int secondOfMinute, 349 int millisOfSecond, 350 DateTimeZone zone) { 351 super(year, monthOfYear, dayOfMonth, 352 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone); 353 } 354 355 /** 356 * Constructs an instance from datetime field values 357 * using the specified chronology. 358 * <p> 359 * If the chronology is null, <code>ISOChronology</code> 360 * in the default time zone is used. 361 * 362 * @param year the year 363 * @param monthOfYear the month of the year 364 * @param dayOfMonth the day of the month 365 * @param hourOfDay the hour of the day 366 * @param minuteOfHour the minute of the hour 367 * @param secondOfMinute the second of the minute 368 * @param millisOfSecond the millisecond of the second 369 * @param chronology the chronology, null means ISOChronology in default zone 370 */ 371 public MutableDateTime( 372 int year, 373 int monthOfYear, 374 int dayOfMonth, 375 int hourOfDay, 376 int minuteOfHour, 377 int secondOfMinute, 378 int millisOfSecond, 379 Chronology chronology) { 380 super(year, monthOfYear, dayOfMonth, 381 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, chronology); 382 } 383 384 //----------------------------------------------------------------------- 385 /** 386 * Gets the field used for rounding this instant, returning null if rounding 387 * is not enabled. 388 * 389 * @return the rounding field 390 */ 391 public DateTimeField getRoundingField() { 392 return iRoundingField; 393 } 394 395 /** 396 * Gets the rounding mode for this instant, returning ROUND_NONE if rounding 397 * is not enabled. 398 * 399 * @return the rounding mode constant 400 */ 401 public int getRoundingMode() { 402 return iRoundingMode; 403 } 404 405 /** 406 * Sets the status of rounding to use the specified field and ROUND_FLOOR mode. 407 * A null field will disable rounding. 408 * Once set, the instant is then rounded using the new field and mode. 409 * <p> 410 * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)} 411 * to be rounded. This can be used to control the precision of the instant, 412 * for example by setting a rounding field of minuteOfDay, the seconds and 413 * milliseconds will always be zero. 414 * 415 * @param field rounding field or null to disable 416 */ 417 public void setRounding(DateTimeField field) { 418 setRounding(field, MutableDateTime.ROUND_FLOOR); 419 } 420 421 /** 422 * Sets the status of rounding to use the specified field and mode. 423 * A null field or mode of ROUND_NONE will disable rounding. 424 * Once set, the instant is then rounded using the new field and mode. 425 * <p> 426 * Enabling rounding will cause all subsequent calls to {@link #setMillis(long)} 427 * to be rounded. This can be used to control the precision of the instant, 428 * for example by setting a rounding field of minuteOfDay, the seconds and 429 * milliseconds will always be zero. 430 * 431 * @param field rounding field or null to disable 432 * @param mode rounding mode or ROUND_NONE to disable 433 * @throws IllegalArgumentException if mode is unknown, no exception if field is null 434 */ 435 public void setRounding(DateTimeField field, int mode) { 436 if (field != null && (mode < ROUND_NONE || mode > ROUND_HALF_EVEN)) { 437 throw new IllegalArgumentException("Illegal rounding mode: " + mode); 438 } 439 iRoundingField = (mode == ROUND_NONE ? null : field); 440 iRoundingMode = (field == null ? ROUND_NONE : mode); 441 setMillis(getMillis()); 442 } 443 444 //----------------------------------------------------------------------- 445 /** 446 * Set the milliseconds of the datetime. 447 * <p> 448 * All changes to the millisecond field occurs via this method. 449 * 450 * @param instant the milliseconds since 1970-01-01T00:00:00Z to set the 451 * datetime to 452 */ 453 public void setMillis(long instant) { 454 switch (iRoundingMode) { 455 case ROUND_NONE: 456 break; 457 case ROUND_FLOOR: 458 instant = iRoundingField.roundFloor(instant); 459 break; 460 case ROUND_CEILING: 461 instant = iRoundingField.roundCeiling(instant); 462 break; 463 case ROUND_HALF_FLOOR: 464 instant = iRoundingField.roundHalfFloor(instant); 465 break; 466 case ROUND_HALF_CEILING: 467 instant = iRoundingField.roundHalfCeiling(instant); 468 break; 469 case ROUND_HALF_EVEN: 470 instant = iRoundingField.roundHalfEven(instant); 471 break; 472 } 473 474 super.setMillis(instant); 475 } 476 477 /** 478 * Sets the millisecond instant of this instant from another. 479 * <p> 480 * This method does not change the chronology of this instant, just the 481 * millisecond instant. 482 * 483 * @param instant the instant to use, null means now 484 */ 485 public void setMillis(ReadableInstant instant) { 486 long instantMillis = DateTimeUtils.getInstantMillis(instant); 487 setMillis(instantMillis); // set via this class not super 488 } 489 490 //----------------------------------------------------------------------- 491 /** 492 * Add an amount of time to the datetime. 493 * 494 * @param duration the millis to add 495 * @throws ArithmeticException if the result exceeds the capacity of the instant 496 */ 497 public void add(long duration) { 498 setMillis(FieldUtils.safeAdd(getMillis(), duration)); // set via this class not super 499 } 500 501 /** 502 * Adds a duration to this instant. 503 * <p> 504 * This will typically change the value of most fields. 505 * 506 * @param duration the duration to add, null means add zero 507 * @throws ArithmeticException if the result exceeds the capacity of the instant 508 */ 509 public void add(ReadableDuration duration) { 510 add(duration, 1); 511 } 512 513 /** 514 * Adds a duration to this instant specifying how many times to add. 515 * <p> 516 * This will typically change the value of most fields. 517 * 518 * @param duration the duration to add, null means add zero 519 * @param scalar direction and amount to add, which may be negative 520 * @throws ArithmeticException if the result exceeds the capacity of the instant 521 */ 522 public void add(ReadableDuration duration, int scalar) { 523 if (duration != null) { 524 add(FieldUtils.safeMultiply(duration.getMillis(), scalar)); 525 } 526 } 527 528 /** 529 * Adds a period to this instant. 530 * <p> 531 * This will typically change the value of most fields. 532 * 533 * @param period the period to add, null means add zero 534 * @throws ArithmeticException if the result exceeds the capacity of the instant 535 */ 536 public void add(ReadablePeriod period) { 537 add(period, 1); 538 } 539 540 /** 541 * Adds a period to this instant specifying how many times to add. 542 * <p> 543 * This will typically change the value of most fields. 544 * 545 * @param period the period to add, null means add zero 546 * @param scalar direction and amount to add, which may be negative 547 * @throws ArithmeticException if the result exceeds the capacity of the instant 548 */ 549 public void add(ReadablePeriod period, int scalar) { 550 if (period != null) { 551 setMillis(getChronology().add(period, getMillis(), scalar)); // set via this class not super 552 } 553 } 554 555 //----------------------------------------------------------------------- 556 /** 557 * Set the chronology of the datetime. 558 * <p> 559 * All changes to the chronology occur via this method. 560 * 561 * @param chronology the chronology to use, null means ISOChronology in default zone 562 */ 563 public void setChronology(Chronology chronology) { 564 super.setChronology(chronology); 565 } 566 567 //----------------------------------------------------------------------- 568 /** 569 * Sets the time zone of the datetime, changing the chronology and field values. 570 * <p> 571 * Changing the zone using this method retains the millisecond instant. 572 * The millisecond instant is adjusted in the new zone to compensate. 573 * 574 * chronology. Setting the time zone does not affect the millisecond value 575 * of this instant. 576 * <p> 577 * If the chronology already has this time zone, no change occurs. 578 * 579 * @param newZone the time zone to use, null means default zone 580 * @see #setZoneRetainFields 581 */ 582 public void setZone(DateTimeZone newZone) { 583 newZone = DateTimeUtils.getZone(newZone); 584 Chronology chrono = getChronology(); 585 if (chrono.getZone() != newZone) { 586 setChronology(chrono.withZone(newZone)); // set via this class not super 587 } 588 } 589 590 /** 591 * Sets the time zone of the datetime, changing the chronology and millisecond. 592 * <p> 593 * Changing the zone using this method retains the field values. 594 * The millisecond instant is adjusted in the new zone to compensate. 595 * <p> 596 * If the chronology already has this time zone, no change occurs. 597 * 598 * @param newZone the time zone to use, null means default zone 599 * @see #setZone 600 */ 601 public void setZoneRetainFields(DateTimeZone newZone) { 602 newZone = DateTimeUtils.getZone(newZone); 603 DateTimeZone originalZone = DateTimeUtils.getZone(getZone()); 604 if (newZone == originalZone) { 605 return; 606 } 607 608 long millis = originalZone.getMillisKeepLocal(newZone, getMillis()); 609 setChronology(getChronology().withZone(newZone)); // set via this class not super 610 setMillis(millis); 611 } 612 613 //----------------------------------------------------------------------- 614 /** 615 * Sets the value of one of the fields of the instant, such as hourOfDay. 616 * 617 * @param type a field type, usually obtained from DateTimeFieldType, not null 618 * @param value the value to set the field to 619 * @throws IllegalArgumentException if the value is null or invalid 620 */ 621 public void set(DateTimeFieldType type, int value) { 622 if (type == null) { 623 throw new IllegalArgumentException("Field must not be null"); 624 } 625 setMillis(type.getField(getChronology()).set(getMillis(), value)); 626 } 627 628 /** 629 * Adds to the instant specifying the duration and multiple to add. 630 * 631 * @param type a field type, usually obtained from DateTimeFieldType, not null 632 * @param amount the amount to add of this duration 633 * @throws IllegalArgumentException if the value is null or invalid 634 * @throws ArithmeticException if the result exceeds the capacity of the instant 635 */ 636 public void add(DurationFieldType type, int amount) { 637 if (type == null) { 638 throw new IllegalArgumentException("Field must not be null"); 639 } 640 setMillis(type.getField(getChronology()).add(getMillis(), amount)); 641 } 642 643 //----------------------------------------------------------------------- 644 /** 645 * Set the year to the specified value. 646 * 647 * @param year the year 648 * @throws IllegalArgumentException if the value is invalid 649 */ 650 public void setYear(final int year) { 651 setMillis(getChronology().year().set(getMillis(), year)); 652 } 653 654 /** 655 * Add a number of years to the date. 656 * 657 * @param years the years to add 658 * @throws IllegalArgumentException if the value is invalid 659 */ 660 public void addYears(final int years) { 661 setMillis(getChronology().years().add(getMillis(), years)); 662 } 663 664 //----------------------------------------------------------------------- 665 /** 666 * Set the weekyear to the specified value. 667 * 668 * @param weekyear the weekyear 669 * @throws IllegalArgumentException if the value is invalid 670 */ 671 public void setWeekyear(final int weekyear) { 672 setMillis(getChronology().weekyear().set(getMillis(), weekyear)); 673 } 674 675 /** 676 * Add a number of weekyears to the date. 677 * 678 * @param weekyears the weekyears to add 679 * @throws IllegalArgumentException if the value is invalid 680 */ 681 public void addWeekyears(final int weekyears) { 682 setMillis(getChronology().weekyears().add(getMillis(), weekyears)); 683 } 684 685 //----------------------------------------------------------------------- 686 /** 687 * Set the month of the year to the specified value. 688 * 689 * @param monthOfYear the month of the year 690 * @throws IllegalArgumentException if the value is invalid 691 */ 692 public void setMonthOfYear(final int monthOfYear) { 693 setMillis(getChronology().monthOfYear().set(getMillis(), monthOfYear)); 694 } 695 696 /** 697 * Add a number of months to the date. 698 * 699 * @param months the months to add 700 * @throws IllegalArgumentException if the value is invalid 701 */ 702 public void addMonths(final int months) { 703 setMillis(getChronology().months().add(getMillis(), months)); 704 } 705 706 //----------------------------------------------------------------------- 707 /** 708 * Set the week of weekyear to the specified value. 709 * 710 * @param weekOfWeekyear the week of the weekyear 711 * @throws IllegalArgumentException if the value is invalid 712 */ 713 public void setWeekOfWeekyear(final int weekOfWeekyear) { 714 setMillis(getChronology().weekOfWeekyear().set(getMillis(), weekOfWeekyear)); 715 } 716 717 /** 718 * Add a number of weeks to the date. 719 * 720 * @param weeks the weeks to add 721 * @throws IllegalArgumentException if the value is invalid 722 */ 723 public void addWeeks(final int weeks) { 724 setMillis(getChronology().weeks().add(getMillis(), weeks)); 725 } 726 727 //----------------------------------------------------------------------- 728 /** 729 * Set the day of year to the specified value. 730 * 731 * @param dayOfYear the day of the year 732 * @throws IllegalArgumentException if the value is invalid 733 */ 734 public void setDayOfYear(final int dayOfYear) { 735 setMillis(getChronology().dayOfYear().set(getMillis(), dayOfYear)); 736 } 737 738 /** 739 * Set the day of the month to the specified value. 740 * 741 * @param dayOfMonth the day of the month 742 * @throws IllegalArgumentException if the value is invalid 743 */ 744 public void setDayOfMonth(final int dayOfMonth) { 745 setMillis(getChronology().dayOfMonth().set(getMillis(), dayOfMonth)); 746 } 747 748 /** 749 * Set the day of week to the specified value. 750 * 751 * @param dayOfWeek the day of the week 752 * @throws IllegalArgumentException if the value is invalid 753 */ 754 public void setDayOfWeek(final int dayOfWeek) { 755 setMillis(getChronology().dayOfWeek().set(getMillis(), dayOfWeek)); 756 } 757 758 /** 759 * Add a number of days to the date. 760 * 761 * @param days the days to add 762 * @throws IllegalArgumentException if the value is invalid 763 */ 764 public void addDays(final int days) { 765 setMillis(getChronology().days().add(getMillis(), days)); 766 } 767 768 //----------------------------------------------------------------------- 769 /** 770 * Set the hour of the day to the specified value. 771 * 772 * @param hourOfDay the hour of day 773 * @throws IllegalArgumentException if the value is invalid 774 */ 775 public void setHourOfDay(final int hourOfDay) { 776 setMillis(getChronology().hourOfDay().set(getMillis(), hourOfDay)); 777 } 778 779 /** 780 * Add a number of hours to the date. 781 * 782 * @param hours the hours to add 783 * @throws IllegalArgumentException if the value is invalid 784 */ 785 public void addHours(final int hours) { 786 setMillis(getChronology().hours().add(getMillis(), hours)); 787 } 788 789 //----------------------------------------------------------------------- 790 /** 791 * Set the minute of the day to the specified value. 792 * 793 * @param minuteOfDay the minute of day 794 * @throws IllegalArgumentException if the value is invalid 795 */ 796 public void setMinuteOfDay(final int minuteOfDay) { 797 setMillis(getChronology().minuteOfDay().set(getMillis(), minuteOfDay)); 798 } 799 800 /** 801 * Set the minute of the hour to the specified value. 802 * 803 * @param minuteOfHour the minute of hour 804 * @throws IllegalArgumentException if the value is invalid 805 */ 806 public void setMinuteOfHour(final int minuteOfHour) { 807 setMillis(getChronology().minuteOfHour().set(getMillis(), minuteOfHour)); 808 } 809 810 /** 811 * Add a number of minutes to the date. 812 * 813 * @param minutes the minutes to add 814 * @throws IllegalArgumentException if the value is invalid 815 */ 816 public void addMinutes(final int minutes) { 817 setMillis(getChronology().minutes().add(getMillis(), minutes)); 818 } 819 820 //----------------------------------------------------------------------- 821 /** 822 * Set the second of the day to the specified value. 823 * 824 * @param secondOfDay the second of day 825 * @throws IllegalArgumentException if the value is invalid 826 */ 827 public void setSecondOfDay(final int secondOfDay) { 828 setMillis(getChronology().secondOfDay().set(getMillis(), secondOfDay)); 829 } 830 831 /** 832 * Set the second of the minute to the specified value. 833 * 834 * @param secondOfMinute the second of minute 835 * @throws IllegalArgumentException if the value is invalid 836 */ 837 public void setSecondOfMinute(final int secondOfMinute) { 838 setMillis(getChronology().secondOfMinute().set(getMillis(), secondOfMinute)); 839 } 840 841 /** 842 * Add a number of seconds to the date. 843 * 844 * @param seconds the seconds to add 845 * @throws IllegalArgumentException if the value is invalid 846 */ 847 public void addSeconds(final int seconds) { 848 setMillis(getChronology().seconds().add(getMillis(), seconds)); 849 } 850 851 //----------------------------------------------------------------------- 852 /** 853 * Set the millis of the day to the specified value. 854 * 855 * @param millisOfDay the millis of day 856 * @throws IllegalArgumentException if the value is invalid 857 */ 858 public void setMillisOfDay(final int millisOfDay) { 859 setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay)); 860 } 861 862 /** 863 * Set the millis of the second to the specified value. 864 * 865 * @param millisOfSecond the millis of second 866 * @throws IllegalArgumentException if the value is invalid 867 */ 868 public void setMillisOfSecond(final int millisOfSecond) { 869 setMillis(getChronology().millisOfSecond().set(getMillis(), millisOfSecond)); 870 } 871 872 /** 873 * Add a number of milliseconds to the date. The implementation of this 874 * method differs from the {@link #add(long)} method in that a 875 * DateTimeField performs the addition. 876 * 877 * @param millis the milliseconds to add 878 * @throws IllegalArgumentException if the value is invalid 879 */ 880 public void addMillis(final int millis) { 881 setMillis(getChronology().millis().add(getMillis(), millis)); 882 } 883 884 //----------------------------------------------------------------------- 885 /** 886 * Set the date from milliseconds. 887 * The time part of this object will be unaffected. 888 * 889 * @param instant an instant to copy the date from, time part ignored 890 * @throws IllegalArgumentException if the value is invalid 891 */ 892 public void setDate(final long instant) { 893 setMillis(getChronology().millisOfDay().set(instant, getMillisOfDay())); 894 } 895 896 /** 897 * Set the date from another instant. 898 * The time part of this object will be unaffected. 899 * <p> 900 * If the input is a {@code ReadableDateTime} then it is converted to the 901 * same time-zone as this object before using the instant millis. 902 * 903 * @param instant an instant to copy the date from, time part ignored 904 * @throws IllegalArgumentException if the object is invalid 905 */ 906 public void setDate(final ReadableInstant instant) { 907 long instantMillis = DateTimeUtils.getInstantMillis(instant); 908 if (instant instanceof ReadableDateTime) { 909 ReadableDateTime rdt = (ReadableDateTime) instant; 910 Chronology instantChrono = DateTimeUtils.getChronology(rdt.getChronology()); 911 DateTimeZone zone = instantChrono.getZone(); 912 if (zone != null) { 913 instantMillis = zone.getMillisKeepLocal(getZone(), instantMillis); 914 } 915 } 916 setDate(instantMillis); 917 } 918 919 /** 920 * Set the date from fields. 921 * The time part of this object will be unaffected. 922 * 923 * @param year the year 924 * @param monthOfYear the month of the year 925 * @param dayOfMonth the day of the month 926 * @throws IllegalArgumentException if the value is invalid 927 */ 928 public void setDate( 929 final int year, 930 final int monthOfYear, 931 final int dayOfMonth) { 932 Chronology c = getChronology(); 933 long instantMidnight = c.getDateTimeMillis(year, monthOfYear, dayOfMonth, 0); 934 setDate(instantMidnight); 935 } 936 937 //----------------------------------------------------------------------- 938 /** 939 * Set the time from milliseconds. 940 * The date part of this object will be unaffected. 941 * 942 * @param millis an instant to copy the time from, date part ignored 943 * @throws IllegalArgumentException if the value is invalid 944 */ 945 public void setTime(final long millis) { 946 int millisOfDay = ISOChronology.getInstanceUTC().millisOfDay().get(millis); 947 setMillis(getChronology().millisOfDay().set(getMillis(), millisOfDay)); 948 } 949 950 /** 951 * Set the time from another instant. 952 * The date part of this object will be unaffected. 953 * 954 * @param instant an instant to copy the time from, date part ignored 955 * @throws IllegalArgumentException if the object is invalid 956 */ 957 public void setTime(final ReadableInstant instant) { 958 long instantMillis = DateTimeUtils.getInstantMillis(instant); 959 Chronology instantChrono = DateTimeUtils.getInstantChronology(instant); 960 DateTimeZone zone = instantChrono.getZone(); 961 if (zone != null) { 962 instantMillis = zone.getMillisKeepLocal(DateTimeZone.UTC, instantMillis); 963 } 964 setTime(instantMillis); 965 } 966 967 /** 968 * Set the time from fields. 969 * The date part of this object will be unaffected. 970 * 971 * @param hour the hour 972 * @param minuteOfHour the minute of the hour 973 * @param secondOfMinute the second of the minute 974 * @param millisOfSecond the millisecond of the second 975 * @throws IllegalArgumentException if the value is invalid 976 */ 977 public void setTime( 978 final int hour, 979 final int minuteOfHour, 980 final int secondOfMinute, 981 final int millisOfSecond) { 982 long instant = getChronology().getDateTimeMillis( 983 getMillis(), hour, minuteOfHour, secondOfMinute, millisOfSecond); 984 setMillis(instant); 985 } 986 987 /** 988 * Set the date and time from fields. 989 * 990 * @param year the year 991 * @param monthOfYear the month of the year 992 * @param dayOfMonth the day of the month 993 * @param hourOfDay the hour of the day 994 * @param minuteOfHour the minute of the hour 995 * @param secondOfMinute the second of the minute 996 * @param millisOfSecond the millisecond of the second 997 * @throws IllegalArgumentException if the value is invalid 998 */ 999 public void setDateTime( 1000 final int year, 1001 final int monthOfYear, 1002 final int dayOfMonth, 1003 final int hourOfDay, 1004 final int minuteOfHour, 1005 final int secondOfMinute, 1006 final int millisOfSecond) { 1007 long instant = getChronology().getDateTimeMillis( 1008 year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); 1009 setMillis(instant); 1010 } 1011 1012 //----------------------------------------------------------------------- 1013 /** 1014 * Gets the property object for the specified type, which contains many useful methods. 1015 * 1016 * @param type the field type to get the chronology for 1017 * @return the property object 1018 * @throws IllegalArgumentException if the field is null or unsupported 1019 * @since 1.2 1020 */ 1021 public Property property(DateTimeFieldType type) { 1022 if (type == null) { 1023 throw new IllegalArgumentException("The DateTimeFieldType must not be null"); 1024 } 1025 DateTimeField field = type.getField(getChronology()); 1026 if (field.isSupported() == false) { 1027 throw new IllegalArgumentException("Field '" + type + "' is not supported"); 1028 } 1029 return new Property(this, field); 1030 } 1031 1032 /** 1033 * Get the era property. 1034 * 1035 * @return the era property 1036 */ 1037 public Property era() { 1038 return new Property(this, getChronology().era()); 1039 } 1040 1041 /** 1042 * Get the century of era property. 1043 * 1044 * @return the year of era property 1045 */ 1046 public Property centuryOfEra() { 1047 return new Property(this, getChronology().centuryOfEra()); 1048 } 1049 1050 /** 1051 * Get the year of century property. 1052 * 1053 * @return the year of era property 1054 */ 1055 public Property yearOfCentury() { 1056 return new Property(this, getChronology().yearOfCentury()); 1057 } 1058 1059 /** 1060 * Get the year of era property. 1061 * 1062 * @return the year of era property 1063 */ 1064 public Property yearOfEra() { 1065 return new Property(this, getChronology().yearOfEra()); 1066 } 1067 1068 /** 1069 * Get the year property. 1070 * 1071 * @return the year property 1072 */ 1073 public Property year() { 1074 return new Property(this, getChronology().year()); 1075 } 1076 1077 /** 1078 * Get the year of a week based year property. 1079 * 1080 * @return the year of a week based year property 1081 */ 1082 public Property weekyear() { 1083 return new Property(this, getChronology().weekyear()); 1084 } 1085 1086 /** 1087 * Get the month of year property. 1088 * 1089 * @return the month of year property 1090 */ 1091 public Property monthOfYear() { 1092 return new Property(this, getChronology().monthOfYear()); 1093 } 1094 1095 /** 1096 * Get the week of a week based year property. 1097 * 1098 * @return the week of a week based year property 1099 */ 1100 public Property weekOfWeekyear() { 1101 return new Property(this, getChronology().weekOfWeekyear()); 1102 } 1103 1104 /** 1105 * Get the day of year property. 1106 * 1107 * @return the day of year property 1108 */ 1109 public Property dayOfYear() { 1110 return new Property(this, getChronology().dayOfYear()); 1111 } 1112 1113 /** 1114 * Get the day of month property. 1115 * <p> 1116 * The values for day of month are defined in {@link DateTimeConstants}. 1117 * 1118 * @return the day of month property 1119 */ 1120 public Property dayOfMonth() { 1121 return new Property(this, getChronology().dayOfMonth()); 1122 } 1123 1124 /** 1125 * Get the day of week property. 1126 * <p> 1127 * The values for day of week are defined in {@link DateTimeConstants}. 1128 * 1129 * @return the day of week property 1130 */ 1131 public Property dayOfWeek() { 1132 return new Property(this, getChronology().dayOfWeek()); 1133 } 1134 1135 //----------------------------------------------------------------------- 1136 /** 1137 * Get the hour of day field property 1138 * 1139 * @return the hour of day property 1140 */ 1141 public Property hourOfDay() { 1142 return new Property(this, getChronology().hourOfDay()); 1143 } 1144 1145 /** 1146 * Get the minute of day property 1147 * 1148 * @return the minute of day property 1149 */ 1150 public Property minuteOfDay() { 1151 return new Property(this, getChronology().minuteOfDay()); 1152 } 1153 1154 /** 1155 * Get the minute of hour field property 1156 * 1157 * @return the minute of hour property 1158 */ 1159 public Property minuteOfHour() { 1160 return new Property(this, getChronology().minuteOfHour()); 1161 } 1162 1163 /** 1164 * Get the second of day property 1165 * 1166 * @return the second of day property 1167 */ 1168 public Property secondOfDay() { 1169 return new Property(this, getChronology().secondOfDay()); 1170 } 1171 1172 /** 1173 * Get the second of minute field property 1174 * 1175 * @return the second of minute property 1176 */ 1177 public Property secondOfMinute() { 1178 return new Property(this, getChronology().secondOfMinute()); 1179 } 1180 1181 /** 1182 * Get the millis of day property 1183 * 1184 * @return the millis of day property 1185 */ 1186 public Property millisOfDay() { 1187 return new Property(this, getChronology().millisOfDay()); 1188 } 1189 1190 /** 1191 * Get the millis of second property 1192 * 1193 * @return the millis of second property 1194 */ 1195 public Property millisOfSecond() { 1196 return new Property(this, getChronology().millisOfSecond()); 1197 } 1198 1199 //----------------------------------------------------------------------- 1200 /** 1201 * Clone this object without having to cast the returned object. 1202 * 1203 * @return a clone of the this object. 1204 */ 1205 public MutableDateTime copy() { 1206 return (MutableDateTime) clone(); 1207 } 1208 1209 //----------------------------------------------------------------------- 1210 /** 1211 * Clone this object. 1212 * 1213 * @return a clone of this object. 1214 */ 1215 public Object clone() { 1216 try { 1217 return super.clone(); 1218 } catch (CloneNotSupportedException ex) { 1219 throw new InternalError("Clone error"); 1220 } 1221 } 1222 1223 /** 1224 * Output the date time in ISO8601 format (yyyy-MM-ddTHH:mm:ss.SSSZZ). 1225 * 1226 * @return ISO8601 time formatted string. 1227 */ 1228 @ToString 1229 public String toString() { 1230 return ISODateTimeFormat.dateTime().print(this); 1231 } 1232 1233 /** 1234 * MutableDateTime.Property binds a MutableDateTime to a 1235 * DateTimeField allowing powerful datetime functionality to be easily 1236 * accessed. 1237 * <p> 1238 * The example below shows how to use the property to change the value of a 1239 * MutableDateTime object. 1240 * <pre> 1241 * MutableDateTime dt = new MutableDateTime(1972, 12, 3, 13, 32, 19, 123); 1242 * dt.year().add(20); 1243 * dt.second().roundFloor().minute().set(10); 1244 * </pre> 1245 * <p> 1246 * MutableDateTime.Propery itself is thread-safe and immutable, but the 1247 * MutableDateTime being operated on is not. 1248 * 1249 * @author Stephen Colebourne 1250 * @author Brian S O'Neill 1251 * @since 1.0 1252 */ 1253 public static final class Property extends AbstractReadableInstantFieldProperty { 1254 1255 /** Serialization version */ 1256 private static final long serialVersionUID = -4481126543819298617L; 1257 1258 /** The instant this property is working against */ 1259 private MutableDateTime iInstant; 1260 /** The field this property is working against */ 1261 private DateTimeField iField; 1262 1263 /** 1264 * Constructor. 1265 * 1266 * @param instant the instant to set 1267 * @param field the field to use 1268 */ 1269 Property(MutableDateTime instant, DateTimeField field) { 1270 super(); 1271 iInstant = instant; 1272 iField = field; 1273 } 1274 1275 /** 1276 * Writes the property in a safe serialization format. 1277 */ 1278 private void writeObject(ObjectOutputStream oos) throws IOException { 1279 oos.writeObject(iInstant); 1280 oos.writeObject(iField.getType()); 1281 } 1282 1283 /** 1284 * Reads the property from a safe serialization format. 1285 */ 1286 private void readObject(ObjectInputStream oos) throws IOException, ClassNotFoundException { 1287 iInstant = (MutableDateTime) oos.readObject(); 1288 DateTimeFieldType type = (DateTimeFieldType) oos.readObject(); 1289 iField = type.getField(iInstant.getChronology()); 1290 } 1291 1292 //----------------------------------------------------------------------- 1293 /** 1294 * Gets the field being used. 1295 * 1296 * @return the field 1297 */ 1298 public DateTimeField getField() { 1299 return iField; 1300 } 1301 1302 /** 1303 * Gets the milliseconds of the datetime that this property is linked to. 1304 * 1305 * @return the milliseconds 1306 */ 1307 protected long getMillis() { 1308 return iInstant.getMillis(); 1309 } 1310 1311 /** 1312 * Gets the chronology of the datetime that this property is linked to. 1313 * 1314 * @return the chronology 1315 * @since 1.4 1316 */ 1317 protected Chronology getChronology() { 1318 return iInstant.getChronology(); 1319 } 1320 1321 /** 1322 * Gets the mutable datetime being used. 1323 * 1324 * @return the mutable datetime 1325 */ 1326 public MutableDateTime getMutableDateTime() { 1327 return iInstant; 1328 } 1329 1330 //----------------------------------------------------------------------- 1331 /** 1332 * Adds a value to the millis value. 1333 * 1334 * @param value the value to add 1335 * @return the mutable datetime being used, so calls can be chained 1336 * @see DateTimeField#add(long,int) 1337 */ 1338 public MutableDateTime add(int value) { 1339 iInstant.setMillis(getField().add(iInstant.getMillis(), value)); 1340 return iInstant; 1341 } 1342 1343 /** 1344 * Adds a value to the millis value. 1345 * 1346 * @param value the value to add 1347 * @return the mutable datetime being used, so calls can be chained 1348 * @see DateTimeField#add(long,long) 1349 */ 1350 public MutableDateTime add(long value) { 1351 iInstant.setMillis(getField().add(iInstant.getMillis(), value)); 1352 return iInstant; 1353 } 1354 1355 /** 1356 * Adds a value, possibly wrapped, to the millis value. 1357 * 1358 * @param value the value to add 1359 * @return the mutable datetime being used, so calls can be chained 1360 * @see DateTimeField#addWrapField 1361 */ 1362 public MutableDateTime addWrapField(int value) { 1363 iInstant.setMillis(getField().addWrapField(iInstant.getMillis(), value)); 1364 return iInstant; 1365 } 1366 1367 //----------------------------------------------------------------------- 1368 /** 1369 * Sets a value. 1370 * 1371 * @param value the value to set. 1372 * @return the mutable datetime being used, so calls can be chained 1373 * @see DateTimeField#set(long,int) 1374 */ 1375 public MutableDateTime set(int value) { 1376 iInstant.setMillis(getField().set(iInstant.getMillis(), value)); 1377 return iInstant; 1378 } 1379 1380 /** 1381 * Sets a text value. 1382 * 1383 * @param text the text value to set 1384 * @param locale optional locale to use for selecting a text symbol 1385 * @return the mutable datetime being used, so calls can be chained 1386 * @throws IllegalArgumentException if the text value isn't valid 1387 * @see DateTimeField#set(long,java.lang.String,java.util.Locale) 1388 */ 1389 public MutableDateTime set(String text, Locale locale) { 1390 iInstant.setMillis(getField().set(iInstant.getMillis(), text, locale)); 1391 return iInstant; 1392 } 1393 1394 /** 1395 * Sets a text value. 1396 * 1397 * @param text the text value to set 1398 * @return the mutable datetime being used, so calls can be chained 1399 * @throws IllegalArgumentException if the text value isn't valid 1400 * @see DateTimeField#set(long,java.lang.String) 1401 */ 1402 public MutableDateTime set(String text) { 1403 set(text, null); 1404 return iInstant; 1405 } 1406 1407 //----------------------------------------------------------------------- 1408 /** 1409 * Round to the lowest whole unit of this field. 1410 * 1411 * @return the mutable datetime being used, so calls can be chained 1412 * @see DateTimeField#roundFloor 1413 */ 1414 public MutableDateTime roundFloor() { 1415 iInstant.setMillis(getField().roundFloor(iInstant.getMillis())); 1416 return iInstant; 1417 } 1418 1419 /** 1420 * Round to the highest whole unit of this field. 1421 * 1422 * @return the mutable datetime being used, so calls can be chained 1423 * @see DateTimeField#roundCeiling 1424 */ 1425 public MutableDateTime roundCeiling() { 1426 iInstant.setMillis(getField().roundCeiling(iInstant.getMillis())); 1427 return iInstant; 1428 } 1429 1430 /** 1431 * Round to the nearest whole unit of this field, favoring the floor if 1432 * halfway. 1433 * 1434 * @return the mutable datetime being used, so calls can be chained 1435 * @see DateTimeField#roundHalfFloor 1436 */ 1437 public MutableDateTime roundHalfFloor() { 1438 iInstant.setMillis(getField().roundHalfFloor(iInstant.getMillis())); 1439 return iInstant; 1440 } 1441 1442 /** 1443 * Round to the nearest whole unit of this field, favoring the ceiling if 1444 * halfway. 1445 * 1446 * @return the mutable datetime being used, so calls can be chained 1447 * @see DateTimeField#roundHalfCeiling 1448 */ 1449 public MutableDateTime roundHalfCeiling() { 1450 iInstant.setMillis(getField().roundHalfCeiling(iInstant.getMillis())); 1451 return iInstant; 1452 } 1453 1454 /** 1455 * Round to the nearest whole unit of this field. If halfway, the ceiling 1456 * is favored over the floor only if it makes this field's value even. 1457 * 1458 * @return the mutable datetime being used, so calls can be chained 1459 * @see DateTimeField#roundHalfEven 1460 */ 1461 public MutableDateTime roundHalfEven() { 1462 iInstant.setMillis(getField().roundHalfEven(iInstant.getMillis())); 1463 return iInstant; 1464 } 1465 } 1466 1467 }