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; 019 020import org.joda.time.base.BasePeriod; 021import org.joda.time.chrono.ISOChronology; 022import org.joda.time.field.FieldUtils; 023import org.joda.time.format.ISOPeriodFormat; 024 025/** 026 * An immutable time period specifying a set of duration field values. 027 * <p> 028 * A time period is divided into a number of fields, such as hours and seconds. 029 * Which fields are supported is defined by the PeriodType class. 030 * The default is the standard period type, which supports years, months, weeks, days, 031 * hours, minutes, seconds and millis. 032 * <p> 033 * When this time period is added to an instant, the effect is of adding each field in turn. 034 * As a result, this takes into account daylight savings time. 035 * Adding a time period of 1 day to the day before daylight savings starts will only add 036 * 23 hours rather than 24 to ensure that the time remains the same. 037 * If this is not the behaviour you want, then see {@link Duration}. 038 * <p> 039 * The definition of a period also affects the equals method. A period of 1 040 * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. 041 * This is because periods represent an abstracted definition of a time period 042 * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight 043 * savings boundary). To compare the actual duration of two periods, convert 044 * both to durations using toDuration, an operation that emphasises that the 045 * result may differ according to the date you choose. 046 * <p> 047 * Period is thread-safe and immutable, provided that the PeriodType is as well. 048 * All standard PeriodType classes supplied are thread-safe and immutable. 049 * 050 * @author Brian S O'Neill 051 * @author Stephen Colebourne 052 * @since 1.0 053 * @see MutablePeriod 054 */ 055public final class Period 056 extends BasePeriod 057 implements ReadablePeriod, Serializable { 058 059 /** 060 * A period of zero length and standard period type. 061 * @since 1.4 062 */ 063 public static final Period ZERO = new Period(); 064 065 /** Serialization version */ 066 private static final long serialVersionUID = 741052353876488155L; 067 068 //----------------------------------------------------------------------- 069 /** 070 * Create a period with a specified number of years. 071 * <p> 072 * The standard period type is used, thus you can add other fields such 073 * as months or days using the <code>withXxx()</code> methods. 074 * For example, <code>Period.years(2).withMonths(6);</code> 075 * <p> 076 * If you want a year-based period that cannot have other fields added, 077 * then you should consider using {@link Years}. 078 * 079 * @param years the amount of years in this period 080 * @return the period 081 */ 082 public static Period years(int years) { 083 return new Period(new int[] {years, 0, 0, 0, 0, 0, 0, 0, 0}, PeriodType.standard()); 084 } 085 086 /** 087 * Create a period with a specified number of months. 088 * <p> 089 * The standard period type is used, thus you can add other fields such 090 * as years or days using the <code>withXxx()</code> methods. 091 * For example, <code>Period.months(2).withDays(6);</code> 092 * <p> 093 * If you want a month-based period that cannot have other fields added, 094 * then you should consider using {@link Months}. 095 * 096 * @param months the amount of months in this period 097 * @return the period 098 */ 099 public static Period months(int months) { 100 return new Period(new int[] {0, months, 0, 0, 0, 0, 0, 0}, PeriodType.standard()); 101 } 102 103 /** 104 * Create a period with a specified number of weeks. 105 * <p> 106 * The standard period type is used, thus you can add other fields such 107 * as months or days using the <code>withXxx()</code> methods. 108 * For example, <code>Period.weeks(2).withDays(6);</code> 109 * <p> 110 * If you want a week-based period that cannot have other fields added, 111 * then you should consider using {@link Weeks}. 112 * 113 * @param weeks the amount of weeks in this period 114 * @return the period 115 */ 116 public static Period weeks(int weeks) { 117 return new Period(new int[] {0, 0, weeks, 0, 0, 0, 0, 0}, PeriodType.standard()); 118 } 119 120 /** 121 * Create a period with a specified number of days. 122 * <p> 123 * The standard period type is used, thus you can add other fields such 124 * as months or weeks using the <code>withXxx()</code> methods. 125 * For example, <code>Period.days(2).withHours(6);</code> 126 * <p> 127 * If you want a day-based period that cannot have other fields added, 128 * then you should consider using {@link Days}. 129 * 130 * @param days the amount of days in this period 131 * @return the period 132 */ 133 public static Period days(int days) { 134 return new Period(new int[] {0, 0, 0, days, 0, 0, 0, 0}, PeriodType.standard()); 135 } 136 137 /** 138 * Create a period with a specified number of hours. 139 * <p> 140 * The standard period type is used, thus you can add other fields such 141 * as months or days using the <code>withXxx()</code> methods. 142 * For example, <code>Period.hours(2).withMinutes(30);</code> 143 * <p> 144 * If you want a hour-based period that cannot have other fields added, 145 * then you should consider using {@link Hours}. 146 * 147 * @param hours the amount of hours in this period 148 * @return the period 149 */ 150 public static Period hours(int hours) { 151 return new Period(new int[] {0, 0, 0, 0, hours, 0, 0, 0}, PeriodType.standard()); 152 } 153 154 /** 155 * Create a period with a specified number of minutes. 156 * <p> 157 * The standard period type is used, thus you can add other fields such 158 * as days or hours using the <code>withXxx()</code> methods. 159 * For example, <code>Period.minutes(2).withSeconds(30);</code> 160 * <p> 161 * If you want a minute-based period that cannot have other fields added, 162 * then you should consider using {@link Minutes}. 163 * 164 * @param minutes the amount of minutes in this period 165 * @return the period 166 */ 167 public static Period minutes(int minutes) { 168 return new Period(new int[] {0, 0, 0, 0, 0, minutes, 0, 0}, PeriodType.standard()); 169 } 170 171 /** 172 * Create a period with a specified number of seconds. 173 * <p> 174 * The standard period type is used, thus you can add other fields such 175 * as days or hours using the <code>withXxx()</code> methods. 176 * For example, <code>Period.seconds(2).withMillis(30);</code> 177 * <p> 178 * If you want a second-based period that cannot have other fields added, 179 * then you should consider using {@link Seconds}. 180 * 181 * @param seconds the amount of seconds in this period 182 * @return the period 183 */ 184 public static Period seconds(int seconds) { 185 return new Period(new int[] {0, 0, 0, 0, 0, 0, seconds, 0}, PeriodType.standard()); 186 } 187 188 /** 189 * Create a period with a specified number of millis. 190 * <p> 191 * The standard period type is used, thus you can add other fields such 192 * as days or hours using the <code>withXxx()</code> methods. 193 * For example, <code>Period.millis(20).withSeconds(30);</code> 194 * 195 * @param millis the amount of millis in this period 196 * @return the period 197 */ 198 public static Period millis(int millis) { 199 return new Period(new int[] {0, 0, 0, 0, 0, 0, 0, millis}, PeriodType.standard()); 200 } 201 202 //----------------------------------------------------------------------- 203 /** 204 * Creates a period from two partially specified times, calculating 205 * by field difference. 206 * <p> 207 * The two partials must contain the same fields, thus you can specify 208 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects, 209 * but not one of each. Also, the partial may not contain overlapping 210 * fields, such as dayOfWeek and dayOfMonth. 211 * <p> 212 * Calculation by field difference works by extracting the difference 213 * one field at a time and not wrapping into other fields. 214 * Thus 2005-06-09/2007-04-12 will yield P1Y-2M3D. 215 * <p> 216 * For example, you have an event that always runs from the 27th of 217 * each month to the 2nd of the next month. If you calculate this 218 * period using a standard constructor, then you will get between 219 * P3D and P6D depending on the month. If you use this method, then 220 * you will get P1M-25D. This field-difference based period can 221 * be successfully applied to each month of the year to obtain the 222 * correct end date for a given start date. 223 * 224 * @param start the start of the period, must not be null 225 * @param end the end of the period, must not be null 226 * @throws IllegalArgumentException if the partials are null or invalid 227 * @since 1.1 228 */ 229 public static Period fieldDifference(ReadablePartial start, ReadablePartial end) { 230 if (start == null || end == null) { 231 throw new IllegalArgumentException("ReadablePartial objects must not be null"); 232 } 233 if (start.size() != end.size()) { 234 throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); 235 } 236 DurationFieldType[] types = new DurationFieldType[start.size()]; 237 int[] values = new int[start.size()]; 238 for (int i = 0, isize = start.size(); i < isize; i++) { 239 if (start.getFieldType(i) != end.getFieldType(i)) { 240 throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); 241 } 242 types[i] = start.getFieldType(i).getDurationType(); 243 if (i > 0 && types[i - 1] == types[i]) { 244 throw new IllegalArgumentException("ReadablePartial objects must not have overlapping fields"); 245 } 246 values[i] = end.getValue(i) - start.getValue(i); 247 } 248 return new Period(values, PeriodType.forFields(types)); 249 } 250 251 //----------------------------------------------------------------------- 252 /** 253 * Creates a new empty period with the standard set of fields. 254 * <p> 255 * One way to initialise a period is as follows: 256 * <pre> 257 * Period = new Period().withYears(6).withMonths(3).withSeconds(23); 258 * </pre> 259 * Bear in mind that this creates four period instances in total, three of 260 * which are immediately discarded. 261 * The alterative is more efficient, but less readable: 262 * <pre> 263 * Period = new Period(6, 3, 0, 0, 0, 0, 23, 0); 264 * </pre> 265 * The following is also slightly less wasteful: 266 * <pre> 267 * Period = Period.years(6).withMonths(3).withSeconds(23); 268 * </pre> 269 */ 270 public Period() { 271 super(0L, null, null); 272 } 273 274 /** 275 * Create a period from a set of field values using the standard set of fields. 276 * Note that the parameters specify the time fields hours, minutes, 277 * seconds and millis, not the date fields. 278 * 279 * @param hours amount of hours in this period 280 * @param minutes amount of minutes in this period 281 * @param seconds amount of seconds in this period 282 * @param millis amount of milliseconds in this period 283 */ 284 public Period(int hours, int minutes, int seconds, int millis) { 285 super(0, 0, 0, 0, hours, minutes, seconds, millis, PeriodType.standard()); 286 } 287 288 /** 289 * Create a period from a set of field values using the standard set of fields. 290 * 291 * @param years amount of years in this period 292 * @param months amount of months in this period 293 * @param weeks amount of weeks in this period 294 * @param days amount of days in this period 295 * @param hours amount of hours in this period 296 * @param minutes amount of minutes in this period 297 * @param seconds amount of seconds in this period 298 * @param millis amount of milliseconds in this period 299 */ 300 public Period(int years, int months, int weeks, int days, 301 int hours, int minutes, int seconds, int millis) { 302 super(years, months, weeks, days, hours, minutes, seconds, millis, PeriodType.standard()); 303 } 304 305 /** 306 * Create a period from a set of field values. 307 * <p> 308 * There is usually little need to use this constructor. 309 * The period type is used primarily to define how to split an interval into a period. 310 * As this constructor already is split, the period type does no real work. 311 * 312 * @param years amount of years in this period, which must be zero if unsupported 313 * @param months amount of months in this period, which must be zero if unsupported 314 * @param weeks amount of weeks in this period, which must be zero if unsupported 315 * @param days amount of days in this period, which must be zero if unsupported 316 * @param hours amount of hours in this period, which must be zero if unsupported 317 * @param minutes amount of minutes in this period, which must be zero if unsupported 318 * @param seconds amount of seconds in this period, which must be zero if unsupported 319 * @param millis amount of milliseconds in this period, which must be zero if unsupported 320 * @param type which set of fields this period supports, null means AllType 321 * @throws IllegalArgumentException if an unsupported field's value is non-zero 322 */ 323 public Period(int years, int months, int weeks, int days, 324 int hours, int minutes, int seconds, int millis, PeriodType type) { 325 super(years, months, weeks, days, hours, minutes, seconds, millis, type); 326 } 327 328 /** 329 * Creates a period from the given millisecond duration using the standard 330 * set of fields. 331 * <p> 332 * Only precise fields in the period type will be used. 333 * For the standard period type this is the time fields only. 334 * Thus the year, month, week and day fields will not be populated. 335 * <p> 336 * If the duration is small, less than one day, then this method will perform 337 * as you might expect and split the fields evenly. 338 * <p> 339 * If the duration is larger than one day then all the remaining duration will 340 * be stored in the largest available precise field, hours in this case. 341 * <p> 342 * For example, a duration equal to (365 + 60 + 5) days will be converted to 343 * ((365 + 60 + 5) * 24) hours by this constructor. 344 * <p> 345 * For more control over the conversion process, you have two options: 346 * <ul> 347 * <li>convert the duration to an {@link Interval}, and from there obtain the period 348 * <li>specify a period type that contains precise definitions of the day and larger 349 * fields, such as UTC 350 * </ul> 351 * 352 * @param duration the duration, in milliseconds 353 */ 354 public Period(long duration) { 355 super(duration, null, null); 356 } 357 358 /** 359 * Creates a period from the given millisecond duration. 360 * <p> 361 * Only precise fields in the period type will be used. 362 * Imprecise fields will not be populated. 363 * <p> 364 * If the duration is small then this method will perform 365 * as you might expect and split the fields evenly. 366 * <p> 367 * If the duration is large then all the remaining duration will 368 * be stored in the largest available precise field. 369 * For details as to which fields are precise, review the period type javadoc. 370 * 371 * @param duration the duration, in milliseconds 372 * @param type which set of fields this period supports, null means standard 373 */ 374 public Period(long duration, PeriodType type) { 375 super(duration, type, null); 376 } 377 378 /** 379 * Creates a period from the given millisecond duration using the standard 380 * set of fields. 381 * <p> 382 * Only precise fields in the period type will be used. 383 * Imprecise fields will not be populated. 384 * <p> 385 * If the duration is small then this method will perform 386 * as you might expect and split the fields evenly. 387 * <p> 388 * If the duration is large then all the remaining duration will 389 * be stored in the largest available precise field. 390 * For details as to which fields are precise, review the period type javadoc. 391 * 392 * @param duration the duration, in milliseconds 393 * @param chronology the chronology to use to split the duration, null means ISO default 394 */ 395 public Period(long duration, Chronology chronology) { 396 super(duration, null, chronology); 397 } 398 399 /** 400 * Creates a period from the given millisecond duration. 401 * <p> 402 * Only precise fields in the period type will be used. 403 * Imprecise fields will not be populated. 404 * <p> 405 * If the duration is small then this method will perform 406 * as you might expect and split the fields evenly. 407 * <p> 408 * If the duration is large then all the remaining duration will 409 * be stored in the largest available precise field. 410 * For details as to which fields are precise, review the period type javadoc. 411 * 412 * @param duration the duration, in milliseconds 413 * @param type which set of fields this period supports, null means standard 414 * @param chronology the chronology to use to split the duration, null means ISO default 415 */ 416 public Period(long duration, PeriodType type, Chronology chronology) { 417 super(duration, type, chronology); 418 } 419 420 /** 421 * Creates a period from the given interval endpoints using the standard 422 * set of fields. 423 * 424 * @param startInstant interval start, in milliseconds 425 * @param endInstant interval end, in milliseconds 426 */ 427 public Period(long startInstant, long endInstant) { 428 super(startInstant, endInstant, null, null); 429 } 430 431 /** 432 * Creates a period from the given interval endpoints. 433 * 434 * @param startInstant interval start, in milliseconds 435 * @param endInstant interval end, in milliseconds 436 * @param type which set of fields this period supports, null means standard 437 */ 438 public Period(long startInstant, long endInstant, PeriodType type) { 439 super(startInstant, endInstant, type, null); 440 } 441 442 /** 443 * Creates a period from the given interval endpoints using the standard 444 * set of fields. 445 * 446 * @param startInstant interval start, in milliseconds 447 * @param endInstant interval end, in milliseconds 448 * @param chrono the chronology to use, null means ISO in default zone 449 */ 450 public Period(long startInstant, long endInstant, Chronology chrono) { 451 super(startInstant, endInstant, null, chrono); 452 } 453 454 /** 455 * Creates a period from the given interval endpoints. 456 * 457 * @param startInstant interval start, in milliseconds 458 * @param endInstant interval end, in milliseconds 459 * @param type which set of fields this period supports, null means standard 460 * @param chrono the chronology to use, null means ISO in default zone 461 */ 462 public Period(long startInstant, long endInstant, PeriodType type, Chronology chrono) { 463 super(startInstant, endInstant, type, chrono); 464 } 465 466 /** 467 * Creates a period from the given interval endpoints using the standard 468 * set of fields. 469 * 470 * @param startInstant interval start, null means now 471 * @param endInstant interval end, null means now 472 */ 473 public Period(ReadableInstant startInstant, ReadableInstant endInstant) { 474 super(startInstant, endInstant, null); 475 } 476 477 /** 478 * Creates a period from the given interval endpoints. 479 * 480 * @param startInstant interval start, null means now 481 * @param endInstant interval end, null means now 482 * @param type which set of fields this period supports, null means standard 483 */ 484 public Period(ReadableInstant startInstant, ReadableInstant endInstant, PeriodType type) { 485 super(startInstant, endInstant, type); 486 } 487 488 /** 489 * Creates a period from two partially specified times. 490 * <p> 491 * The two partials must contain the same fields, thus you can specify 492 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects, 493 * but not one of each. 494 * As these are Partial objects, time zones have no effect on the result. 495 * <p> 496 * The two partials must also both be contiguous - see 497 * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition. 498 * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous. 499 * <p> 500 * An alternative way of constructing a Period from two Partials 501 * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. 502 * That method handles all kinds of partials. 503 * 504 * @param start the start of the period, must not be null 505 * @param end the end of the period, must not be null 506 * @throws IllegalArgumentException if the partials are null or invalid 507 * @since 1.1 508 */ 509 public Period(ReadablePartial start, ReadablePartial end) { 510 super(start, end, null); 511 } 512 513 /** 514 * Creates a period from two partially specified times. 515 * <p> 516 * The two partials must contain the same fields, thus you can specify 517 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects, 518 * but not one of each. 519 * As these are Partial objects, time zones have no effect on the result. 520 * <p> 521 * The two partials must also both be contiguous - see 522 * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition. 523 * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous. 524 * <p> 525 * An alternative way of constructing a Period from two Partials 526 * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. 527 * That method handles all kinds of partials. 528 * 529 * @param start the start of the period, must not be null 530 * @param end the end of the period, must not be null 531 * @param type which set of fields this period supports, null means standard 532 * @throws IllegalArgumentException if the partials are null or invalid 533 * @since 1.1 534 */ 535 public Period(ReadablePartial start, ReadablePartial end, PeriodType type) { 536 super(start, end, type); 537 } 538 539 /** 540 * Creates a period from the given start point and the duration. 541 * 542 * @param startInstant the interval start, null means now 543 * @param duration the duration of the interval, null means zero-length 544 */ 545 public Period(ReadableInstant startInstant, ReadableDuration duration) { 546 super(startInstant, duration, null); 547 } 548 549 /** 550 * Creates a period from the given start point and the duration. 551 * 552 * @param startInstant the interval start, null means now 553 * @param duration the duration of the interval, null means zero-length 554 * @param type which set of fields this period supports, null means standard 555 */ 556 public Period(ReadableInstant startInstant, ReadableDuration duration, PeriodType type) { 557 super(startInstant, duration, type); 558 } 559 560 /** 561 * Creates a period from the given duration and end point. 562 * 563 * @param duration the duration of the interval, null means zero-length 564 * @param endInstant the interval end, null means now 565 */ 566 public Period(ReadableDuration duration, ReadableInstant endInstant) { 567 super(duration, endInstant, null); 568 } 569 570 /** 571 * Creates a period from the given duration and end point. 572 * 573 * @param duration the duration of the interval, null means zero-length 574 * @param endInstant the interval end, null means now 575 * @param type which set of fields this period supports, null means standard 576 */ 577 public Period(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) { 578 super(duration, endInstant, type); 579 } 580 581 /** 582 * Creates a period by converting or copying from another object. 583 * <p> 584 * The recognised object types are defined in 585 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 586 * include ReadablePeriod, ReadableInterval and String. 587 * The String formats are described by {@link ISOPeriodFormat#standard()}. 588 * 589 * @param period period to convert 590 * @throws IllegalArgumentException if period is invalid 591 * @throws UnsupportedOperationException if an unsupported field's value is non-zero 592 */ 593 public Period(Object period) { 594 super(period, null, null); 595 } 596 597 /** 598 * Creates a period by converting or copying from another object. 599 * <p> 600 * The recognised object types are defined in 601 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 602 * include ReadablePeriod, ReadableInterval and String. 603 * The String formats are described by {@link ISOPeriodFormat#standard()}. 604 * 605 * @param period period to convert 606 * @param type which set of fields this period supports, null means use converter 607 * @throws IllegalArgumentException if period is invalid 608 * @throws UnsupportedOperationException if an unsupported field's value is non-zero 609 */ 610 public Period(Object period, PeriodType type) { 611 super(period, type, null); 612 } 613 614 /** 615 * Creates a period by converting or copying from another object. 616 * <p> 617 * The recognised object types are defined in 618 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 619 * include ReadablePeriod, ReadableInterval and String. 620 * The String formats are described by {@link ISOPeriodFormat#standard()}. 621 * 622 * @param period period to convert 623 * @param chrono the chronology to use, null means ISO in default zone 624 * @throws IllegalArgumentException if period is invalid 625 * @throws UnsupportedOperationException if an unsupported field's value is non-zero 626 */ 627 public Period(Object period, Chronology chrono) { 628 super(period, null, chrono); 629 } 630 631 /** 632 * Creates a period by converting or copying from another object. 633 * <p> 634 * The recognised object types are defined in 635 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 636 * include ReadablePeriod, ReadableInterval and String. 637 * The String formats are described by {@link ISOPeriodFormat#standard()}. 638 * 639 * @param period period to convert 640 * @param type which set of fields this period supports, null means use converter 641 * @param chrono the chronology to use, null means ISO in default zone 642 * @throws IllegalArgumentException if period is invalid 643 * @throws UnsupportedOperationException if an unsupported field's value is non-zero 644 */ 645 public Period(Object period, PeriodType type, Chronology chrono) { 646 super(period, type, chrono); 647 } 648 649 /** 650 * Constructor used when we trust ourselves. 651 * 652 * @param values the values to use, not null, not cloned 653 * @param type which set of fields this period supports, not null 654 */ 655 private Period(int[] values, PeriodType type) { 656 super(values, type); 657 } 658 659 //----------------------------------------------------------------------- 660 /** 661 * Get this period as an immutable <code>Period</code> object 662 * by returning <code>this</code>. 663 * 664 * @return <code>this</code> 665 */ 666 public Period toPeriod() { 667 return this; 668 } 669 670 //----------------------------------------------------------------------- 671 /** 672 * Gets the years field part of the period. 673 * 674 * @return the number of years in the period, zero if unsupported 675 */ 676 public int getYears() { 677 return getPeriodType().getIndexedField(this, PeriodType.YEAR_INDEX); 678 } 679 680 /** 681 * Gets the months field part of the period. 682 * 683 * @return the number of months in the period, zero if unsupported 684 */ 685 public int getMonths() { 686 return getPeriodType().getIndexedField(this, PeriodType.MONTH_INDEX); 687 } 688 689 /** 690 * Gets the weeks field part of the period. 691 * 692 * @return the number of weeks in the period, zero if unsupported 693 */ 694 public int getWeeks() { 695 return getPeriodType().getIndexedField(this, PeriodType.WEEK_INDEX); 696 } 697 698 /** 699 * Gets the days field part of the period. 700 * 701 * @return the number of days in the period, zero if unsupported 702 */ 703 public int getDays() { 704 return getPeriodType().getIndexedField(this, PeriodType.DAY_INDEX); 705 } 706 707 //----------------------------------------------------------------------- 708 /** 709 * Gets the hours field part of the period. 710 * 711 * @return the number of hours in the period, zero if unsupported 712 */ 713 public int getHours() { 714 return getPeriodType().getIndexedField(this, PeriodType.HOUR_INDEX); 715 } 716 717 /** 718 * Gets the minutes field part of the period. 719 * 720 * @return the number of minutes in the period, zero if unsupported 721 */ 722 public int getMinutes() { 723 return getPeriodType().getIndexedField(this, PeriodType.MINUTE_INDEX); 724 } 725 726 /** 727 * Gets the seconds field part of the period. 728 * 729 * @return the number of seconds in the period, zero if unsupported 730 */ 731 public int getSeconds() { 732 return getPeriodType().getIndexedField(this, PeriodType.SECOND_INDEX); 733 } 734 735 /** 736 * Gets the millis field part of the period. 737 * 738 * @return the number of millis in the period, zero if unsupported 739 */ 740 public int getMillis() { 741 return getPeriodType().getIndexedField(this, PeriodType.MILLI_INDEX); 742 } 743 744 //----------------------------------------------------------------------- 745 /** 746 * Creates a new Period instance with the same field values but 747 * different PeriodType. 748 * <p> 749 * This period instance is immutable and unaffected by this method call. 750 * 751 * @param type the period type to use, null means standard 752 * @return the new period instance 753 * @throws IllegalArgumentException if the new period won't accept all of the current fields 754 */ 755 public Period withPeriodType(PeriodType type) { 756 type = DateTimeUtils.getPeriodType(type); 757 if (type.equals(getPeriodType())) { 758 return this; 759 } 760 return new Period(this, type); 761 } 762 763 /** 764 * Creates a new Period instance with the fields from the specified period 765 * copied on top of those from this period. 766 * <p> 767 * This period instance is immutable and unaffected by this method call. 768 * 769 * @param period the period to copy from, null ignored 770 * @return the new period instance 771 * @throws IllegalArgumentException if a field type is unsupported 772 */ 773 public Period withFields(ReadablePeriod period) { 774 if (period == null) { 775 return this; 776 } 777 int[] newValues = getValues(); // cloned 778 newValues = super.mergePeriodInto(newValues, period); 779 return new Period(newValues, getPeriodType()); 780 } 781 782 //----------------------------------------------------------------------- 783 /** 784 * Creates a new Period instance with the specified field set to a new value. 785 * <p> 786 * This period instance is immutable and unaffected by this method call. 787 * 788 * @param field the field to set, not null 789 * @param value the value to set to 790 * @return the new period instance 791 * @throws IllegalArgumentException if the field type is null or unsupported 792 */ 793 public Period withField(DurationFieldType field, int value) { 794 if (field == null) { 795 throw new IllegalArgumentException("Field must not be null"); 796 } 797 int[] newValues = getValues(); // cloned 798 super.setFieldInto(newValues, field, value); 799 return new Period(newValues, getPeriodType()); 800 } 801 802 /** 803 * Creates a new Period instance with the valueToAdd added to the specified field. 804 * <p> 805 * This period instance is immutable and unaffected by this method call. 806 * 807 * @param field the field to set, not null 808 * @param value the value to add 809 * @return the new period instance 810 * @throws IllegalArgumentException if the field type is null or unsupported 811 */ 812 public Period withFieldAdded(DurationFieldType field, int value) { 813 if (field == null) { 814 throw new IllegalArgumentException("Field must not be null"); 815 } 816 if (value == 0) { 817 return this; 818 } 819 int[] newValues = getValues(); // cloned 820 super.addFieldInto(newValues, field, value); 821 return new Period(newValues, getPeriodType()); 822 } 823 824 //----------------------------------------------------------------------- 825 /** 826 * Returns a new period with the specified number of years. 827 * <p> 828 * This period instance is immutable and unaffected by this method call. 829 * 830 * @param years the amount of years to add, may be negative 831 * @return the new period with the increased years 832 * @throws UnsupportedOperationException if the field is not supported 833 */ 834 public Period withYears(int years) { 835 int[] values = getValues(); // cloned 836 getPeriodType().setIndexedField(this, PeriodType.YEAR_INDEX, values, years); 837 return new Period(values, getPeriodType()); 838 } 839 840 /** 841 * Returns a new period with the specified number of months. 842 * <p> 843 * This period instance is immutable and unaffected by this method call. 844 * 845 * @param months the amount of months to add, may be negative 846 * @return the new period with the increased months 847 * @throws UnsupportedOperationException if the field is not supported 848 */ 849 public Period withMonths(int months) { 850 int[] values = getValues(); // cloned 851 getPeriodType().setIndexedField(this, PeriodType.MONTH_INDEX, values, months); 852 return new Period(values, getPeriodType()); 853 } 854 855 /** 856 * Returns a new period with the specified number of weeks. 857 * <p> 858 * This period instance is immutable and unaffected by this method call. 859 * 860 * @param weeks the amount of weeks to add, may be negative 861 * @return the new period with the increased weeks 862 * @throws UnsupportedOperationException if the field is not supported 863 */ 864 public Period withWeeks(int weeks) { 865 int[] values = getValues(); // cloned 866 getPeriodType().setIndexedField(this, PeriodType.WEEK_INDEX, values, weeks); 867 return new Period(values, getPeriodType()); 868 } 869 870 /** 871 * Returns a new period with the specified number of days. 872 * <p> 873 * This period instance is immutable and unaffected by this method call. 874 * 875 * @param days the amount of days to add, may be negative 876 * @return the new period with the increased days 877 * @throws UnsupportedOperationException if the field is not supported 878 */ 879 public Period withDays(int days) { 880 int[] values = getValues(); // cloned 881 getPeriodType().setIndexedField(this, PeriodType.DAY_INDEX, values, days); 882 return new Period(values, getPeriodType()); 883 } 884 885 /** 886 * Returns a new period with the specified number of hours. 887 * <p> 888 * This period instance is immutable and unaffected by this method call. 889 * 890 * @param hours the amount of hours to add, may be negative 891 * @return the new period with the increased hours 892 * @throws UnsupportedOperationException if the field is not supported 893 */ 894 public Period withHours(int hours) { 895 int[] values = getValues(); // cloned 896 getPeriodType().setIndexedField(this, PeriodType.HOUR_INDEX, values, hours); 897 return new Period(values, getPeriodType()); 898 } 899 900 /** 901 * Returns a new period with the specified number of minutes. 902 * <p> 903 * This period instance is immutable and unaffected by this method call. 904 * 905 * @param minutes the amount of minutes to add, may be negative 906 * @return the new period with the increased minutes 907 * @throws UnsupportedOperationException if the field is not supported 908 */ 909 public Period withMinutes(int minutes) { 910 int[] values = getValues(); // cloned 911 getPeriodType().setIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes); 912 return new Period(values, getPeriodType()); 913 } 914 915 /** 916 * Returns a new period with the specified number of seconds. 917 * <p> 918 * This period instance is immutable and unaffected by this method call. 919 * 920 * @param seconds the amount of seconds to add, may be negative 921 * @return the new period with the increased seconds 922 * @throws UnsupportedOperationException if the field is not supported 923 */ 924 public Period withSeconds(int seconds) { 925 int[] values = getValues(); // cloned 926 getPeriodType().setIndexedField(this, PeriodType.SECOND_INDEX, values, seconds); 927 return new Period(values, getPeriodType()); 928 } 929 930 /** 931 * Returns a new period with the specified number of millis. 932 * <p> 933 * This period instance is immutable and unaffected by this method call. 934 * 935 * @param millis the amount of millis to add, may be negative 936 * @return the new period with the increased millis 937 * @throws UnsupportedOperationException if the field is not supported 938 */ 939 public Period withMillis(int millis) { 940 int[] values = getValues(); // cloned 941 getPeriodType().setIndexedField(this, PeriodType.MILLI_INDEX, values, millis); 942 return new Period(values, getPeriodType()); 943 } 944 945 //----------------------------------------------------------------------- 946 /** 947 * Returns a new period with the specified period added. 948 * <p> 949 * Each field of the period is added separately. Thus a period of 950 * 2 hours 30 minutes plus 3 hours 40 minutes will produce a result 951 * of 5 hours 70 minutes - see {@link #normalizedStandard()}. 952 * <p> 953 * If the period being added contains a non-zero amount for a field that 954 * is not supported in this period then an exception is thrown. 955 * <p> 956 * This period instance is immutable and unaffected by this method call. 957 * 958 * @param period the period to add, null adds zero and returns this 959 * @return the new updated period 960 * @throws UnsupportedOperationException if any field is not supported 961 * @since 1.5 962 */ 963 public Period plus(ReadablePeriod period) { 964 if (period == null) { 965 return this; 966 } 967 int[] values = getValues(); // cloned 968 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, period.get(DurationFieldType.YEARS_TYPE)); 969 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, period.get(DurationFieldType.MONTHS_TYPE)); 970 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, period.get(DurationFieldType.WEEKS_TYPE)); 971 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, period.get(DurationFieldType.DAYS_TYPE)); 972 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, period.get(DurationFieldType.HOURS_TYPE)); 973 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, period.get(DurationFieldType.MINUTES_TYPE)); 974 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, period.get(DurationFieldType.SECONDS_TYPE)); 975 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, period.get(DurationFieldType.MILLIS_TYPE)); 976 return new Period(values, getPeriodType()); 977 } 978 979 //----------------------------------------------------------------------- 980 /** 981 * Returns a new period with the specified number of years added. 982 * <p> 983 * This period instance is immutable and unaffected by this method call. 984 * 985 * @param years the amount of years to add, may be negative 986 * @return the new period with the increased years 987 * @throws UnsupportedOperationException if the field is not supported 988 */ 989 public Period plusYears(int years) { 990 if (years == 0) { 991 return this; 992 } 993 int[] values = getValues(); // cloned 994 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, years); 995 return new Period(values, getPeriodType()); 996 } 997 998 /** 999 * Returns a new period plus the specified number of months added. 1000 * <p> 1001 * This period instance is immutable and unaffected by this method call. 1002 * 1003 * @param months the amount of months to add, may be negative 1004 * @return the new period plus the increased months 1005 * @throws UnsupportedOperationException if the field is not supported 1006 */ 1007 public Period plusMonths(int months) { 1008 if (months == 0) { 1009 return this; 1010 } 1011 int[] values = getValues(); // cloned 1012 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, months); 1013 return new Period(values, getPeriodType()); 1014 } 1015 1016 /** 1017 * Returns a new period plus the specified number of weeks added. 1018 * <p> 1019 * This period instance is immutable and unaffected by this method call. 1020 * 1021 * @param weeks the amount of weeks to add, may be negative 1022 * @return the new period plus the increased weeks 1023 * @throws UnsupportedOperationException if the field is not supported 1024 */ 1025 public Period plusWeeks(int weeks) { 1026 if (weeks == 0) { 1027 return this; 1028 } 1029 int[] values = getValues(); // cloned 1030 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, weeks); 1031 return new Period(values, getPeriodType()); 1032 } 1033 1034 /** 1035 * Returns a new period plus the specified number of days added. 1036 * <p> 1037 * This period instance is immutable and unaffected by this method call. 1038 * 1039 * @param days the amount of days to add, may be negative 1040 * @return the new period plus the increased days 1041 * @throws UnsupportedOperationException if the field is not supported 1042 */ 1043 public Period plusDays(int days) { 1044 if (days == 0) { 1045 return this; 1046 } 1047 int[] values = getValues(); // cloned 1048 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, days); 1049 return new Period(values, getPeriodType()); 1050 } 1051 1052 /** 1053 * Returns a new period plus the specified number of hours added. 1054 * <p> 1055 * This period instance is immutable and unaffected by this method call. 1056 * 1057 * @param hours the amount of hours to add, may be negative 1058 * @return the new period plus the increased hours 1059 * @throws UnsupportedOperationException if the field is not supported 1060 */ 1061 public Period plusHours(int hours) { 1062 if (hours == 0) { 1063 return this; 1064 } 1065 int[] values = getValues(); // cloned 1066 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, hours); 1067 return new Period(values, getPeriodType()); 1068 } 1069 1070 /** 1071 * Returns a new period plus the specified number of minutes added. 1072 * <p> 1073 * This period instance is immutable and unaffected by this method call. 1074 * 1075 * @param minutes the amount of minutes to add, may be negative 1076 * @return the new period plus the increased minutes 1077 * @throws UnsupportedOperationException if the field is not supported 1078 */ 1079 public Period plusMinutes(int minutes) { 1080 if (minutes == 0) { 1081 return this; 1082 } 1083 int[] values = getValues(); // cloned 1084 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes); 1085 return new Period(values, getPeriodType()); 1086 } 1087 1088 /** 1089 * Returns a new period plus the specified number of seconds added. 1090 * <p> 1091 * This period instance is immutable and unaffected by this method call. 1092 * 1093 * @param seconds the amount of seconds to add, may be negative 1094 * @return the new period plus the increased seconds 1095 * @throws UnsupportedOperationException if the field is not supported 1096 */ 1097 public Period plusSeconds(int seconds) { 1098 if (seconds == 0) { 1099 return this; 1100 } 1101 int[] values = getValues(); // cloned 1102 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, seconds); 1103 return new Period(values, getPeriodType()); 1104 } 1105 1106 /** 1107 * Returns a new period plus the specified number of millis added. 1108 * <p> 1109 * This period instance is immutable and unaffected by this method call. 1110 * 1111 * @param millis the amount of millis to add, may be negative 1112 * @return the new period plus the increased millis 1113 * @throws UnsupportedOperationException if the field is not supported 1114 */ 1115 public Period plusMillis(int millis) { 1116 if (millis == 0) { 1117 return this; 1118 } 1119 int[] values = getValues(); // cloned 1120 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, millis); 1121 return new Period(values, getPeriodType()); 1122 } 1123 1124 //----------------------------------------------------------------------- 1125 /** 1126 * Returns a new period with the specified period subtracted. 1127 * <p> 1128 * Each field of the period is subtracted separately. Thus a period of 1129 * 3 hours 30 minutes minus 2 hours 40 minutes will produce a result 1130 * of 1 hour and -10 minutes - see {@link #normalizedStandard()}. 1131 * <p> 1132 * If the period being added contains a non-zero amount for a field that 1133 * is not supported in this period then an exception is thrown. 1134 * <p> 1135 * This period instance is immutable and unaffected by this method call. 1136 * 1137 * @param period the period to add, null adds zero and returns this 1138 * @return the new updated period 1139 * @throws UnsupportedOperationException if any field is not supported 1140 * @since 1.5 1141 */ 1142 public Period minus(ReadablePeriod period) { 1143 if (period == null) { 1144 return this; 1145 } 1146 int[] values = getValues(); // cloned 1147 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, -period.get(DurationFieldType.YEARS_TYPE)); 1148 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, -period.get(DurationFieldType.MONTHS_TYPE)); 1149 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, -period.get(DurationFieldType.WEEKS_TYPE)); 1150 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, -period.get(DurationFieldType.DAYS_TYPE)); 1151 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, -period.get(DurationFieldType.HOURS_TYPE)); 1152 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, -period.get(DurationFieldType.MINUTES_TYPE)); 1153 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, -period.get(DurationFieldType.SECONDS_TYPE)); 1154 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, -period.get(DurationFieldType.MILLIS_TYPE)); 1155 return new Period(values, getPeriodType()); 1156 } 1157 1158 //----------------------------------------------------------------------- 1159 /** 1160 * Returns a new period with the specified number of years taken away. 1161 * <p> 1162 * This period instance is immutable and unaffected by this method call. 1163 * 1164 * @param years the amount of years to take away, may be negative 1165 * @return the new period with the increased years 1166 * @throws UnsupportedOperationException if the field is not supported 1167 */ 1168 public Period minusYears(int years) { 1169 return plusYears(-years); 1170 } 1171 1172 /** 1173 * Returns a new period minus the specified number of months taken away. 1174 * <p> 1175 * This period instance is immutable and unaffected by this method call. 1176 * 1177 * @param months the amount of months to take away, may be negative 1178 * @return the new period minus the increased months 1179 * @throws UnsupportedOperationException if the field is not supported 1180 */ 1181 public Period minusMonths(int months) { 1182 return plusMonths(-months); 1183 } 1184 1185 /** 1186 * Returns a new period minus the specified number of weeks taken away. 1187 * <p> 1188 * This period instance is immutable and unaffected by this method call. 1189 * 1190 * @param weeks the amount of weeks to take away, may be negative 1191 * @return the new period minus the increased weeks 1192 * @throws UnsupportedOperationException if the field is not supported 1193 */ 1194 public Period minusWeeks(int weeks) { 1195 return plusWeeks(-weeks); 1196 } 1197 1198 /** 1199 * Returns a new period minus the specified number of days taken away. 1200 * <p> 1201 * This period instance is immutable and unaffected by this method call. 1202 * 1203 * @param days the amount of days to take away, may be negative 1204 * @return the new period minus the increased days 1205 * @throws UnsupportedOperationException if the field is not supported 1206 */ 1207 public Period minusDays(int days) { 1208 return plusDays(-days); 1209 } 1210 1211 /** 1212 * Returns a new period minus the specified number of hours taken away. 1213 * <p> 1214 * This period instance is immutable and unaffected by this method call. 1215 * 1216 * @param hours the amount of hours to take away, may be negative 1217 * @return the new period minus the increased hours 1218 * @throws UnsupportedOperationException if the field is not supported 1219 */ 1220 public Period minusHours(int hours) { 1221 return plusHours(-hours); 1222 } 1223 1224 /** 1225 * Returns a new period minus the specified number of minutes taken away. 1226 * <p> 1227 * This period instance is immutable and unaffected by this method call. 1228 * 1229 * @param minutes the amount of minutes to take away, may be negative 1230 * @return the new period minus the increased minutes 1231 * @throws UnsupportedOperationException if the field is not supported 1232 */ 1233 public Period minusMinutes(int minutes) { 1234 return plusMinutes(-minutes); 1235 } 1236 1237 /** 1238 * Returns a new period minus the specified number of seconds taken away. 1239 * <p> 1240 * This period instance is immutable and unaffected by this method call. 1241 * 1242 * @param seconds the amount of seconds to take away, may be negative 1243 * @return the new period minus the increased seconds 1244 * @throws UnsupportedOperationException if the field is not supported 1245 */ 1246 public Period minusSeconds(int seconds) { 1247 return plusSeconds(-seconds); 1248 } 1249 1250 /** 1251 * Returns a new period minus the specified number of millis taken away. 1252 * <p> 1253 * This period instance is immutable and unaffected by this method call. 1254 * 1255 * @param millis the amount of millis to take away, may be negative 1256 * @return the new period minus the increased millis 1257 * @throws UnsupportedOperationException if the field is not supported 1258 */ 1259 public Period minusMillis(int millis) { 1260 return plusMillis(-millis); 1261 } 1262 1263 //----------------------------------------------------------------------- 1264 /** 1265 * Converts this period to a period in weeks assuming a 1266 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1267 * <p> 1268 * This method allows you to convert between different types of period. 1269 * However to achieve this it makes the assumption that all 1270 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1271 * all minutes are 60 seconds. This is not true when daylight savings time 1272 * is considered, and may also not be true for some unusual chronologies. 1273 * However, it is included as it is a useful operation for many 1274 * applications and business rules. 1275 * <p> 1276 * If the period contains years or months, an exception will be thrown. 1277 * 1278 * @return a period representing the number of standard weeks in this period 1279 * @throws UnsupportedOperationException if the period contains years or months 1280 * @throws ArithmeticException if the number of weeks is too large to be represented 1281 * @since 1.5 1282 */ 1283 public Weeks toStandardWeeks() { 1284 checkYearsAndMonths("Weeks"); 1285 long millis = getMillis(); // assign to a long 1286 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; 1287 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; 1288 millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; 1289 millis += ((long) getDays()) * DateTimeConstants.MILLIS_PER_DAY; 1290 long weeks = ((long) getWeeks()) + millis / DateTimeConstants.MILLIS_PER_WEEK; 1291 return Weeks.weeks(FieldUtils.safeToInt(weeks)); 1292 } 1293 1294 /** 1295 * Converts this period to a period in days assuming a 1296 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1297 * <p> 1298 * This method allows you to convert between different types of period. 1299 * However to achieve this it makes the assumption that all 1300 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1301 * all minutes are 60 seconds. This is not true when daylight savings time 1302 * is considered, and may also not be true for some unusual chronologies. 1303 * However, it is included as it is a useful operation for many 1304 * applications and business rules. 1305 * <p> 1306 * If the period contains years or months, an exception will be thrown. 1307 * 1308 * @return a period representing the number of standard days in this period 1309 * @throws UnsupportedOperationException if the period contains years or months 1310 * @throws ArithmeticException if the number of days is too large to be represented 1311 * @since 1.5 1312 */ 1313 public Days toStandardDays() { 1314 checkYearsAndMonths("Days"); 1315 long millis = getMillis(); // assign to a long 1316 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; 1317 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; 1318 millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; 1319 long days = millis / DateTimeConstants.MILLIS_PER_DAY; 1320 days = FieldUtils.safeAdd(days, getDays()); 1321 days = FieldUtils.safeAdd(days, ((long) getWeeks()) * ((long) DateTimeConstants.DAYS_PER_WEEK)); 1322 return Days.days(FieldUtils.safeToInt(days)); 1323 } 1324 1325 /** 1326 * Converts this period to a period in hours assuming a 1327 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1328 * <p> 1329 * This method allows you to convert between different types of period. 1330 * However to achieve this it makes the assumption that all 1331 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1332 * all minutes are 60 seconds. This is not true when daylight savings time 1333 * is considered, and may also not be true for some unusual chronologies. 1334 * However, it is included as it is a useful operation for many 1335 * applications and business rules. 1336 * <p> 1337 * If the period contains years or months, an exception will be thrown. 1338 * 1339 * @return a period representing the number of standard hours in this period 1340 * @throws UnsupportedOperationException if the period contains years or months 1341 * @throws ArithmeticException if the number of hours is too large to be represented 1342 * @since 1.5 1343 */ 1344 public Hours toStandardHours() { 1345 checkYearsAndMonths("Hours"); 1346 long millis = getMillis(); // assign to a long 1347 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; 1348 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; 1349 long hours = millis / DateTimeConstants.MILLIS_PER_HOUR; 1350 hours = FieldUtils.safeAdd(hours, getHours()); 1351 hours = FieldUtils.safeAdd(hours, ((long) getDays()) * ((long) DateTimeConstants.HOURS_PER_DAY)); 1352 hours = FieldUtils.safeAdd(hours, ((long) getWeeks()) * ((long) DateTimeConstants.HOURS_PER_WEEK)); 1353 return Hours.hours(FieldUtils.safeToInt(hours)); 1354 } 1355 1356 /** 1357 * Converts this period to a period in minutes assuming a 1358 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1359 * <p> 1360 * This method allows you to convert between different types of period. 1361 * However to achieve this it makes the assumption that all 1362 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1363 * all minutes are 60 seconds. This is not true when daylight savings time 1364 * is considered, and may also not be true for some unusual chronologies. 1365 * However, it is included as it is a useful operation for many 1366 * applications and business rules. 1367 * <p> 1368 * If the period contains years or months, an exception will be thrown. 1369 * 1370 * @return a period representing the number of standard minutes in this period 1371 * @throws UnsupportedOperationException if the period contains years or months 1372 * @throws ArithmeticException if the number of minutes is too large to be represented 1373 * @since 1.5 1374 */ 1375 public Minutes toStandardMinutes() { 1376 checkYearsAndMonths("Minutes"); 1377 long millis = getMillis(); // assign to a long 1378 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; 1379 long minutes = millis / DateTimeConstants.MILLIS_PER_MINUTE; 1380 minutes = FieldUtils.safeAdd(minutes, getMinutes()); 1381 minutes = FieldUtils.safeAdd(minutes, ((long) getHours()) * ((long) DateTimeConstants.MINUTES_PER_HOUR)); 1382 minutes = FieldUtils.safeAdd(minutes, ((long) getDays()) * ((long) DateTimeConstants.MINUTES_PER_DAY)); 1383 minutes = FieldUtils.safeAdd(minutes, ((long) getWeeks()) * ((long) DateTimeConstants.MINUTES_PER_WEEK)); 1384 return Minutes.minutes(FieldUtils.safeToInt(minutes)); 1385 } 1386 1387 /** 1388 * Converts this period to a period in seconds assuming a 1389 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1390 * <p> 1391 * This method allows you to convert between different types of period. 1392 * However to achieve this it makes the assumption that all 1393 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1394 * all minutes are 60 seconds. This is not true when daylight savings time 1395 * is considered, and may also not be true for some unusual chronologies. 1396 * However, it is included as it is a useful operation for many 1397 * applications and business rules. 1398 * <p> 1399 * If the period contains years or months, an exception will be thrown. 1400 * 1401 * @return a period representing the number of standard seconds in this period 1402 * @throws UnsupportedOperationException if the period contains years or months 1403 * @throws ArithmeticException if the number of seconds is too large to be represented 1404 * @since 1.5 1405 */ 1406 public Seconds toStandardSeconds() { 1407 checkYearsAndMonths("Seconds"); 1408 long seconds = getMillis() / DateTimeConstants.MILLIS_PER_SECOND; 1409 seconds = FieldUtils.safeAdd(seconds, getSeconds()); 1410 seconds = FieldUtils.safeAdd(seconds, ((long) getMinutes()) * ((long) DateTimeConstants.SECONDS_PER_MINUTE)); 1411 seconds = FieldUtils.safeAdd(seconds, ((long) getHours()) * ((long) DateTimeConstants.SECONDS_PER_HOUR)); 1412 seconds = FieldUtils.safeAdd(seconds, ((long) getDays()) * ((long) DateTimeConstants.SECONDS_PER_DAY)); 1413 seconds = FieldUtils.safeAdd(seconds, ((long) getWeeks()) * ((long) DateTimeConstants.SECONDS_PER_WEEK)); 1414 return Seconds.seconds(FieldUtils.safeToInt(seconds)); 1415 } 1416 1417 //----------------------------------------------------------------------- 1418 /** 1419 * Converts this period to a duration assuming a 1420 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1421 * <p> 1422 * This method allows you to convert from a period to a duration. 1423 * However to achieve this it makes the assumption that all 1424 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and 1425 * all minutes are 60 seconds. This is not true when daylight savings time 1426 * is considered, and may also not be true for some unusual chronologies. 1427 * However, it is included as it is a useful operation for many 1428 * applications and business rules. 1429 * <p> 1430 * If the period contains years or months, an exception will be thrown. 1431 * 1432 * @return a duration equivalent to this period 1433 * @throws UnsupportedOperationException if the period contains years or months 1434 * @since 1.5 1435 */ 1436 public Duration toStandardDuration() { 1437 checkYearsAndMonths("Duration"); 1438 long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs 1439 millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND)); 1440 millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE)); 1441 millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR)); 1442 millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY)); 1443 millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK)); 1444 return new Duration(millis); 1445 } 1446 1447 /** 1448 * Check that there are no years or months in the period. 1449 * 1450 * @param destintionType the destination type, not null 1451 * @throws UnsupportedOperationException if the period contains years or months 1452 */ 1453 private void checkYearsAndMonths(String destintionType) { 1454 if (getMonths() != 0) { 1455 throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains months and months vary in length"); 1456 } 1457 if (getYears() != 0) { 1458 throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains years and years vary in length"); 1459 } 1460 } 1461 1462 //----------------------------------------------------------------------- 1463 /** 1464 * Normalizes this period using standard rules, assuming a 12 month year, 1465 * 7 day week, 24 hour day, 60 minute hour and 60 second minute. 1466 * <p> 1467 * This method allows you to normalize a period. 1468 * However to achieve this it makes the assumption that all years are 1469 * 12 months, all weeks are 7 days, all days are 24 hours, 1470 * all hours are 60 minutes and all minutes are 60 seconds. This is not 1471 * true when daylight savings time is considered, and may also not be true 1472 * for some chronologies. However, it is included as it is a useful operation 1473 * for many applications and business rules. 1474 * <p> 1475 * If the period contains years or months, then the months will be 1476 * normalized to be between 0 and 11. The days field and below will be 1477 * normalized as necessary, however this will not overflow into the months 1478 * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. 1479 * But a period of 1 month 40 days will remain as 1 month 40 days. 1480 * <p> 1481 * The result will always have a <code>PeriodType</code> of standard, thus 1482 * days will be grouped into weeks. 1483 * 1484 * @return a normalized period equivalent to this period 1485 * @throws ArithmeticException if any field is too large to be represented 1486 * @since 1.5 1487 */ 1488 public Period normalizedStandard() { 1489 return normalizedStandard(PeriodType.standard()); 1490 } 1491 1492 //----------------------------------------------------------------------- 1493 /** 1494 * Normalizes this period using standard rules, assuming a 12 month year, 1495 * 7 day week, 24 hour day, 60 minute hour and 60 second minute, 1496 * providing control over how the result is split into fields. 1497 * <p> 1498 * This method allows you to normalize a period. 1499 * However to achieve this it makes the assumption that all years are 1500 * 12 months, all weeks are 7 days, all days are 24 hours, 1501 * all hours are 60 minutes and all minutes are 60 seconds. This is not 1502 * true when daylight savings time is considered, and may also not be true 1503 * for some chronologies. However, it is included as it is a useful operation 1504 * for many applications and business rules. 1505 * <p> 1506 * If the period contains years or months, then the months will be 1507 * normalized to be between 0 and 11. The days field and below will be 1508 * normalized as necessary, however this will not overflow into the months 1509 * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. 1510 * But a period of 1 month 40 days will remain as 1 month 40 days. 1511 * <p> 1512 * The PeriodType parameter controls how the result is created. It allows 1513 * you to omit certain fields from the result if desired. For example, 1514 * you may not want the result to include weeks, in which case you pass 1515 * in <code>PeriodType.yearMonthDayTime()</code>. 1516 * 1517 * @param type the period type of the new period, null means standard type 1518 * @return a normalized period equivalent to this period 1519 * @throws ArithmeticException if any field is too large to be represented 1520 * @throws UnsupportedOperationException if this period contains non-zero 1521 * years or months but the specified period type does not support them 1522 * @since 1.5 1523 */ 1524 public Period normalizedStandard(PeriodType type) { 1525 long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs 1526 millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND)); 1527 millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE)); 1528 millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR)); 1529 millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY)); 1530 millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK)); 1531 Period result = new Period(millis, DateTimeUtils.getPeriodType(type), ISOChronology.getInstanceUTC()); 1532 int years = getYears(); 1533 int months = getMonths(); 1534 if (years != 0 || months != 0) { 1535 years = FieldUtils.safeAdd(years, months / 12); 1536 months = months % 12; 1537 if (years != 0) { 1538 result = result.withYears(years); 1539 } 1540 if (months != 0) { 1541 result = result.withMonths(months); 1542 } 1543 } 1544 return result; 1545 } 1546 1547}