001 /* 002 * Copyright 2001-2011 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 @Deprecated 066 public final class TimeOfDay 067 extends BasePartial 068 implements ReadablePartial, Serializable { 069 // NOTE: No toDateTime(YearMonthDay) as semantics are confusing when 070 // different chronologies 071 072 /** Serialization version */ 073 private static final long serialVersionUID = 3633353405803318660L; 074 /** The singleton set of field types */ 075 private static final DateTimeFieldType[] FIELD_TYPES = new DateTimeFieldType[] { 076 DateTimeFieldType.hourOfDay(), 077 DateTimeFieldType.minuteOfHour(), 078 DateTimeFieldType.secondOfMinute(), 079 DateTimeFieldType.millisOfSecond(), 080 }; 081 082 /** Constant for midnight. */ 083 public static final TimeOfDay MIDNIGHT = new TimeOfDay(0, 0, 0, 0); 084 085 /** The index of the hourOfDay field in the field array */ 086 public static final int HOUR_OF_DAY = 0; 087 /** The index of the minuteOfHour field in the field array */ 088 public static final int MINUTE_OF_HOUR = 1; 089 /** The index of the secondOfMinute field in the field array */ 090 public static final int SECOND_OF_MINUTE = 2; 091 /** The index of the millisOfSecond field in the field array */ 092 public static final int MILLIS_OF_SECOND = 3; 093 094 //----------------------------------------------------------------------- 095 /** 096 * Constructs a TimeOfDay from a <code>java.util.Calendar</code> 097 * using exactly the same field values avoiding any time zone effects. 098 * <p> 099 * 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 }