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 */ 016package org.joda.time; 017 018import java.io.Serializable; 019import java.util.Calendar; 020import java.util.Date; 021import java.util.Locale; 022 023import org.joda.time.base.BasePartial; 024import org.joda.time.chrono.ISOChronology; 025import org.joda.time.field.AbstractPartialFieldProperty; 026import org.joda.time.field.FieldUtils; 027import 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 */ 065public 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}