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