001 /*
002 * Copyright 2001-2006 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.Serializable;
019 import java.util.Calendar;
020 import java.util.Date;
021 import java.util.Locale;
022
023 import org.joda.time.base.BasePartial;
024 import org.joda.time.chrono.ISOChronology;
025 import org.joda.time.field.AbstractPartialFieldProperty;
026 import org.joda.time.field.FieldUtils;
027 import org.joda.time.format.ISODateTimeFormat;
028
029 /**
030 * TimeOfDay is an immutable partial supporting the hour, minute, second
031 * and millisecond fields.
032 * <p>
033 * NOTE: This class only supports the four fields listed above. Thus, you
034 * cannot query the millisOfDay or secondOfDay fields for example.
035 * The new <code>LocalTime</code> class removes this restriction.
036 * <p>
037 * Calculations on TimeOfDay are performed using a {@link Chronology}.
038 * This chronology is set to be in the UTC time zone for all calculations.
039 * <p>
040 * Each individual field can be queried in two ways:
041 * <ul>
042 * <li><code>getHourOfDay()</code>
043 * <li><code>hourOfDay().get()</code>
044 * </ul>
045 * The second technique also provides access to other useful methods on the
046 * field:
047 * <ul>
048 * <li>numeric value - <code>hourOfDay().get()</code>
049 * <li>text value - <code>hourOfDay().getAsText()</code>
050 * <li>short text value - <code>hourOfDay().getAsShortText()</code>
051 * <li>maximum/minimum values - <code>hourOfDay().getMaximumValue()</code>
052 * <li>add/subtract - <code>hourOfDay().addToCopy()</code>
053 * <li>set - <code>hourOfDay().setCopy()</code>
054 * </ul>
055 * <p>
056 * TimeOfDay is thread-safe and immutable, provided that the Chronology is as well.
057 * All standard Chronology classes supplied are thread-safe and immutable.
058 *
059 * @author Stephen Colebourne
060 * @author Brian S O'Neill
061 * @since 1.0
062 * @deprecated Use LocalTime which has a much better internal implementation and
063 * has been available since 1.3
064 */
065 public final class TimeOfDay
066 extends BasePartial
067 implements ReadablePartial, Serializable {
068 // NOTE: No toDateTime(YearMonthDay) as semantics are confusing when
069 // different chronologies
070
071 /** Serialization version */
072 private static final long serialVersionUID = 3633353405803318660L;
073 /** The singleton set of field types */
074 private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] {
075 DateTimeFieldType.hourOfDay(),
076 DateTimeFieldType.minuteOfHour(),
077 DateTimeFieldType.secondOfMinute(),
078 DateTimeFieldType.millisOfSecond(),
079 };
080
081 /** Constant for midnight. */
082 public static final TimeOfDay MIDNIGHT = new TimeOfDay(0, 0, 0, 0);
083
084 /** The index of the hourOfDay field in the field array */
085 public static final int HOUR_OF_DAY = 0;
086 /** The index of the minuteOfHour field in the field array */
087 public static final int MINUTE_OF_HOUR = 1;
088 /** The index of the secondOfMinute field in the field array */
089 public static final int SECOND_OF_MINUTE = 2;
090 /** The index of the millisOfSecond field in the field array */
091 public static final int MILLIS_OF_SECOND = 3;
092
093 //-----------------------------------------------------------------------
094 /**
095 * Constructs a TimeOfDay from a <code>java.util.Calendar</code>
096 * using exactly the same field values avoiding any time zone effects.
097 * <p>
098 * Each field is queried from the Calendar and assigned to the TimeOfDay.
099 * This is useful to ensure that the field values are the same in the
100 * created TimeOfDay no matter what the time zone is. For example, if
101 * the Calendar states that the time is 04:29, then the created TimeOfDay
102 * will always have the time 04:29 irrespective of time zone issues.
103 * <p>
104 * This factory method ignores the type of the calendar and always
105 * creates a TimeOfDay with ISO chronology.
106 *
107 * @param calendar the Calendar to extract fields from
108 * @return the created TimeOfDay
109 * @throws IllegalArgumentException if the calendar is null
110 * @throws IllegalArgumentException if the time is invalid for the ISO chronology
111 * @since 1.2
112 */
113 public static TimeOfDay fromCalendarFields(Calendar calendar) {
114 if (calendar == null) {
115 throw new IllegalArgumentException("The calendar must not be null");
116 }
117 return new TimeOfDay(
118 calendar.get(Calendar.HOUR_OF_DAY),
119 calendar.get(Calendar.MINUTE),
120 calendar.get(Calendar.SECOND),
121 calendar.get(Calendar.MILLISECOND)
122 );
123 }
124
125 /**
126 * Constructs a TimeOfDay from a <code>java.util.Date</code>
127 * using exactly the same field values avoiding any time zone effects.
128 * <p>
129 * Each field is queried from the Date and assigned to the TimeOfDay.
130 * This is useful to ensure that the field values are the same in the
131 * created TimeOfDay no matter what the time zone is. For example, if
132 * the Calendar states that the time is 04:29, then the created TimeOfDay
133 * will always have the time 04:29 irrespective of time zone issues.
134 * <p>
135 * This factory method always creates a TimeOfDay with ISO chronology.
136 *
137 * @param date the Date to extract fields from
138 * @return the created TimeOfDay
139 * @throws IllegalArgumentException if the calendar is null
140 * @throws IllegalArgumentException if the date is invalid for the ISO chronology
141 * @since 1.2
142 */
143 public static TimeOfDay fromDateFields(Date date) {
144 if (date == null) {
145 throw new IllegalArgumentException("The date must not be null");
146 }
147 return new TimeOfDay(
148 date.getHours(),
149 date.getMinutes(),
150 date.getSeconds(),
151 (((int) (date.getTime() % 1000)) + 1000) % 1000
152 );
153 }
154
155 //-----------------------------------------------------------------------
156 /**
157 * Constructs a TimeOfDay from the specified millis of day using the
158 * ISO chronology.
159 * <p>
160 * The millisOfDay value may exceed the number of millis in one day,
161 * but additional days will be ignored.
162 * This method uses the UTC time zone internally.
163 *
164 * @param millisOfDay the number of milliseconds into a day to convert
165 */
166 public static TimeOfDay fromMillisOfDay(long millisOfDay) {
167 return fromMillisOfDay(millisOfDay, null);
168 }
169
170 /**
171 * Constructs a TimeOfDay from the specified millis of day using the
172 * specified chronology.
173 * <p>
174 * The millisOfDay value may exceed the number of millis in one day,
175 * but additional days will be ignored.
176 * This method uses the UTC time zone internally.
177 *
178 * @param millisOfDay the number of milliseconds into a day to convert
179 * @param chrono the chronology, null means ISO chronology
180 */
181 public static TimeOfDay fromMillisOfDay(long millisOfDay, Chronology chrono) {
182 chrono = DateTimeUtils.getChronology(chrono);
183 chrono = chrono.withUTC();
184 return new TimeOfDay(millisOfDay, chrono);
185 }
186
187 // Constructors
188 //-----------------------------------------------------------------------
189 /**
190 * Constructs a TimeOfDay with the current time, using ISOChronology in
191 * the default zone to extract the fields.
192 * <p>
193 * The constructor uses the default time zone, resulting in the local time
194 * being initialised. Once the constructor is complete, all further calculations
195 * are performed without reference to a timezone (by switching to UTC).
196 */
197 public TimeOfDay() {
198 super();
199 }
200
201 /**
202 * Constructs a TimeOfDay with the current time, using ISOChronology in
203 * the specified zone to extract the fields.
204 * <p>
205 * The constructor uses the specified time zone to obtain the current time.
206 * Once the constructor is complete, all further calculations
207 * are performed without reference to a timezone (by switching to UTC).
208 *
209 * @param zone the zone to use, null means default zone
210 * @since 1.1
211 */
212 public TimeOfDay(DateTimeZone zone) {
213 super(ISOChronology.getInstance(zone));
214 }
215
216 /**
217 * Constructs a TimeOfDay with the current time, using the specified chronology
218 * and zone to extract the fields.
219 * <p>
220 * The constructor uses the time zone of the chronology specified.
221 * Once the constructor is complete, all further calculations are performed
222 * without reference to a timezone (by switching to UTC).
223 *
224 * @param chronology the chronology, null means ISOChronology in the default zone
225 */
226 public TimeOfDay(Chronology chronology) {
227 super(chronology);
228 }
229
230 /**
231 * Constructs a TimeOfDay extracting the partial fields from the specified
232 * milliseconds using the ISOChronology in the default zone.
233 * <p>
234 * The constructor uses the default time zone, resulting in the local time
235 * being initialised. Once the constructor is complete, all further calculations
236 * are performed without reference to a timezone (by switching to UTC).
237 *
238 * @param instant the milliseconds from 1970-01-01T00:00:00Z
239 */
240 public TimeOfDay(long instant) {
241 super(instant);
242 }
243
244 /**
245 * Constructs a TimeOfDay extracting the partial fields from the specified
246 * milliseconds using the chronology provided.
247 * <p>
248 * The constructor uses the time zone of the chronology specified.
249 * Once the constructor is complete, all further calculations are performed
250 * without reference to a timezone (by switching to UTC).
251 *
252 * @param instant the milliseconds from 1970-01-01T00:00:00Z
253 * @param chronology the chronology, null means ISOChronology in the default zone
254 */
255 public TimeOfDay(long instant, Chronology chronology) {
256 super(instant, chronology);
257 }
258
259 /**
260 * Constructs a TimeOfDay from an Object that represents a time.
261 * <p>
262 * The recognised object types are defined in
263 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
264 * include ReadableInstant, String, Calendar and Date.
265 * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
266 * <p>
267 * The chronology used will be derived from the object, defaulting to ISO.
268 * <p>
269 * NOTE: Prior to v1.3 the string format was described by
270 * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
271 *
272 * @param instant the datetime object, null means now
273 * @throws IllegalArgumentException if the instant is invalid
274 */
275 public TimeOfDay(Object instant) {
276 super(instant, null, ISODateTimeFormat.timeParser());
277 }
278
279 /**
280 * Constructs a TimeOfDay from an Object that represents a time, using the
281 * specified chronology.
282 * <p>
283 * The recognised object types are defined in
284 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
285 * include ReadableInstant, String, Calendar and Date.
286 * The String formats are described by {@link ISODateTimeFormat#timeParser()}.
287 * <p>
288 * The constructor uses the time zone of the chronology specified.
289 * Once the constructor is complete, all further calculations are performed
290 * without reference to a timezone (by switching to UTC).
291 * The specified chronology overrides that of the object.
292 * <p>
293 * NOTE: Prior to v1.3 the string format was described by
294 * {@link ISODateTimeFormat#dateTimeParser()}. Dates are now rejected.
295 *
296 * @param instant the datetime object, null means now
297 * @param chronology the chronology, null means ISO default
298 * @throws IllegalArgumentException if the instant is invalid
299 */
300 public TimeOfDay(Object instant, Chronology chronology) {
301 super(instant, DateTimeUtils.getChronology(chronology), ISODateTimeFormat.timeParser());
302 }
303
304 /**
305 * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds
306 * using <code>ISOChronology</code> in the default zone.
307 * <p>
308 * The constructor uses the no time zone initialising the fields as provided.
309 * Once the constructor is complete, all further calculations
310 * are performed without reference to a timezone (by switching to UTC).
311 *
312 * @param hourOfDay the hour of the day
313 * @param minuteOfHour the minute of the hour
314 */
315 public TimeOfDay(int hourOfDay, int minuteOfHour) {
316 this(hourOfDay, minuteOfHour, 0, 0, null);
317 }
318
319 /**
320 * Constructs a TimeOfDay with specified hour and minute and zero seconds and milliseconds.
321 * <p>
322 * The constructor uses the time zone of the chronology specified.
323 * Once the constructor is complete, all further calculations are performed
324 * without reference to a timezone (by switching to UTC).
325 *
326 * @param hourOfDay the hour of the day
327 * @param minuteOfHour the minute of the hour
328 * @param chronology the chronology, null means ISOChronology in the default zone
329 */
330 public TimeOfDay(int hourOfDay, int minuteOfHour, Chronology chronology) {
331 this(hourOfDay, minuteOfHour, 0, 0, chronology);
332 }
333
334 /**
335 * Constructs a TimeOfDay with specified time field values and zero milliseconds
336 * using <code>ISOChronology</code> in the default zone.
337 * <p>
338 * The constructor uses the no time zone initialising the fields as provided.
339 * Once the constructor is complete, all further calculations
340 * are performed without reference to a timezone (by switching to UTC).
341 *
342 * @param hourOfDay the hour of the day
343 * @param minuteOfHour the minute of the hour
344 * @param secondOfMinute the second of the minute
345 */
346 public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute) {
347 this(hourOfDay, minuteOfHour, secondOfMinute, 0, null);
348 }
349
350 /**
351 * Constructs a TimeOfDay with specified time field values and zero milliseconds.
352 * <p>
353 * The constructor uses the time zone of the chronology specified.
354 * Once the constructor is complete, all further calculations are performed
355 * without reference to a timezone (by switching to UTC).
356 *
357 * @param hourOfDay the hour of the day
358 * @param minuteOfHour the minute of the hour
359 * @param secondOfMinute the second of the minute
360 * @param chronology the chronology, null means ISOChronology in the default zone
361 */
362 public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute, Chronology chronology) {
363 this(hourOfDay, minuteOfHour, secondOfMinute, 0, chronology);
364 }
365
366 /**
367 * Constructs a TimeOfDay with specified time field values using
368 * <code>ISOChronology</code> in the default zone.
369 * <p>
370 * The constructor uses the no time zone initialising the fields as provided.
371 * Once the constructor is complete, all further calculations
372 * are performed without reference to a timezone (by switching to UTC).
373 *
374 * @param hourOfDay the hour of the day
375 * @param minuteOfHour the minute of the hour
376 * @param secondOfMinute the second of the minute
377 * @param millisOfSecond the millisecond of the second
378 */
379 public TimeOfDay(int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond) {
380 this(hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, null);
381 }
382
383 /**
384 * Constructs a TimeOfDay with specified time field values and chronology.
385 * <p>
386 * The constructor uses the time zone of the chronology specified.
387 * Once the constructor is complete, all further calculations are performed
388 * without reference to a timezone (by switching to UTC).
389 *
390 * @param hourOfDay the hour of the day
391 * @param minuteOfHour the minute of the hour
392 * @param secondOfMinute the second of the minute
393 * @param millisOfSecond the millisecond of the second
394 * @param chronology the chronology, null means ISOChronology in the default zone
395 */
396 public TimeOfDay(int hourOfDay, int minuteOfHour,
397 int secondOfMinute, int millisOfSecond, Chronology chronology) {
398 super(new int[] {hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond}, chronology);
399 }
400
401 /**
402 * Constructs a TimeOfDay with chronology from this instance and new values.
403 *
404 * @param partial the partial to base this new instance on
405 * @param values the new set of values
406 */
407 TimeOfDay(TimeOfDay partial, int[] values) {
408 super(partial, values);
409 }
410
411 /**
412 * Constructs a TimeOfDay with values from this instance and a new chronology.
413 *
414 * @param partial the partial to base this new instance on
415 * @param chrono the new chronology
416 */
417 TimeOfDay(TimeOfDay partial, Chronology chrono) {
418 super(partial, chrono);
419 }
420
421 //-----------------------------------------------------------------------
422 /**
423 * Gets the number of fields in this partial.
424 *
425 * @return the field count
426 */
427 public int size() {
428 return 4;
429 }
430
431 /**
432 * Gets the field for a specific index in the chronology specified.
433 * <p>
434 * This method must not use any instance variables.
435 *
436 * @param index the index to retrieve
437 * @param chrono the chronology to use
438 * @return the field
439 */
440 protected DateTimeField getField(int index, Chronology chrono) {
441 switch (index) {
442 case HOUR_OF_DAY:
443 return chrono.hourOfDay();
444 case MINUTE_OF_HOUR:
445 return chrono.minuteOfHour();
446 case SECOND_OF_MINUTE:
447 return chrono.secondOfMinute();
448 case MILLIS_OF_SECOND:
449 return chrono.millisOfSecond();
450 default:
451 throw new IndexOutOfBoundsException("Invalid index: " + index);
452 }
453 }
454
455 /**
456 * Gets the field type at the specified index.
457 *
458 * @param index the index to retrieve
459 * @return the field at the specified index
460 * @throws IndexOutOfBoundsException if the index is invalid
461 */
462 public DateTimeFieldType getFieldType(int index) {
463 return FIELD_TYPES[index];
464 }
465
466 /**
467 * Gets an array of the field type of each of the fields that this partial supports.
468 * <p>
469 * The fields are returned largest to smallest, Hour, Minute, Second, Millis.
470 *
471 * @return the array of field types (cloned), largest to smallest
472 */
473 public DateTimeFieldType[] getFieldTypes() {
474 return (DateTimeFieldType[]) FIELD_TYPES.clone();
475 }
476
477 //-----------------------------------------------------------------------
478 /**
479 * Returns a copy of this time with the specified chronology.
480 * This instance is immutable and unaffected by this method call.
481 * <p>
482 * This method retains the values of the fields, thus the result will
483 * typically refer to a different instant.
484 * <p>
485 * The time zone of the specified chronology is ignored, as TimeOfDay
486 * operates without a time zone.
487 *
488 * @param newChronology the new chronology, null means ISO
489 * @return a copy of this datetime with a different chronology
490 * @throws IllegalArgumentException if the values are invalid for the new chronology
491 */
492 public TimeOfDay withChronologyRetainFields(Chronology newChronology) {
493 newChronology = DateTimeUtils.getChronology(newChronology);
494 newChronology = newChronology.withUTC();
495 if (newChronology == getChronology()) {
496 return this;
497 } else {
498 TimeOfDay newTimeOfDay = new TimeOfDay(this, newChronology);
499 newChronology.validate(newTimeOfDay, getValues());
500 return newTimeOfDay;
501 }
502 }
503
504 /**
505 * Returns a copy of this time with the specified field set to a new value.
506 * <p>
507 * For example, if the field type is <code>minuteOfHour</code> then the day
508 * would be changed in the returned instance.
509 * <p>
510 * These three lines are equivalent:
511 * <pre>
512 * TimeOfDay updated = tod.withField(DateTimeFieldType.minuteOfHour(), 6);
513 * TimeOfDay updated = tod.minuteOfHour().setCopy(6);
514 * TimeOfDay updated = tod.property(DateTimeFieldType.minuteOfHour()).setCopy(6);
515 * </pre>
516 *
517 * @param fieldType the field type to set, not null
518 * @param value the value to set
519 * @return a copy of this instance with the field set
520 * @throws IllegalArgumentException if the value is null or invalid
521 */
522 public TimeOfDay withField(DateTimeFieldType fieldType, int value) {
523 int index = indexOfSupported(fieldType);
524 if (value == getValue(index)) {
525 return this;
526 }
527 int[] newValues = getValues();
528 newValues = getField(index).set(this, index, newValues, value);
529 return new TimeOfDay(this, newValues);
530 }
531
532 /**
533 * Returns a copy of this time with the value of the specified field increased,
534 * wrapping to what would be a new day if required.
535 * <p>
536 * If the addition is zero, then <code>this</code> is returned.
537 * <p>
538 * These three lines are equivalent:
539 * <pre>
540 * TimeOfDay added = tod.withFieldAdded(DurationFieldType.minutes(), 6);
541 * TimeOfDay added = tod.plusMinutes(6);
542 * TimeOfDay added = tod.minuteOfHour().addToCopy(6);
543 * </pre>
544 *
545 * @param fieldType the field type to add to, not null
546 * @param amount the amount to add
547 * @return a copy of this instance with the field updated
548 * @throws IllegalArgumentException if the value is null or invalid
549 * @throws ArithmeticException if the new datetime exceeds the capacity
550 */
551 public TimeOfDay withFieldAdded(DurationFieldType fieldType, int amount) {
552 int index = indexOfSupported(fieldType);
553 if (amount == 0) {
554 return this;
555 }
556 int[] newValues = getValues();
557 newValues = getField(index).addWrapPartial(this, index, newValues, amount);
558 return new TimeOfDay(this, newValues);
559 }
560
561 /**
562 * Returns a copy of this time with the specified period added,
563 * wrapping to what would be a new day if required.
564 * <p>
565 * If the addition is zero, then <code>this</code> is returned.
566 * Fields in the period that aren't present in the partial are ignored.
567 * <p>
568 * This method is typically used to add multiple copies of complex
569 * period instances. Adding one field is best achieved using methods
570 * like {@link #withFieldAdded(DurationFieldType, int)}
571 * or {@link #plusHours(int)}.
572 *
573 * @param period the period to add to this one, null means zero
574 * @param scalar the amount of times to add, such as -1 to subtract once
575 * @return a copy of this instance with the period added
576 * @throws ArithmeticException if the new datetime exceeds the capacity
577 */
578 public TimeOfDay withPeriodAdded(ReadablePeriod period, int scalar) {
579 if (period == null || scalar == 0) {
580 return this;
581 }
582 int[] newValues = getValues();
583 for (int i = 0; i < period.size(); i++) {
584 DurationFieldType fieldType = period.getFieldType(i);
585 int index = indexOf(fieldType);
586 if (index >= 0) {
587 newValues = getField(index).addWrapPartial(this, index, newValues,
588 FieldUtils.safeMultiply(period.getValue(i), scalar));
589 }
590 }
591 return new TimeOfDay(this, newValues);
592 }
593
594 //-----------------------------------------------------------------------
595 /**
596 * Returns a copy of this time with the specified period added,
597 * wrapping to what would be a new day if required.
598 * <p>
599 * If the amount is zero or null, then <code>this</code> is returned.
600 * <p>
601 * This method is typically used to add complex period instances.
602 * Adding one field is best achieved using methods
603 * like {@link #plusHours(int)}.
604 *
605 * @param period the duration to add to this one, null means zero
606 * @return a copy of this instance with the period added
607 * @throws ArithmeticException if the new datetime exceeds the capacity of a long
608 */
609 public TimeOfDay plus(ReadablePeriod period) {
610 return withPeriodAdded(period, 1);
611 }
612
613 //-----------------------------------------------------------------------
614 /**
615 * Returns a copy of this time plus the specified number of hours.
616 * <p>
617 * This time instance is immutable and unaffected by this method call.
618 * <p>
619 * The following three lines are identical in effect:
620 * <pre>
621 * TimeOfDay added = dt.plusHours(6);
622 * TimeOfDay added = dt.plus(Period.hours(6));
623 * TimeOfDay added = dt.withFieldAdded(DurationFieldType.hours(), 6);
624 * </pre>
625 *
626 * @param hours the amount of hours to add, may be negative
627 * @return the new time plus the increased hours
628 * @since 1.1
629 */
630 public TimeOfDay plusHours(int hours) {
631 return withFieldAdded(DurationFieldType.hours(), hours);
632 }
633
634 /**
635 * Returns a copy of this time plus the specified number of minutes.
636 * <p>
637 * This time instance is immutable and unaffected by this method call.
638 * <p>
639 * The following three lines are identical in effect:
640 * <pre>
641 * TimeOfDay added = dt.plusMinutes(6);
642 * TimeOfDay added = dt.plus(Period.minutes(6));
643 * TimeOfDay added = dt.withFieldAdded(DurationFieldType.minutes(), 6);
644 * </pre>
645 *
646 * @param minutes the amount of minutes to add, may be negative
647 * @return the new time plus the increased minutes
648 * @since 1.1
649 */
650 public TimeOfDay plusMinutes(int minutes) {
651 return withFieldAdded(DurationFieldType.minutes(), minutes);
652 }
653
654 /**
655 * Returns a copy of this time plus the specified number of seconds.
656 * <p>
657 * This time instance is immutable and unaffected by this method call.
658 * <p>
659 * The following three lines are identical in effect:
660 * <pre>
661 * TimeOfDay added = dt.plusSeconds(6);
662 * TimeOfDay added = dt.plus(Period.seconds(6));
663 * TimeOfDay added = dt.withFieldAdded(DurationFieldType.seconds(), 6);
664 * </pre>
665 *
666 * @param seconds the amount of seconds to add, may be negative
667 * @return the new time plus the increased seconds
668 * @since 1.1
669 */
670 public TimeOfDay plusSeconds(int seconds) {
671 return withFieldAdded(DurationFieldType.seconds(), seconds);
672 }
673
674 /**
675 * Returns a copy of this time plus the specified number of millis.
676 * <p>
677 * This time instance is immutable and unaffected by this method call.
678 * <p>
679 * The following three lines are identical in effect:
680 * <pre>
681 * TimeOfDay added = dt.plusMillis(6);
682 * TimeOfDay added = dt.plus(Period.millis(6));
683 * TimeOfDay added = dt.withFieldAdded(DurationFieldType.millis(), 6);
684 * </pre>
685 *
686 * @param millis the amount of millis to add, may be negative
687 * @return the new time plus the increased millis
688 * @since 1.1
689 */
690 public TimeOfDay plusMillis(int millis) {
691 return withFieldAdded(DurationFieldType.millis(), millis);
692 }
693
694 //-----------------------------------------------------------------------
695 /**
696 * Returns a copy of this time with the specified period taken away,
697 * wrapping to what would be a new day if required.
698 * <p>
699 * If the amount is zero or null, then <code>this</code> is returned.
700 * <p>
701 * This method is typically used to subtract complex period instances.
702 * Subtracting one field is best achieved using methods
703 * like {@link #minusHours(int)}.
704 *
705 * @param period the period to reduce this instant by
706 * @return a copy of this instance with the period taken away
707 * @throws ArithmeticException if the new time exceeds capacity
708 */
709 public TimeOfDay minus(ReadablePeriod period) {
710 return withPeriodAdded(period, -1);
711 }
712
713 //-----------------------------------------------------------------------
714 /**
715 * Returns a copy of this time minus the specified number of hours.
716 * <p>
717 * This time instance is immutable and unaffected by this method call.
718 * <p>
719 * The following three lines are identical in effect:
720 * <pre>
721 * TimeOfDay subtracted = dt.minusHours(6);
722 * TimeOfDay subtracted = dt.minus(Period.hours(6));
723 * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.hours(), -6);
724 * </pre>
725 *
726 * @param hours the amount of hours to subtract, may be negative
727 * @return the new time minus the increased hours
728 * @since 1.1
729 */
730 public TimeOfDay minusHours(int hours) {
731 return withFieldAdded(DurationFieldType.hours(), FieldUtils.safeNegate(hours));
732 }
733
734 /**
735 * Returns a copy of this time minus the specified number of minutes.
736 * <p>
737 * This time instance is immutable and unaffected by this method call.
738 * <p>
739 * The following three lines are identical in effect:
740 * <pre>
741 * TimeOfDay subtracted = dt.minusMinutes(6);
742 * TimeOfDay subtracted = dt.minus(Period.minutes(6));
743 * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.minutes(), -6);
744 * </pre>
745 *
746 * @param minutes the amount of minutes to subtract, may be negative
747 * @return the new time minus the increased minutes
748 * @since 1.1
749 */
750 public TimeOfDay minusMinutes(int minutes) {
751 return withFieldAdded(DurationFieldType.minutes(), FieldUtils.safeNegate(minutes));
752 }
753
754 /**
755 * Returns a copy of this time minus the specified number of seconds.
756 * <p>
757 * This time instance is immutable and unaffected by this method call.
758 * <p>
759 * The following three lines are identical in effect:
760 * <pre>
761 * TimeOfDay subtracted = dt.minusSeconds(6);
762 * TimeOfDay subtracted = dt.minus(Period.seconds(6));
763 * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.seconds(), -6);
764 * </pre>
765 *
766 * @param seconds the amount of seconds to subtract, may be negative
767 * @return the new time minus the increased seconds
768 * @since 1.1
769 */
770 public TimeOfDay minusSeconds(int seconds) {
771 return withFieldAdded(DurationFieldType.seconds(), FieldUtils.safeNegate(seconds));
772 }
773
774 /**
775 * Returns a copy of this time minus the specified number of millis.
776 * <p>
777 * This time instance is immutable and unaffected by this method call.
778 * <p>
779 * The following three lines are identical in effect:
780 * <pre>
781 * TimeOfDay subtracted = dt.minusMillis(6);
782 * TimeOfDay subtracted = dt.minus(Period.millis(6));
783 * TimeOfDay subtracted = dt.withFieldAdded(DurationFieldType.millis(), -6);
784 * </pre>
785 *
786 * @param millis the amount of millis to subtract, may be negative
787 * @return the new time minus the increased millis
788 * @since 1.1
789 */
790 public TimeOfDay minusMillis(int millis) {
791 return withFieldAdded(DurationFieldType.millis(), FieldUtils.safeNegate(millis));
792 }
793
794 //-----------------------------------------------------------------------
795 /**
796 * Gets the property object for the specified type, which contains
797 * many useful methods.
798 *
799 * @param type the field type to get the property for
800 * @return the property object
801 * @throws IllegalArgumentException if the field is null or unsupported
802 */
803 public Property property(DateTimeFieldType type) {
804 return new Property(this, indexOfSupported(type));
805 }
806
807 //-----------------------------------------------------------------------
808 /**
809 * Converts this object to a LocalTime with the same time and chronology.
810 *
811 * @return a LocalTime with the same time and chronology
812 * @since 1.3
813 */
814 public LocalTime toLocalTime() {
815 return new LocalTime(getHourOfDay(), getMinuteOfHour(),
816 getSecondOfMinute(), getMillisOfSecond(), getChronology());
817 }
818
819 //-----------------------------------------------------------------------
820 /**
821 * Converts this partial to a full datetime using the default time zone
822 * setting the time fields from this instance and the date fields from
823 * the current time.
824 *
825 * @return this date as a datetime with the time as the current time
826 */
827 public DateTime toDateTimeToday() {
828 return toDateTimeToday(null);
829 }
830
831 /**
832 * Converts this partial to a full datetime using the specified time zone
833 * setting the time fields from this instance and the date fields from
834 * the current time.
835 * <p>
836 * This method uses the chronology from this instance plus the time zone
837 * specified.
838 *
839 * @param zone the zone to use, null means default
840 * @return this date as a datetime with the time as the current time
841 */
842 public DateTime toDateTimeToday(DateTimeZone zone) {
843 Chronology chrono = getChronology().withZone(zone);
844 long instantMillis = DateTimeUtils.currentTimeMillis();
845 long resolved = chrono.set(this, instantMillis);
846 return new DateTime(resolved, chrono);
847 }
848
849 //-----------------------------------------------------------------------
850 /**
851 * Get the hour of day (0-23) field value.
852 *
853 * @return the hour of day
854 */
855 public int getHourOfDay() {
856 return getValue(HOUR_OF_DAY);
857 }
858
859 /**
860 * Get the minute of hour field value.
861 *
862 * @return the minute of hour
863 */
864 public int getMinuteOfHour() {
865 return getValue(MINUTE_OF_HOUR);
866 }
867
868 /**
869 * Get the second of minute field value.
870 *
871 * @return the second of minute
872 */
873 public int getSecondOfMinute() {
874 return getValue(SECOND_OF_MINUTE);
875 }
876
877 /**
878 * Get the millis of second field value.
879 *
880 * @return the millis of second
881 */
882 public int getMillisOfSecond() {
883 return getValue(MILLIS_OF_SECOND);
884 }
885
886 //-----------------------------------------------------------------------
887 /**
888 * Returns a copy of this time with the hour of day field updated.
889 * <p>
890 * TimeOfDay is immutable, so there are no set methods.
891 * Instead, this method returns a new instance with the value of
892 * hour of day changed.
893 *
894 * @param hour the hour of day to set
895 * @return a copy of this object with the field set
896 * @throws IllegalArgumentException if the value is invalid
897 * @since 1.3
898 */
899 public TimeOfDay withHourOfDay(int hour) {
900 int[] newValues = getValues();
901 newValues = getChronology().hourOfDay().set(this, HOUR_OF_DAY, newValues, hour);
902 return new TimeOfDay(this, newValues);
903 }
904
905 /**
906 * Returns a copy of this time with the minute of hour field updated.
907 * <p>
908 * TimeOfDay is immutable, so there are no set methods.
909 * Instead, this method returns a new instance with the value of
910 * minute of hour changed.
911 *
912 * @param minute the minute of hour to set
913 * @return a copy of this object with the field set
914 * @throws IllegalArgumentException if the value is invalid
915 * @since 1.3
916 */
917 public TimeOfDay withMinuteOfHour(int minute) {
918 int[] newValues = getValues();
919 newValues = getChronology().minuteOfHour().set(this, MINUTE_OF_HOUR, newValues, minute);
920 return new TimeOfDay(this, newValues);
921 }
922
923 /**
924 * Returns a copy of this time with the second of minute field updated.
925 * <p>
926 * TimeOfDay is immutable, so there are no set methods.
927 * Instead, this method returns a new instance with the value of
928 * second of minute changed.
929 *
930 * @param second the second of minute to set
931 * @return a copy of this object with the field set
932 * @throws IllegalArgumentException if the value is invalid
933 * @since 1.3
934 */
935 public TimeOfDay withSecondOfMinute(int second) {
936 int[] newValues = getValues();
937 newValues = getChronology().secondOfMinute().set(this, SECOND_OF_MINUTE, newValues, second);
938 return new TimeOfDay(this, newValues);
939 }
940
941 /**
942 * Returns a copy of this time with the millis of second field updated.
943 * <p>
944 * TimeOfDay is immutable, so there are no set methods.
945 * Instead, this method returns a new instance with the value of
946 * millis of second changed.
947 *
948 * @param millis the millis of second to set
949 * @return a copy of this object with the field set
950 * @throws IllegalArgumentException if the value is invalid
951 * @since 1.3
952 */
953 public TimeOfDay withMillisOfSecond(int millis) {
954 int[] newValues = getValues();
955 newValues = getChronology().millisOfSecond().set(this, MILLIS_OF_SECOND, newValues, millis);
956 return new TimeOfDay(this, newValues);
957 }
958
959 //-----------------------------------------------------------------------
960 /**
961 * Get the hour of day field property which provides access to advanced functionality.
962 *
963 * @return the hour of day property
964 */
965 public Property hourOfDay() {
966 return new Property(this, HOUR_OF_DAY);
967 }
968
969 /**
970 * Get the minute of hour field property which provides access to advanced functionality.
971 *
972 * @return the minute of hour property
973 */
974 public Property minuteOfHour() {
975 return new Property(this, MINUTE_OF_HOUR);
976 }
977
978 /**
979 * Get the second of minute field property which provides access to advanced functionality.
980 *
981 * @return the second of minute property
982 */
983 public Property secondOfMinute() {
984 return new Property(this, SECOND_OF_MINUTE);
985 }
986
987 /**
988 * Get the millis of second property which provides access to advanced functionality.
989 *
990 * @return the millis of second property
991 */
992 public Property millisOfSecond() {
993 return new Property(this, MILLIS_OF_SECOND);
994 }
995
996 //-----------------------------------------------------------------------
997 /**
998 * Output the time in the ISO8601 format THH:mm:ss.SSS.
999 *
1000 * @return ISO8601 formatted string
1001 */
1002 public String toString() {
1003 return ISODateTimeFormat.tTime().print(this);
1004 }
1005
1006 //-----------------------------------------------------------------------
1007 /**
1008 * The property class for <code>TimeOfDay</code>.
1009 * <p>
1010 * This class binds a <code>TimeOfDay</code> to a <code>DateTimeField</code>.
1011 *
1012 * @author Stephen Colebourne
1013 * @since 1.0
1014 * @deprecated Use LocalTime which has a much better internal implementation
1015 */
1016 public static class Property extends AbstractPartialFieldProperty implements Serializable {
1017
1018 /** Serialization version */
1019 private static final long serialVersionUID = 5598459141741063833L;
1020
1021 /** The partial */
1022 private final TimeOfDay iTimeOfDay;
1023 /** The field index */
1024 private final int iFieldIndex;
1025
1026 /**
1027 * Constructs a property.
1028 *
1029 * @param partial the partial instance
1030 * @param fieldIndex the index in the partial
1031 */
1032 Property(TimeOfDay partial, int fieldIndex) {
1033 super();
1034 iTimeOfDay = partial;
1035 iFieldIndex = fieldIndex;
1036 }
1037
1038 /**
1039 * Gets the field that this property uses.
1040 *
1041 * @return the field
1042 */
1043 public DateTimeField getField() {
1044 return iTimeOfDay.getField(iFieldIndex);
1045 }
1046
1047 /**
1048 * Gets the partial that this property belongs to.
1049 *
1050 * @return the partial
1051 */
1052 protected ReadablePartial getReadablePartial() {
1053 return iTimeOfDay;
1054 }
1055
1056 /**
1057 * Gets the partial that this property belongs to.
1058 *
1059 * @return the partial
1060 */
1061 public TimeOfDay getTimeOfDay() {
1062 return iTimeOfDay;
1063 }
1064
1065 /**
1066 * Gets the value of this field.
1067 *
1068 * @return the field value
1069 */
1070 public int get() {
1071 return iTimeOfDay.getValue(iFieldIndex);
1072 }
1073
1074 //-----------------------------------------------------------------------
1075 /**
1076 * Adds to the value of this field in a copy of this TimeOfDay,
1077 * wrapping to what would be the next day if necessary.
1078 * <p>
1079 * The value will be added to this field. If the value is too large to be
1080 * added solely to this field then it will affect larger fields.
1081 * Smaller fields are unaffected.
1082 * <p>
1083 * If the result would be too large, beyond 23:59:59:999, then the
1084 * calculation wraps to 00:00:00.000. For the alternate strict behaviour
1085 * with no wrapping see {@link #addNoWrapToCopy(int)}.
1086 * <p>
1087 * The TimeOfDay attached to this property is unchanged by this call.
1088 * Instead, a new instance is returned.
1089 *
1090 * @param valueToAdd the value to add to the field in the copy
1091 * @return a copy of the TimeOfDay with the field value changed
1092 * @throws IllegalArgumentException if the value isn't valid
1093 */
1094 public TimeOfDay addToCopy(int valueToAdd) {
1095 int[] newValues = iTimeOfDay.getValues();
1096 newValues = getField().addWrapPartial(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1097 return new TimeOfDay(iTimeOfDay, newValues);
1098 }
1099
1100 /**
1101 * Adds to the value of this field in a copy of this TimeOfDay,
1102 * throwing an Exception if the bounds are exceeded.
1103 * <p>
1104 * The value will be added to this field. If the value is too large to be
1105 * added solely to this field then it will affect larger fields.
1106 * Smaller fields are unaffected.
1107 * <p>
1108 * If the result would be too large (beyond 23:59:59:999) or too
1109 * small (less than 00:00:00.000) then an Execption is thrown.
1110 * For the alternate behaviour which wraps to the next 'day',
1111 * see {@link #addToCopy(int)}.
1112 * <p>
1113 * The TimeOfDay attached to this property is unchanged by this call.
1114 * Instead, a new instance is returned.
1115 *
1116 * @param valueToAdd the value to add to the field in the copy
1117 * @return a copy of the TimeOfDay with the field value changed
1118 * @throws IllegalArgumentException if the value isn't valid
1119 */
1120 public TimeOfDay addNoWrapToCopy(int valueToAdd) {
1121 int[] newValues = iTimeOfDay.getValues();
1122 newValues = getField().add(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1123 return new TimeOfDay(iTimeOfDay, newValues);
1124 }
1125
1126 /**
1127 * Adds to the value of this field in a copy of this TimeOfDay wrapping
1128 * within this field if the maximum value is reached.
1129 * <p>
1130 * The value will be added to this field. If the value is too large to be
1131 * added solely to this field then it wraps within this field.
1132 * Other fields are unaffected.
1133 * <p>
1134 * For example,
1135 * <code>12:59:37</code> addWrapField one minute returns <code>12:00:37</code>.
1136 * <p>
1137 * The TimeOfDay attached to this property is unchanged by this call.
1138 * Instead, a new instance is returned.
1139 *
1140 * @param valueToAdd the value to add to the field in the copy
1141 * @return a copy of the TimeOfDay with the field value changed
1142 * @throws IllegalArgumentException if the value isn't valid
1143 */
1144 public TimeOfDay addWrapFieldToCopy(int valueToAdd) {
1145 int[] newValues = iTimeOfDay.getValues();
1146 newValues = getField().addWrapField(iTimeOfDay, iFieldIndex, newValues, valueToAdd);
1147 return new TimeOfDay(iTimeOfDay, newValues);
1148 }
1149
1150 //-----------------------------------------------------------------------
1151 /**
1152 * Sets this field in a copy of the TimeOfDay.
1153 * <p>
1154 * The TimeOfDay attached to this property is unchanged by this call.
1155 * Instead, a new instance is returned.
1156 *
1157 * @param value the value to set the field in the copy to
1158 * @return a copy of the TimeOfDay with the field value changed
1159 * @throws IllegalArgumentException if the value isn't valid
1160 */
1161 public TimeOfDay setCopy(int value) {
1162 int[] newValues = iTimeOfDay.getValues();
1163 newValues = getField().set(iTimeOfDay, iFieldIndex, newValues, value);
1164 return new TimeOfDay(iTimeOfDay, newValues);
1165 }
1166
1167 /**
1168 * Sets this field in a copy of the TimeOfDay to a parsed text value.
1169 * <p>
1170 * The TimeOfDay attached to this property is unchanged by this call.
1171 * Instead, a new instance is returned.
1172 *
1173 * @param text the text value to set
1174 * @param locale optional locale to use for selecting a text symbol
1175 * @return a copy of the TimeOfDay with the field value changed
1176 * @throws IllegalArgumentException if the text value isn't valid
1177 */
1178 public TimeOfDay setCopy(String text, Locale locale) {
1179 int[] newValues = iTimeOfDay.getValues();
1180 newValues = getField().set(iTimeOfDay, iFieldIndex, newValues, text, locale);
1181 return new TimeOfDay(iTimeOfDay, newValues);
1182 }
1183
1184 /**
1185 * Sets this field in a copy of the TimeOfDay to a parsed text value.
1186 * <p>
1187 * The TimeOfDay attached to this property is unchanged by this call.
1188 * Instead, a new instance is returned.
1189 *
1190 * @param text the text value to set
1191 * @return a copy of the TimeOfDay with the field value changed
1192 * @throws IllegalArgumentException if the text value isn't valid
1193 */
1194 public TimeOfDay setCopy(String text) {
1195 return setCopy(text, null);
1196 }
1197
1198 //-----------------------------------------------------------------------
1199 /**
1200 * Returns a new TimeOfDay with this field set to the maximum value
1201 * for this field.
1202 * <p>
1203 * The TimeOfDay attached to this property is unchanged by this call.
1204 *
1205 * @return a copy of the TimeOfDay with this field set to its maximum
1206 * @since 1.2
1207 */
1208 public TimeOfDay withMaximumValue() {
1209 return setCopy(getMaximumValue());
1210 }
1211
1212 /**
1213 * Returns a new TimeOfDay with this field set to the minimum value
1214 * for this field.
1215 * <p>
1216 * The TimeOfDay attached to this property is unchanged by this call.
1217 *
1218 * @return a copy of the TimeOfDay with this field set to its minimum
1219 * @since 1.2
1220 */
1221 public TimeOfDay withMinimumValue() {
1222 return setCopy(getMinimumValue());
1223 }
1224 }
1225
1226 }