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