1 | /* |
2 | * Copyright 2001-2006 Stephen Colebourne |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | package org.joda.time; |
17 | |
18 | import java.io.Serializable; |
19 | |
20 | import org.joda.time.base.BasePeriod; |
21 | import org.joda.time.chrono.ISOChronology; |
22 | import org.joda.time.field.FieldUtils; |
23 | import org.joda.time.format.ISOPeriodFormat; |
24 | |
25 | /** |
26 | * An immutable time period specifying a set of duration field values. |
27 | * <p> |
28 | * A time period is divided into a number of fields, such as hours and seconds. |
29 | * Which fields are supported is defined by the PeriodType class. |
30 | * The default is the standard period type, which supports years, months, weeks, days, |
31 | * hours, minutes, seconds and millis. |
32 | * <p> |
33 | * When this time period is added to an instant, the effect is of adding each field in turn. |
34 | * As a result, this takes into account daylight savings time. |
35 | * Adding a time period of 1 day to the day before daylight savings starts will only add |
36 | * 23 hours rather than 24 to ensure that the time remains the same. |
37 | * If this is not the behaviour you want, then see {@link Duration}. |
38 | * <p> |
39 | * The definition of a period also affects the equals method. A period of 1 |
40 | * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. |
41 | * This is because periods represent an abstracted definition of a time period |
42 | * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight |
43 | * savings boundary). To compare the actual duration of two periods, convert |
44 | * both to durations using toDuration, an operation that emphasises that the |
45 | * result may differ according to the date you choose. |
46 | * <p> |
47 | * Period is thread-safe and immutable, provided that the PeriodType is as well. |
48 | * All standard PeriodType classes supplied are thread-safe and immutable. |
49 | * |
50 | * @author Brian S O'Neill |
51 | * @author Stephen Colebourne |
52 | * @since 1.0 |
53 | * @see MutablePeriod |
54 | */ |
55 | public final class Period |
56 | extends BasePeriod |
57 | implements ReadablePeriod, Serializable { |
58 | |
59 | /** |
60 | * A period of zero length and standard period type. |
61 | * @since 1.4 |
62 | */ |
63 | public static final Period ZERO = new Period(); |
64 | |
65 | /** Serialization version */ |
66 | private static final long serialVersionUID = 741052353876488155L; |
67 | |
68 | //----------------------------------------------------------------------- |
69 | /** |
70 | * Create a period with a specified number of years. |
71 | * <p> |
72 | * The standard period type is used, thus you can add other fields such |
73 | * as months or days using the <code>withXxx()</code> methods. |
74 | * For example, <code>Period.years(2).withMonths(6);</code> |
75 | * <p> |
76 | * If you want a year-based period that cannot have other fields added, |
77 | * then you should consider using {@link Years}. |
78 | * |
79 | * @param years the amount of years in this period |
80 | * @return the period |
81 | */ |
82 | public static Period years(int years) { |
83 | return new Period(new int[] {years, 0, 0, 0, 0, 0, 0, 0, 0}, PeriodType.standard()); |
84 | } |
85 | |
86 | /** |
87 | * Create a period with a specified number of months. |
88 | * <p> |
89 | * The standard period type is used, thus you can add other fields such |
90 | * as years or days using the <code>withXxx()</code> methods. |
91 | * For example, <code>Period.months(2).withDays(6);</code> |
92 | * <p> |
93 | * If you want a month-based period that cannot have other fields added, |
94 | * then you should consider using {@link Months}. |
95 | * |
96 | * @param months the amount of months in this period |
97 | * @return the period |
98 | */ |
99 | 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 | } |