59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 */ |
61 */ |
62 package java.time; |
62 package java.time; |
63 |
63 |
64 import static java.time.LocalTime.NANOS_PER_DAY; |
|
65 import static java.time.LocalTime.NANOS_PER_HOUR; |
|
66 import static java.time.LocalTime.NANOS_PER_MINUTE; |
|
67 import static java.time.LocalTime.NANOS_PER_SECOND; |
|
68 import static java.time.temporal.ChronoField.DAY_OF_MONTH; |
|
69 import static java.time.temporal.ChronoField.EPOCH_MONTH; |
|
70 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; |
64 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; |
71 import static java.time.temporal.ChronoField.NANO_OF_DAY; |
|
72 import static java.time.temporal.ChronoField.YEAR; |
|
73 import static java.time.temporal.ChronoUnit.DAYS; |
65 import static java.time.temporal.ChronoUnit.DAYS; |
74 import static java.time.temporal.ChronoUnit.MONTHS; |
66 import static java.time.temporal.ChronoUnit.MONTHS; |
75 import static java.time.temporal.ChronoUnit.NANOS; |
|
76 import static java.time.temporal.ChronoUnit.YEARS; |
67 import static java.time.temporal.ChronoUnit.YEARS; |
77 |
68 |
|
69 import java.io.DataInput; |
|
70 import java.io.DataOutput; |
|
71 import java.io.IOException; |
|
72 import java.io.InvalidObjectException; |
|
73 import java.io.ObjectStreamException; |
78 import java.io.Serializable; |
74 import java.io.Serializable; |
|
75 import java.time.chrono.ChronoLocalDate; |
|
76 import java.time.chrono.Chronology; |
79 import java.time.format.DateTimeParseException; |
77 import java.time.format.DateTimeParseException; |
80 import java.time.temporal.Chrono; |
|
81 import java.time.temporal.ChronoField; |
|
82 import java.time.temporal.ChronoUnit; |
78 import java.time.temporal.ChronoUnit; |
83 import java.time.temporal.Temporal; |
79 import java.time.temporal.Temporal; |
84 import java.time.temporal.TemporalAccessor; |
80 import java.time.temporal.TemporalAmount; |
85 import java.time.temporal.TemporalAdder; |
|
86 import java.time.temporal.TemporalSubtractor; |
|
87 import java.time.temporal.TemporalUnit; |
81 import java.time.temporal.TemporalUnit; |
88 import java.time.temporal.ValueRange; |
82 import java.time.temporal.ValueRange; |
|
83 import java.util.Arrays; |
|
84 import java.util.Collections; |
|
85 import java.util.List; |
89 import java.util.Objects; |
86 import java.util.Objects; |
|
87 import java.util.regex.Matcher; |
|
88 import java.util.regex.Pattern; |
90 |
89 |
91 /** |
90 /** |
92 * A period of time, measured using the most common units, such as '3 Months, 4 Days and 7 Hours'. |
91 * A date-based amount of time, such as '2 years, 3 months and 4 days'. |
93 * <p> |
92 * <p> |
94 * A {@code Period} represents an amount of time measured in terms of the most commonly used units: |
93 * This class models a quantity or amount of time in terms of years, months and days. |
95 * <p><ul> |
94 * See {@link Duration} for the time-based equivalent to this class. |
96 * <li>{@link ChronoUnit#YEARS YEARS}</li> |
95 * <p> |
97 * <li>{@link ChronoUnit#MONTHS MONTHS}</li> |
96 * Durations and period differ in their treatment of daylight savings time |
98 * <li>{@link ChronoUnit#DAYS DAYS}</li> |
97 * when added to {@link ZonedDateTime}. A {@code Duration} will add an exact |
99 * <li>time units with an {@linkplain TemporalUnit#isDurationEstimated() exact duration}</li> |
98 * number of seconds, thus a duration of one day is always exactly 24 hours. |
100 * </ul><p> |
99 * By contrast, a {@code Period} will add a conceptual day, trying to maintain |
101 * The period may be used with any calendar system with the exception is methods with an "ISO" suffix. |
100 * the local time. |
102 * The meaning of a "year" or a "month" is only applied when the object is added to a date. |
101 * <p> |
|
102 * For example, consider adding a period of one day and a duration of one day to |
|
103 * 18:00 on the evening before a daylight savings gap. The {@code Period} will add |
|
104 * the conceptual day and result in a {@code ZonedDateTime} at 18:00 the following day. |
|
105 * By contrast, the {@code Duration} will add exactly 24 hours, resulting in a |
|
106 * {@code ZonedDateTime} at 19:00 the following day (assuming a one hour DST gap). |
|
107 * <p> |
|
108 * The supported units of a period are {@link ChronoUnit#YEARS YEARS}, |
|
109 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. |
|
110 * All three fields are always present, but may be set to zero. |
|
111 * <p> |
|
112 * The period may be used with any calendar system. |
|
113 * The meaning of a "year" or "month" is only applied when the object is added to a date. |
103 * <p> |
114 * <p> |
104 * The period is modeled as a directed amount of time, meaning that individual parts of the |
115 * The period is modeled as a directed amount of time, meaning that individual parts of the |
105 * period may be negative. |
116 * period may be negative. |
|
117 * <p> |
|
118 * The months and years fields may be {@linkplain #normalized() normalized}. |
|
119 * The normalization assumes a 12 month year, so is not appropriate for all calendar systems. |
106 * |
120 * |
107 * <h3>Specification for implementors</h3> |
121 * <h3>Specification for implementors</h3> |
108 * This class is immutable and thread-safe. |
122 * This class is immutable and thread-safe. |
109 * The maximum number of hours that can be stored is about 2.5 million, limited by storing |
|
110 * a single {@code long} nanoseconds for all time units internally. |
|
111 * |
123 * |
112 * @since 1.8 |
124 * @since 1.8 |
113 */ |
125 */ |
114 public final class Period |
126 public final class Period |
115 implements TemporalAdder, TemporalSubtractor, Serializable { |
127 implements TemporalAmount, Serializable { |
116 // maximum hours is 2,562,047 |
|
117 |
128 |
118 /** |
129 /** |
119 * A constant for a period of zero. |
130 * A constant for a period of zero. |
120 */ |
131 */ |
121 public static final Period ZERO = new Period(0, 0, 0, 0); |
132 public static final Period ZERO = new Period(0, 0, 0); |
122 /** |
133 /** |
123 * Serialization version. |
134 * Serialization version. |
124 */ |
135 */ |
125 private static final long serialVersionUID = -8290556941213247973L; |
136 private static final long serialVersionUID = -3587258372562876L; |
|
137 /** |
|
138 * The pattern for parsing. |
|
139 */ |
|
140 private final static Pattern PATTERN = |
|
141 Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); |
|
142 /** |
|
143 * The set of supported units. |
|
144 */ |
|
145 private final static List<TemporalUnit> SUPPORTED_UNITS = |
|
146 Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS)); |
126 |
147 |
127 /** |
148 /** |
128 * The number of years. |
149 * The number of years. |
129 */ |
150 */ |
130 private final int years; |
151 private final int years; |
134 private final int months; |
155 private final int months; |
135 /** |
156 /** |
136 * The number of days. |
157 * The number of days. |
137 */ |
158 */ |
138 private final int days; |
159 private final int days; |
139 /** |
160 |
140 * The number of nanoseconds. |
161 //----------------------------------------------------------------------- |
141 */ |
162 /** |
142 private final long nanos; |
163 * Obtains a {@code Period} representing a number of years. |
143 |
164 * <p> |
144 //----------------------------------------------------------------------- |
165 * The resulting period will have the specified years. |
145 /** |
166 * The months and days units will be zero. |
146 * Obtains a {@code Period} from date-based and time-based fields. |
167 * |
147 * <p> |
168 * @param years the number of years, positive or negative |
148 * This creates an instance based on years, months, days, hours, minutes and seconds. |
169 * @return the period of years, not null |
149 * Within a period, the time fields are always normalized. |
170 */ |
|
171 public static Period ofYears(int years) { |
|
172 return create(years, 0, 0); |
|
173 } |
|
174 |
|
175 /** |
|
176 * Obtains a {@code Period} representing a number of months. |
|
177 * <p> |
|
178 * The resulting period will have the specified months. |
|
179 * The years and days units will be zero. |
|
180 * |
|
181 * @param months the number of months, positive or negative |
|
182 * @return the period of months, not null |
|
183 */ |
|
184 public static Period ofMonths(int months) { |
|
185 return create(0, months, 0); |
|
186 } |
|
187 |
|
188 /** |
|
189 * Obtains a {@code Period} representing a number of days. |
|
190 * <p> |
|
191 * The resulting period will have the specified days. |
|
192 * The years and months units will be zero. |
|
193 * |
|
194 * @param days the number of days, positive or negative |
|
195 * @return the period of days, not null |
|
196 */ |
|
197 public static Period ofDays(int days) { |
|
198 return create(0, 0, days); |
|
199 } |
|
200 |
|
201 //----------------------------------------------------------------------- |
|
202 /** |
|
203 * Obtains a {@code Period} representing a number of years, months and days. |
|
204 * <p> |
|
205 * This creates an instance based on years, months and days. |
150 * |
206 * |
151 * @param years the amount of years, may be negative |
207 * @param years the amount of years, may be negative |
152 * @param months the amount of months, may be negative |
208 * @param months the amount of months, may be negative |
153 * @param days the amount of days, may be negative |
209 * @param days the amount of days, may be negative |
154 * @param hours the amount of hours, may be negative |
210 * @return the period of years, months and days, not null |
155 * @param minutes the amount of minutes, may be negative |
211 */ |
156 * @param seconds the amount of seconds, may be negative |
212 public static Period of(int years, int months, int days) { |
157 * @return the period, not null |
213 return create(years, months, days); |
158 */ |
|
159 public static Period of(int years, int months, int days, int hours, int minutes, int seconds) { |
|
160 return of(years, months, days, hours, minutes, seconds, 0); |
|
161 } |
|
162 |
|
163 /** |
|
164 * Obtains a {@code Period} from date-based and time-based fields. |
|
165 * <p> |
|
166 * This creates an instance based on years, months, days, hours, minutes, seconds and nanoseconds. |
|
167 * Within a period, the time fields are always normalized. |
|
168 * |
|
169 * @param years the amount of years, may be negative |
|
170 * @param months the amount of months, may be negative |
|
171 * @param days the amount of days, may be negative |
|
172 * @param hours the amount of hours, may be negative |
|
173 * @param minutes the amount of minutes, may be negative |
|
174 * @param seconds the amount of seconds, may be negative |
|
175 * @param nanos the amount of nanos, may be negative |
|
176 * @return the period, not null |
|
177 */ |
|
178 public static Period of(int years, int months, int days, int hours, int minutes, int seconds, long nanos) { |
|
179 if ((years | months | days | hours | minutes | seconds | nanos) == 0) { |
|
180 return ZERO; |
|
181 } |
|
182 long totSecs = Math.addExact(hours * 3600L, minutes * 60L) + seconds; |
|
183 long totNanos = Math.addExact(Math.multiplyExact(totSecs, 1_000_000_000L), nanos); |
|
184 return create(years, months, days, totNanos); |
|
185 } |
|
186 |
|
187 //----------------------------------------------------------------------- |
|
188 /** |
|
189 * Obtains a {@code Period} from date-based fields. |
|
190 * <p> |
|
191 * This creates an instance based on years, months and days. |
|
192 * |
|
193 * @param years the amount of years, may be negative |
|
194 * @param months the amount of months, may be negative |
|
195 * @param days the amount of days, may be negative |
|
196 * @return the period, not null |
|
197 */ |
|
198 public static Period ofDate(int years, int months, int days) { |
|
199 return of(years, months, days, 0, 0, 0, 0); |
|
200 } |
|
201 |
|
202 //----------------------------------------------------------------------- |
|
203 /** |
|
204 * Obtains a {@code Period} from time-based fields. |
|
205 * <p> |
|
206 * This creates an instance based on hours, minutes and seconds. |
|
207 * Within a period, the time fields are always normalized. |
|
208 * |
|
209 * @param hours the amount of hours, may be negative |
|
210 * @param minutes the amount of minutes, may be negative |
|
211 * @param seconds the amount of seconds, may be negative |
|
212 * @return the period, not null |
|
213 */ |
|
214 public static Period ofTime(int hours, int minutes, int seconds) { |
|
215 return of(0, 0, 0, hours, minutes, seconds, 0); |
|
216 } |
|
217 |
|
218 /** |
|
219 * Obtains a {@code Period} from time-based fields. |
|
220 * <p> |
|
221 * This creates an instance based on hours, minutes, seconds and nanoseconds. |
|
222 * Within a period, the time fields are always normalized. |
|
223 * |
|
224 * @param hours the amount of hours, may be negative |
|
225 * @param minutes the amount of minutes, may be negative |
|
226 * @param seconds the amount of seconds, may be negative |
|
227 * @param nanos the amount of nanos, may be negative |
|
228 * @return the period, not null |
|
229 */ |
|
230 public static Period ofTime(int hours, int minutes, int seconds, long nanos) { |
|
231 return of(0, 0, 0, hours, minutes, seconds, nanos); |
|
232 } |
|
233 |
|
234 //----------------------------------------------------------------------- |
|
235 /** |
|
236 * Obtains an instance of {@code Period} from a period in the specified unit. |
|
237 * <p> |
|
238 * The parameters represent the two parts of a phrase like '6 Days'. For example: |
|
239 * <pre> |
|
240 * Period.of(3, SECONDS); |
|
241 * Period.of(5, YEARS); |
|
242 * </pre> |
|
243 * The specified unit must be one of the supported units from {@link ChronoUnit}, |
|
244 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an |
|
245 * {@linkplain TemporalUnit#isDurationEstimated() exact duration}. |
|
246 * Other units throw an exception. |
|
247 * |
|
248 * @param amount the amount of the period, measured in terms of the unit, positive or negative |
|
249 * @param unit the unit that the period is measured in, must have an exact duration, not null |
|
250 * @return the period, not null |
|
251 * @throws DateTimeException if the period unit is invalid |
|
252 * @throws ArithmeticException if a numeric overflow occurs |
|
253 */ |
|
254 public static Period of(long amount, TemporalUnit unit) { |
|
255 return ZERO.plus(amount, unit); |
|
256 } |
|
257 |
|
258 //----------------------------------------------------------------------- |
|
259 /** |
|
260 * Obtains a {@code Period} from a {@code Duration}. |
|
261 * <p> |
|
262 * This converts the duration to a period. |
|
263 * Within a period, the time fields are always normalized. |
|
264 * The years, months and days fields will be zero. |
|
265 * <p> |
|
266 * To populate the days field, call {@link #normalizedHoursToDays()} on the created period. |
|
267 * |
|
268 * @param duration the duration to convert, not null |
|
269 * @return the period, not null |
|
270 * @throws ArithmeticException if numeric overflow occurs |
|
271 */ |
|
272 public static Period of(Duration duration) { |
|
273 Objects.requireNonNull(duration, "duration"); |
|
274 if (duration.isZero()) { |
|
275 return ZERO; |
|
276 } |
|
277 return new Period(0, 0, 0, duration.toNanos()); |
|
278 } |
|
279 |
|
280 //----------------------------------------------------------------------- |
|
281 /** |
|
282 * Returns a {@code Period} consisting of the number of years, months, days, |
|
283 * hours, minutes, seconds, and nanoseconds between two {@code TemporalAccessor} instances. |
|
284 * <p> |
|
285 * The start date is included, but the end date is not. Only whole years count. |
|
286 * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days. |
|
287 * <p> |
|
288 * This method examines the {@link ChronoField fields} {@code YEAR}, {@code MONTH_OF_YEAR}, |
|
289 * {@code DAY_OF_MONTH} and {@code NANO_OF_DAY} |
|
290 * The difference between each of the fields is calculated independently from the others. |
|
291 * At least one of the four fields must be present. |
|
292 * <p> |
|
293 * The four units are typically retained without normalization. |
|
294 * However, years and months are normalized if the range of months is fixed, as it is with ISO. |
|
295 * <p> |
|
296 * The result of this method can be a negative period if the end is before the start. |
|
297 * The negative sign can be different in each of the four major units. |
|
298 * |
|
299 * @param start the start date, inclusive, not null |
|
300 * @param end the end date, exclusive, not null |
|
301 * @return the period between the date-times, not null |
|
302 * @throws DateTimeException if the two date-times do have similar available fields |
|
303 * @throws ArithmeticException if numeric overflow occurs |
|
304 */ |
|
305 public static Period between(TemporalAccessor start, TemporalAccessor end) { |
|
306 if (Chrono.from(start).equals(Chrono.from(end)) == false) { |
|
307 throw new DateTimeException("Unable to calculate period as date-times have different chronologies"); |
|
308 } |
|
309 int years = 0; |
|
310 int months = 0; |
|
311 int days = 0; |
|
312 long nanos = 0; |
|
313 boolean valid = false; |
|
314 if (start.isSupported(YEAR)) { |
|
315 years = Math.toIntExact(Math.subtractExact(end.getLong(YEAR), start.getLong(YEAR))); |
|
316 valid = true; |
|
317 } |
|
318 if (start.isSupported(MONTH_OF_YEAR)) { |
|
319 months = Math.toIntExact(Math.subtractExact(end.getLong(MONTH_OF_YEAR), start.getLong(MONTH_OF_YEAR))); |
|
320 ValueRange startRange = Chrono.from(start).range(MONTH_OF_YEAR); |
|
321 ValueRange endRange = Chrono.from(end).range(MONTH_OF_YEAR); |
|
322 if (startRange.isFixed() && startRange.isIntValue() && startRange.equals(endRange)) { |
|
323 int monthCount = (int) (startRange.getMaximum() - startRange.getMinimum() + 1); |
|
324 long totMonths = ((long) months) + years * monthCount; |
|
325 months = (int) (totMonths % monthCount); |
|
326 years = Math.toIntExact(totMonths / monthCount); |
|
327 } |
|
328 valid = true; |
|
329 } |
|
330 if (start.isSupported(DAY_OF_MONTH)) { |
|
331 days = Math.toIntExact(Math.subtractExact(end.getLong(DAY_OF_MONTH), start.getLong(DAY_OF_MONTH))); |
|
332 valid = true; |
|
333 } |
|
334 if (start.isSupported(NANO_OF_DAY)) { |
|
335 nanos = Math.subtractExact(end.getLong(NANO_OF_DAY), start.getLong(NANO_OF_DAY)); |
|
336 valid = true; |
|
337 } |
|
338 if (valid == false) { |
|
339 throw new DateTimeException("Unable to calculate period as date-times do not have any valid fields"); |
|
340 } |
|
341 return create(years, months, days, nanos); |
|
342 } |
214 } |
343 |
215 |
344 //----------------------------------------------------------------------- |
216 //----------------------------------------------------------------------- |
345 /** |
217 /** |
346 * Obtains a {@code Period} consisting of the number of years, months, |
218 * Obtains a {@code Period} consisting of the number of years, months, |
356 * The result of this method can be a negative period if the end is before the start. |
228 * The result of this method can be a negative period if the end is before the start. |
357 * The negative sign will be the same in each of year, month and day. |
229 * The negative sign will be the same in each of year, month and day. |
358 * |
230 * |
359 * @param startDate the start date, inclusive, not null |
231 * @param startDate the start date, inclusive, not null |
360 * @param endDate the end date, exclusive, not null |
232 * @param endDate the end date, exclusive, not null |
361 * @return the period between the dates, not null |
233 * @return the period between this date and the end date, not null |
362 * @throws ArithmeticException if numeric overflow occurs |
234 * @see ChronoLocalDate#periodUntil(ChronoLocalDate) |
363 */ |
235 */ |
364 public static Period betweenISO(LocalDate startDate, LocalDate endDate) { |
236 public static Period between(LocalDate startDate, LocalDate endDate) { |
365 long startMonth = startDate.getLong(EPOCH_MONTH); |
237 return startDate.periodUntil(endDate); |
366 long endMonth = endDate.getLong(EPOCH_MONTH); |
238 } |
367 long totalMonths = endMonth - startMonth; // safe |
239 |
368 int days = endDate.getDayOfMonth() - startDate.getDayOfMonth(); |
240 //----------------------------------------------------------------------- |
369 if (totalMonths > 0 && days < 0) { |
241 /** |
370 totalMonths--; |
242 * Obtains a {@code Period} from a text string such as {@code PnYnMnD}. |
371 LocalDate calcDate = startDate.plusMonths(totalMonths); |
|
372 days = (int) (endDate.toEpochDay() - calcDate.toEpochDay()); // safe |
|
373 } else if (totalMonths < 0 && days > 0) { |
|
374 totalMonths++; |
|
375 days -= endDate.lengthOfMonth(); |
|
376 } |
|
377 long years = totalMonths / 12; // safe |
|
378 int months = (int) (totalMonths % 12); // safe |
|
379 return ofDate(Math.toIntExact(years), months, days); |
|
380 } |
|
381 |
|
382 //----------------------------------------------------------------------- |
|
383 /** |
|
384 * Obtains a {@code Period} consisting of the number of hours, minutes, |
|
385 * seconds and nanoseconds between two times. |
|
386 * <p> |
|
387 * The start time is included, but the end time is not. |
|
388 * The period is calculated from the difference between the nano-of-day values |
|
389 * of the two times. For example, from {@code 13:45:00} to {@code 14:50:30.123456789} |
|
390 * is {@code P1H5M30.123456789S}. |
|
391 * <p> |
|
392 * The result of this method can be a negative period if the end is before the start. |
|
393 * |
|
394 * @param startTime the start time, inclusive, not null |
|
395 * @param endTime the end time, exclusive, not null |
|
396 * @return the period between the times, not null |
|
397 * @throws ArithmeticException if numeric overflow occurs |
|
398 */ |
|
399 public static Period betweenISO(LocalTime startTime, LocalTime endTime) { |
|
400 return create(0, 0, 0, endTime.toNanoOfDay() - startTime.toNanoOfDay()); |
|
401 } |
|
402 |
|
403 //----------------------------------------------------------------------- |
|
404 /** |
|
405 * Obtains a {@code Period} from a text string such as {@code PnYnMnDTnHnMn.nS}. |
|
406 * <p> |
243 * <p> |
407 * This will parse the string produced by {@code toString()} which is |
244 * This will parse the string produced by {@code toString()} which is |
408 * a subset of the ISO-8601 period format {@code PnYnMnDTnHnMn.nS}. |
245 * based on the ISO-8601 period format {@code PnYnMnD}. |
409 * <p> |
246 * <p> |
410 * The string consists of a series of numbers with a suffix identifying their meaning. |
247 * The string starts with an optional sign, denoted by the ASCII negative |
411 * The values, and suffixes, must be in the sequence year, month, day, hour, minute, second. |
248 * or positive symbol. If negative, the whole period is negated. |
412 * Any of the number/suffix pairs may be omitted providing at least one is present. |
249 * The ASCII letter "P" is next in upper or lower case. |
413 * If the period is zero, the value is normally represented as {@code PT0S}. |
250 * There are then three sections, each consisting of a number and a suffix. |
414 * The numbers must consist of ASCII digits. |
251 * At least one of the three sections must be present. |
415 * Any of the numbers may be negative. Negative zero is not accepted. |
252 * The sections have suffixes in ASCII of "Y", "M" and "D" for |
416 * The number of nanoseconds is expressed as an optional fraction of the seconds. |
253 * years, months and days, accepted in upper or lower case. |
417 * There must be at least one digit before any decimal point. |
254 * The suffixes must occur in order. |
418 * There must be between 1 and 9 inclusive digits after any decimal point. |
255 * The number part of each section must consist of ASCII digits. |
419 * The letters will all be accepted in upper or lower case. |
256 * The number may be prefixed by the ASCII negative or positive symbol. |
420 * The decimal point may be either a dot or a comma. |
257 * The number must parse to an {@code int}. |
|
258 * <p> |
|
259 * The leading plus/minus sign, and negative values for other units are |
|
260 * not part of the ISO-8601 standard. |
421 * |
261 * |
422 * @param text the text to parse, not null |
262 * @param text the text to parse, not null |
423 * @return the parsed period, not null |
263 * @return the parsed period, not null |
424 * @throws DateTimeParseException if the text cannot be parsed to a period |
264 * @throws DateTimeParseException if the text cannot be parsed to a period |
425 */ |
265 */ |
426 public static Period parse(final CharSequence text) { |
266 public static Period parse(CharSequence text) { |
427 Objects.requireNonNull(text, "text"); |
267 Objects.requireNonNull(text, "text"); |
428 return new PeriodParser(text).parse(); |
268 Matcher matcher = PATTERN.matcher(text); |
|
269 if (matcher.matches()) { |
|
270 int negate = ("-".equals(matcher.group(1)) ? -1 : 1); |
|
271 String yearMatch = matcher.group(2); |
|
272 String monthMatch = matcher.group(3); |
|
273 String dayMatch = matcher.group(4); |
|
274 if (yearMatch != null || monthMatch != null || dayMatch != null) { |
|
275 try { |
|
276 return create(parseNumber(text, yearMatch, negate), |
|
277 parseNumber(text, monthMatch, negate), |
|
278 parseNumber(text, dayMatch, negate)); |
|
279 } catch (NumberFormatException ex) { |
|
280 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); |
|
281 } |
|
282 } |
|
283 } |
|
284 throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0); |
|
285 } |
|
286 |
|
287 private static int parseNumber(CharSequence text, String str, int negate) { |
|
288 if (str == null) { |
|
289 return 0; |
|
290 } |
|
291 int val = Integer.parseInt(str); |
|
292 try { |
|
293 return Math.multiplyExact(val, negate); |
|
294 } catch (ArithmeticException ex) { |
|
295 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); |
|
296 } |
429 } |
297 } |
430 |
298 |
431 //----------------------------------------------------------------------- |
299 //----------------------------------------------------------------------- |
432 /** |
300 /** |
433 * Creates an instance. |
301 * Creates an instance. |
434 * |
302 * |
435 * @param years the amount |
303 * @param years the amount |
436 * @param months the amount |
304 * @param months the amount |
437 * @param days the amount |
305 * @param days the amount |
438 * @param nanos the amount |
306 */ |
439 */ |
307 private static Period create(int years, int months, int days) { |
440 private static Period create(int years, int months, int days, long nanos) { |
308 if ((years | months | days) == 0) { |
441 if ((years | months | days | nanos) == 0) { |
|
442 return ZERO; |
309 return ZERO; |
443 } |
310 } |
444 return new Period(years, months, days, nanos); |
311 return new Period(years, months, days); |
445 } |
312 } |
446 |
313 |
447 /** |
314 /** |
448 * Constructor. |
315 * Constructor. |
449 * |
316 * |
450 * @param years the amount |
317 * @param years the amount |
451 * @param months the amount |
318 * @param months the amount |
452 * @param days the amount |
319 * @param days the amount |
453 * @param nanos the amount |
320 */ |
454 */ |
321 private Period(int years, int months, int days) { |
455 private Period(int years, int months, int days, long nanos) { |
|
456 this.years = years; |
322 this.years = years; |
457 this.months = months; |
323 this.months = months; |
458 this.days = days; |
324 this.days = days; |
459 this.nanos = nanos; |
325 } |
460 } |
326 |
461 |
327 //----------------------------------------------------------------------- |
462 /** |
328 /** |
463 * Resolves singletons. |
329 * Gets the value of the requested unit. |
464 * |
330 * <p> |
465 * @return the resolved instance |
331 * This returns a value for each of the three supported units, |
466 */ |
332 * {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS} and |
467 private Object readResolve() { |
333 * {@link ChronoUnit#DAYS DAYS}. |
468 if ((years | months | days | nanos) == 0) { |
334 * All other units throw an exception. |
469 return ZERO; |
335 * |
470 } |
336 * @param unit the {@code TemporalUnit} for which to return the value |
471 return this; |
337 * @return the long value of the unit |
472 } |
338 * @throws DateTimeException if the unit is not supported |
473 |
339 */ |
474 //----------------------------------------------------------------------- |
340 @Override |
475 /** |
341 public long get(TemporalUnit unit) { |
476 * Checks if this period is zero-length. |
342 if (unit == ChronoUnit.YEARS) { |
|
343 return getYears(); |
|
344 } else if (unit == ChronoUnit.MONTHS) { |
|
345 return getMonths(); |
|
346 } else if (unit == ChronoUnit.DAYS) { |
|
347 return getDays(); |
|
348 } else { |
|
349 throw new DateTimeException("Unsupported unit: " + unit.getName()); |
|
350 } |
|
351 } |
|
352 |
|
353 /** |
|
354 * Gets the set of units supported by this period. |
|
355 * <p> |
|
356 * The supported units are {@link ChronoUnit#YEARS YEARS}, |
|
357 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. |
|
358 * They are returned in the order years, months, days. |
|
359 * <p> |
|
360 * This set can be used in conjunction with {@link #get(TemporalUnit)} |
|
361 * to access the entire state of the period. |
|
362 * |
|
363 * @return a list containing the years, months and days units, not null |
|
364 */ |
|
365 @Override |
|
366 public List<TemporalUnit> getUnits() { |
|
367 return SUPPORTED_UNITS; |
|
368 } |
|
369 |
|
370 //----------------------------------------------------------------------- |
|
371 /** |
|
372 * Checks if all three units of this period are zero. |
|
373 * <p> |
|
374 * A zero period has the value zero for the years, months and days units. |
477 * |
375 * |
478 * @return true if this period is zero-length |
376 * @return true if this period is zero-length |
479 */ |
377 */ |
480 public boolean isZero() { |
378 public boolean isZero() { |
481 return (this == ZERO); |
379 return (this == ZERO); |
482 } |
380 } |
483 |
381 |
484 /** |
382 /** |
485 * Checks if this period is fully positive, excluding zero. |
383 * Checks if any of the three units of this period are negative. |
486 * <p> |
384 * <p> |
487 * This checks whether all the amounts in the period are positive, |
385 * This checks whether the years, months or days units are less than zero. |
488 * defined as greater than zero. |
386 * |
489 * |
387 * @return true if any unit of this period is negative |
490 * @return true if this period is fully positive excluding zero |
388 */ |
491 */ |
389 public boolean isNegative() { |
492 public boolean isPositive() { |
390 return years < 0 || months < 0 || days < 0; |
493 return ((years | months | days | nanos) > 0); |
|
494 } |
391 } |
495 |
392 |
496 //----------------------------------------------------------------------- |
393 //----------------------------------------------------------------------- |
497 /** |
394 /** |
498 * Gets the amount of years of this period. |
395 * Gets the amount of years of this period. |
499 * |
396 * <p> |
500 * @return the amount of years of this period |
397 * This returns the years unit. |
|
398 * <p> |
|
399 * The months unit is not normalized with the years unit. |
|
400 * This means that a period of "15 months" is different to a period |
|
401 * of "1 year and 3 months". |
|
402 * |
|
403 * @return the amount of years of this period, may be negative |
501 */ |
404 */ |
502 public int getYears() { |
405 public int getYears() { |
503 return years; |
406 return years; |
504 } |
407 } |
505 |
408 |
506 /** |
409 /** |
507 * Gets the amount of months of this period. |
410 * Gets the amount of months of this period. |
508 * |
411 * <p> |
509 * @return the amount of months of this period |
412 * This returns the months unit. |
|
413 * <p> |
|
414 * The months unit is not normalized with the years unit. |
|
415 * This means that a period of "15 months" is different to a period |
|
416 * of "1 year and 3 months". |
|
417 * |
|
418 * @return the amount of months of this period, may be negative |
510 */ |
419 */ |
511 public int getMonths() { |
420 public int getMonths() { |
512 return months; |
421 return months; |
513 } |
422 } |
514 |
423 |
515 /** |
424 /** |
516 * Gets the amount of days of this period. |
425 * Gets the amount of days of this period. |
517 * |
426 * <p> |
518 * @return the amount of days of this period |
427 * This returns the days unit. |
|
428 * |
|
429 * @return the amount of days of this period, may be negative |
519 */ |
430 */ |
520 public int getDays() { |
431 public int getDays() { |
521 return days; |
432 return days; |
522 } |
433 } |
523 |
434 |
524 /** |
|
525 * Gets the amount of hours of this period. |
|
526 * <p> |
|
527 * Within a period, the time fields are always normalized. |
|
528 * |
|
529 * @return the amount of hours of this period |
|
530 */ |
|
531 public int getHours() { |
|
532 return (int) (nanos / NANOS_PER_HOUR); |
|
533 } |
|
534 |
|
535 /** |
|
536 * Gets the amount of minutes within an hour of this period. |
|
537 * <p> |
|
538 * Within a period, the time fields are always normalized. |
|
539 * |
|
540 * @return the amount of minutes within an hour of this period |
|
541 */ |
|
542 public int getMinutes() { |
|
543 return (int) ((nanos / NANOS_PER_MINUTE) % 60); |
|
544 } |
|
545 |
|
546 /** |
|
547 * Gets the amount of seconds within a minute of this period. |
|
548 * <p> |
|
549 * Within a period, the time fields are always normalized. |
|
550 * |
|
551 * @return the amount of seconds within a minute of this period |
|
552 */ |
|
553 public int getSeconds() { |
|
554 return (int) ((nanos / NANOS_PER_SECOND) % 60); |
|
555 } |
|
556 |
|
557 /** |
|
558 * Gets the amount of nanoseconds within a second of this period. |
|
559 * <p> |
|
560 * Within a period, the time fields are always normalized. |
|
561 * |
|
562 * @return the amount of nanoseconds within a second of this period |
|
563 */ |
|
564 public int getNanos() { |
|
565 return (int) (nanos % NANOS_PER_SECOND); // safe from overflow |
|
566 } |
|
567 |
|
568 /** |
|
569 * Gets the total amount of the time units of this period, measured in nanoseconds. |
|
570 * <p> |
|
571 * Within a period, the time fields are always normalized. |
|
572 * |
|
573 * @return the total amount of time unit nanoseconds of this period |
|
574 */ |
|
575 public long getTimeNanos() { |
|
576 return nanos; |
|
577 } |
|
578 |
|
579 //----------------------------------------------------------------------- |
435 //----------------------------------------------------------------------- |
580 /** |
436 /** |
581 * Returns a copy of this period with the specified amount of years. |
437 * Returns a copy of this period with the specified amount of years. |
582 * <p> |
438 * <p> |
583 * This method will only affect the years field. |
439 * This sets the amount of the years unit in a copy of this period. |
584 * All other units are unaffected. |
440 * The months and days units are unaffected. |
585 * <p> |
441 * <p> |
586 * This instance is immutable and unaffected by this method call. |
442 * The months unit is not normalized with the years unit. |
587 * |
443 * This means that a period of "15 months" is different to a period |
588 * @param years the years to represent |
444 * of "1 year and 3 months". |
|
445 * <p> |
|
446 * This instance is immutable and unaffected by this method call. |
|
447 * |
|
448 * @param years the years to represent, may be negative |
589 * @return a {@code Period} based on this period with the requested years, not null |
449 * @return a {@code Period} based on this period with the requested years, not null |
590 */ |
450 */ |
591 public Period withYears(int years) { |
451 public Period withYears(int years) { |
592 if (years == this.years) { |
452 if (years == this.years) { |
593 return this; |
453 return this; |
594 } |
454 } |
595 return create(years, months, days, nanos); |
455 return create(years, months, days); |
596 } |
456 } |
597 |
457 |
598 /** |
458 /** |
599 * Returns a copy of this period with the specified amount of months. |
459 * Returns a copy of this period with the specified amount of months. |
600 * <p> |
460 * <p> |
601 * This method will only affect the months field. |
461 * This sets the amount of the months unit in a copy of this period. |
602 * All other units are unaffected. |
462 * The years and days units are unaffected. |
603 * <p> |
463 * <p> |
604 * This instance is immutable and unaffected by this method call. |
464 * The months unit is not normalized with the years unit. |
605 * |
465 * This means that a period of "15 months" is different to a period |
606 * @param months the months to represent |
466 * of "1 year and 3 months". |
|
467 * <p> |
|
468 * This instance is immutable and unaffected by this method call. |
|
469 * |
|
470 * @param months the months to represent, may be negative |
607 * @return a {@code Period} based on this period with the requested months, not null |
471 * @return a {@code Period} based on this period with the requested months, not null |
608 */ |
472 */ |
609 public Period withMonths(int months) { |
473 public Period withMonths(int months) { |
610 if (months == this.months) { |
474 if (months == this.months) { |
611 return this; |
475 return this; |
612 } |
476 } |
613 return create(years, months, days, nanos); |
477 return create(years, months, days); |
614 } |
478 } |
615 |
479 |
616 /** |
480 /** |
617 * Returns a copy of this period with the specified amount of days. |
481 * Returns a copy of this period with the specified amount of days. |
618 * <p> |
482 * <p> |
619 * This method will only affect the days field. |
483 * This sets the amount of the days unit in a copy of this period. |
620 * All other units are unaffected. |
484 * The years and months units are unaffected. |
621 * <p> |
485 * <p> |
622 * This instance is immutable and unaffected by this method call. |
486 * This instance is immutable and unaffected by this method call. |
623 * |
487 * |
624 * @param days the days to represent |
488 * @param days the days to represent, may be negative |
625 * @return a {@code Period} based on this period with the requested days, not null |
489 * @return a {@code Period} based on this period with the requested days, not null |
626 */ |
490 */ |
627 public Period withDays(int days) { |
491 public Period withDays(int days) { |
628 if (days == this.days) { |
492 if (days == this.days) { |
629 return this; |
493 return this; |
630 } |
494 } |
631 return create(years, months, days, nanos); |
495 return create(years, months, days); |
632 } |
|
633 |
|
634 /** |
|
635 * Returns a copy of this period with the specified total amount of time units |
|
636 * expressed in nanoseconds. |
|
637 * <p> |
|
638 * Within a period, the time fields are always normalized. |
|
639 * This method will affect all the time units - hours, minutes, seconds and nanos. |
|
640 * The date units are unaffected. |
|
641 * <p> |
|
642 * This instance is immutable and unaffected by this method call. |
|
643 * |
|
644 * @param nanos the nanoseconds to represent |
|
645 * @return a {@code Period} based on this period with the requested nanoseconds, not null |
|
646 */ |
|
647 public Period withTimeNanos(long nanos) { |
|
648 if (nanos == this.nanos) { |
|
649 return this; |
|
650 } |
|
651 return create(years, months, days, nanos); |
|
652 } |
496 } |
653 |
497 |
654 //----------------------------------------------------------------------- |
498 //----------------------------------------------------------------------- |
655 /** |
499 /** |
656 * Returns a copy of this period with the specified period added. |
500 * Returns a copy of this period with the specified period added. |
657 * <p> |
501 * <p> |
658 * This operates separately on the years, months, days and the normalized time. |
502 * This operates separately on the years, months, days and the normalized time. |
659 * There is no further normalization beyond the normalized time. |
503 * There is no further normalization beyond the normalized time. |
660 * <p> |
504 * <p> |
661 * This instance is immutable and unaffected by this method call. |
505 * For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days" |
662 * |
506 * returns "3 years, 8 months and 5 days". |
663 * @param other the period to add, not null |
507 * <p> |
|
508 * This instance is immutable and unaffected by this method call. |
|
509 * |
|
510 * @param amountToAdd the period to add, not null |
664 * @return a {@code Period} based on this period with the requested period added, not null |
511 * @return a {@code Period} based on this period with the requested period added, not null |
665 * @throws ArithmeticException if numeric overflow occurs |
512 * @throws ArithmeticException if numeric overflow occurs |
666 */ |
513 */ |
667 public Period plus(Period other) { |
514 public Period plus(Period amountToAdd) { |
668 return create( |
515 return create( |
669 Math.addExact(years, other.years), |
516 Math.addExact(years, amountToAdd.years), |
670 Math.addExact(months, other.months), |
517 Math.addExact(months, amountToAdd.months), |
671 Math.addExact(days, other.days), |
518 Math.addExact(days, amountToAdd.days)); |
672 Math.addExact(nanos, other.nanos)); |
519 } |
673 } |
520 |
674 |
521 /** |
675 /** |
522 * Returns a copy of this period with the specified years added. |
676 * Returns a copy of this period with the specified period added. |
523 * <p> |
677 * <p> |
524 * This adds the amount to the years unit in a copy of this period. |
678 * The specified unit must be one of the supported units from {@link ChronoUnit}, |
525 * The months and days units are unaffected. |
679 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an |
526 * For example, "1 year, 6 months and 3 days" plus 2 years returns "3 years, 6 months and 3 days". |
680 * {@linkplain TemporalUnit#isDurationEstimated() exact duration}. |
527 * <p> |
681 * Other units throw an exception. |
528 * This instance is immutable and unaffected by this method call. |
682 * <p> |
529 * |
683 * This instance is immutable and unaffected by this method call. |
530 * @param yearsToAdd the years to add, positive or negative |
684 * |
531 * @return a {@code Period} based on this period with the specified years added, not null |
685 * @param amount the amount to add, positive or negative |
532 * @throws ArithmeticException if numeric overflow occurs |
686 * @param unit the unit that the amount is expressed in, not null |
533 */ |
687 * @return a {@code Period} based on this period with the requested amount added, not null |
534 public Period plusYears(long yearsToAdd) { |
688 * @throws ArithmeticException if numeric overflow occurs |
535 if (yearsToAdd == 0) { |
689 */ |
536 return this; |
690 public Period plus(long amount, TemporalUnit unit) { |
537 } |
691 Objects.requireNonNull(unit, "unit"); |
538 return create(Math.toIntExact(Math.addExact(years, yearsToAdd)), months, days); |
692 if (unit instanceof ChronoUnit) { |
539 } |
693 if (unit == YEARS || unit == MONTHS || unit == DAYS || unit.isDurationEstimated() == false) { |
540 |
694 if (amount == 0) { |
541 /** |
695 return this; |
542 * Returns a copy of this period with the specified months added. |
696 } |
543 * <p> |
697 switch((ChronoUnit) unit) { |
544 * This adds the amount to the months unit in a copy of this period. |
698 case NANOS: return plusNanos(amount); |
545 * The years and days units are unaffected. |
699 case MICROS: return plusNanos(Math.multiplyExact(amount, 1000L)); |
546 * For example, "1 year, 6 months and 3 days" plus 2 months returns "1 year, 8 months and 3 days". |
700 case MILLIS: return plusNanos(Math.multiplyExact(amount, 1000_000L)); |
547 * <p> |
701 case SECONDS: return plusSeconds(amount); |
548 * This instance is immutable and unaffected by this method call. |
702 case MINUTES: return plusMinutes(amount); |
549 * |
703 case HOURS: return plusHours(amount); |
550 * @param monthsToAdd the months to add, positive or negative |
704 case HALF_DAYS: return plusNanos(Math.multiplyExact(amount, 12 * NANOS_PER_HOUR)); |
551 * @return a {@code Period} based on this period with the specified months added, not null |
705 case DAYS: return plusDays(amount); |
552 * @throws ArithmeticException if numeric overflow occurs |
706 case MONTHS: return plusMonths(amount); |
553 */ |
707 case YEARS: return plusYears(amount); |
554 public Period plusMonths(long monthsToAdd) { |
708 default: throw new DateTimeException("Unsupported unit: " + unit.getName()); |
555 if (monthsToAdd == 0) { |
709 } |
556 return this; |
710 } |
557 } |
711 } |
558 return create(years, Math.toIntExact(Math.addExact(months, monthsToAdd)), days); |
712 if (unit.isDurationEstimated()) { |
559 } |
713 throw new DateTimeException("Unsupported unit: " + unit.getName()); |
560 |
714 } |
561 /** |
715 return plusNanos(Duration.of(amount, unit).toNanos()); |
562 * Returns a copy of this period with the specified days added. |
716 } |
563 * <p> |
717 |
564 * This adds the amount to the days unit in a copy of this period. |
718 public Period plusYears(long amount) { |
565 * The years and months units are unaffected. |
719 return create(Math.toIntExact(Math.addExact(years, amount)), months, days, nanos); |
566 * For example, "1 year, 6 months and 3 days" plus 2 days returns "1 year, 6 months and 5 days". |
720 } |
567 * <p> |
721 |
568 * This instance is immutable and unaffected by this method call. |
722 public Period plusMonths(long amount) { |
569 * |
723 return create(years, Math.toIntExact(Math.addExact(months, amount)), days, nanos); |
570 * @param daysToAdd the days to add, positive or negative |
724 } |
571 * @return a {@code Period} based on this period with the specified days added, not null |
725 |
572 * @throws ArithmeticException if numeric overflow occurs |
726 public Period plusDays(long amount) { |
573 */ |
727 return create(years, months, Math.toIntExact(Math.addExact(days, amount)), nanos); |
574 public Period plusDays(long daysToAdd) { |
728 } |
575 if (daysToAdd == 0) { |
729 |
576 return this; |
730 public Period plusHours(long amount) { |
577 } |
731 return plusNanos(Math.multiplyExact(amount, NANOS_PER_HOUR)); |
578 return create(years, months, Math.toIntExact(Math.addExact(days, daysToAdd))); |
732 } |
|
733 |
|
734 public Period plusMinutes(long amount) { |
|
735 return plusNanos(Math.multiplyExact(amount, NANOS_PER_MINUTE)); |
|
736 } |
|
737 |
|
738 public Period plusSeconds(long amount) { |
|
739 return plusNanos(Math.multiplyExact(amount, NANOS_PER_SECOND)); |
|
740 } |
|
741 |
|
742 public Period plusNanos(long amount) { |
|
743 return create(years, months, days, Math.addExact(nanos, amount)); |
|
744 } |
579 } |
745 |
580 |
746 //----------------------------------------------------------------------- |
581 //----------------------------------------------------------------------- |
747 /** |
582 /** |
748 * Returns a copy of this period with the specified period subtracted. |
583 * Returns a copy of this period with the specified period subtracted. |
749 * <p> |
584 * <p> |
750 * This operates separately on the years, months, days and the normalized time. |
585 * This operates separately on the years, months, days and the normalized time. |
751 * There is no further normalization beyond the normalized time. |
586 * There is no further normalization beyond the normalized time. |
752 * <p> |
587 * <p> |
753 * This instance is immutable and unaffected by this method call. |
588 * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days" |
754 * |
589 * returns "-1 years, 4 months and 1 day". |
755 * @param other the period to subtract, not null |
590 * <p> |
|
591 * This instance is immutable and unaffected by this method call. |
|
592 * |
|
593 * @param amountToSubtract the period to subtract, not null |
756 * @return a {@code Period} based on this period with the requested period subtracted, not null |
594 * @return a {@code Period} based on this period with the requested period subtracted, not null |
757 * @throws ArithmeticException if numeric overflow occurs |
595 * @throws ArithmeticException if numeric overflow occurs |
758 */ |
596 */ |
759 public Period minus(Period other) { |
597 public Period minus(Period amountToSubtract) { |
760 return create( |
598 return create( |
761 Math.subtractExact(years, other.years), |
599 Math.subtractExact(years, amountToSubtract.years), |
762 Math.subtractExact(months, other.months), |
600 Math.subtractExact(months, amountToSubtract.months), |
763 Math.subtractExact(days, other.days), |
601 Math.subtractExact(days, amountToSubtract.days)); |
764 Math.subtractExact(nanos, other.nanos)); |
602 } |
765 } |
603 |
766 |
604 /** |
767 /** |
605 * Returns a copy of this period with the specified years subtracted. |
768 * Returns a copy of this period with the specified period subtracted. |
606 * <p> |
769 * <p> |
607 * This subtracts the amount from the years unit in a copy of this period. |
770 * The specified unit must be one of the supported units from {@link ChronoUnit}, |
608 * The months and days units are unaffected. |
771 * {@code YEARS}, {@code MONTHS} or {@code DAYS} or be a time unit with an |
609 * For example, "1 year, 6 months and 3 days" minus 2 years returns "-1 years, 6 months and 3 days". |
772 * {@linkplain TemporalUnit#isDurationEstimated() exact duration}. |
610 * <p> |
773 * Other units throw an exception. |
611 * This instance is immutable and unaffected by this method call. |
774 * <p> |
612 * |
775 * This instance is immutable and unaffected by this method call. |
613 * @param yearsToSubtract the years to subtract, positive or negative |
776 * |
614 * @return a {@code Period} based on this period with the specified years subtracted, not null |
777 * @param amount the amount to subtract, positive or negative |
615 * @throws ArithmeticException if numeric overflow occurs |
778 * @param unit the unit that the amount is expressed in, not null |
616 */ |
779 * @return a {@code Period} based on this period with the requested amount subtracted, not null |
617 public Period minusYears(long yearsToSubtract) { |
780 * @throws ArithmeticException if numeric overflow occurs |
618 return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract)); |
781 */ |
619 } |
782 public Period minus(long amount, TemporalUnit unit) { |
620 |
783 return (amount == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amount, unit)); |
621 /** |
784 } |
622 * Returns a copy of this period with the specified months subtracted. |
785 |
623 * <p> |
786 public Period minusYears(long amount) { |
624 * This subtracts the amount from the months unit in a copy of this period. |
787 return (amount == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-amount)); |
625 * The years and days units are unaffected. |
788 } |
626 * For example, "1 year, 6 months and 3 days" minus 2 months returns "1 year, 4 months and 3 days". |
789 |
627 * <p> |
790 public Period minusMonths(long amount) { |
628 * This instance is immutable and unaffected by this method call. |
791 return (amount == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-amount)); |
629 * |
792 } |
630 * @param monthsToSubtract the years to subtract, positive or negative |
793 |
631 * @return a {@code Period} based on this period with the specified months subtracted, not null |
794 public Period minusDays(long amount) { |
632 * @throws ArithmeticException if numeric overflow occurs |
795 return (amount == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-amount)); |
633 */ |
796 } |
634 public Period minusMonths(long monthsToSubtract) { |
797 |
635 return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract)); |
798 public Period minusHours(long amount) { |
636 } |
799 return (amount == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-amount)); |
637 |
800 } |
638 /** |
801 |
639 * Returns a copy of this period with the specified days subtracted. |
802 public Period minusMinutes(long amount) { |
640 * <p> |
803 return (amount == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-amount)); |
641 * This subtracts the amount from the days unit in a copy of this period. |
804 } |
642 * The years and months units are unaffected. |
805 |
643 * For example, "1 year, 6 months and 3 days" minus 2 days returns "1 year, 6 months and 1 day". |
806 public Period minusSeconds(long amount) { |
644 * <p> |
807 return (amount == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-amount)); |
645 * This instance is immutable and unaffected by this method call. |
808 } |
646 * |
809 |
647 * @param daysToSubtract the months to subtract, positive or negative |
810 public Period minusNanos(long amount) { |
648 * @return a {@code Period} based on this period with the specified days subtracted, not null |
811 return (amount == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-amount)); |
649 * @throws ArithmeticException if numeric overflow occurs |
|
650 */ |
|
651 public Period minusDays(long daysToSubtract) { |
|
652 return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); |
812 } |
653 } |
813 |
654 |
814 //----------------------------------------------------------------------- |
655 //----------------------------------------------------------------------- |
815 /** |
656 /** |
816 * Returns a new instance with each element in this period multiplied |
657 * Returns a new instance with each element in this period multiplied |
817 * by the specified scalar. |
658 * by the specified scalar. |
818 * <p> |
659 * <p> |
819 * This simply multiplies each field, years, months, days and normalized time, |
660 * This returns a period with each of the years, months and days units |
820 * by the scalar. No normalization is performed. |
661 * individually multiplied. |
|
662 * For example, a period of "2 years, -3 months and 4 days" multiplied by |
|
663 * 3 will return "6 years, -9 months and 12 days". |
|
664 * No normalization is performed. |
821 * |
665 * |
822 * @param scalar the scalar to multiply by, not null |
666 * @param scalar the scalar to multiply by, not null |
823 * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null |
667 * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null |
824 * @throws ArithmeticException if numeric overflow occurs |
668 * @throws ArithmeticException if numeric overflow occurs |
825 */ |
669 */ |
828 return this; |
672 return this; |
829 } |
673 } |
830 return create( |
674 return create( |
831 Math.multiplyExact(years, scalar), |
675 Math.multiplyExact(years, scalar), |
832 Math.multiplyExact(months, scalar), |
676 Math.multiplyExact(months, scalar), |
833 Math.multiplyExact(days, scalar), |
677 Math.multiplyExact(days, scalar)); |
834 Math.multiplyExact(nanos, scalar)); |
|
835 } |
678 } |
836 |
679 |
837 /** |
680 /** |
838 * Returns a new instance with each amount in this period negated. |
681 * Returns a new instance with each amount in this period negated. |
|
682 * <p> |
|
683 * This returns a period with each of the years, months and days units |
|
684 * individually negated. |
|
685 * For example, a period of "2 years, -3 months and 4 days" will be |
|
686 * negated to "-2 years, 3 months and -4 days". |
|
687 * No normalization is performed. |
839 * |
688 * |
840 * @return a {@code Period} based on this period with the amounts negated, not null |
689 * @return a {@code Period} based on this period with the amounts negated, not null |
841 * @throws ArithmeticException if numeric overflow occurs |
690 * @throws ArithmeticException if numeric overflow occurs, which only happens if |
|
691 * one of the units has the value {@code Long.MIN_VALUE} |
842 */ |
692 */ |
843 public Period negated() { |
693 public Period negated() { |
844 return multipliedBy(-1); |
694 return multipliedBy(-1); |
845 } |
695 } |
846 |
696 |
847 //----------------------------------------------------------------------- |
697 //----------------------------------------------------------------------- |
848 /** |
698 /** |
849 * Returns a copy of this period with the days and hours normalized using a 24 hour day. |
699 * Returns a copy of this period with the years and months normalized |
850 * <p> |
700 * using a 12 month year. |
851 * This normalizes the days and hours units, leaving years and months unchanged. |
701 * <p> |
852 * The hours unit is adjusted to have an absolute value less than 23, |
702 * This normalizes the years and months units, leaving the days unit unchanged. |
853 * with the days unit being adjusted to compensate. |
|
854 * For example, a period of {@code P1DT27H} will be normalized to {@code P2DT3H}. |
|
855 * <p> |
|
856 * The sign of the days and hours units will be the same after normalization. |
|
857 * For example, a period of {@code P1DT-51H} will be normalized to {@code P-1DT-3H}. |
|
858 * Since all time units are always normalized, if the hours units changes sign then |
|
859 * other time units will also be affected. |
|
860 * <p> |
|
861 * This instance is immutable and unaffected by this method call. |
|
862 * |
|
863 * @return a {@code Period} based on this period with excess hours normalized to days, not null |
|
864 * @throws ArithmeticException if numeric overflow occurs |
|
865 */ |
|
866 public Period normalizedHoursToDays() { |
|
867 // logic uses if statements to normalize signs to avoid unnecessary overflows |
|
868 long totalDays = (nanos / NANOS_PER_DAY) + days; // no overflow |
|
869 long splitNanos = nanos % NANOS_PER_DAY; |
|
870 if (totalDays > 0 && splitNanos < 0) { |
|
871 splitNanos += NANOS_PER_DAY; |
|
872 totalDays--; |
|
873 } else if (totalDays < 0 && splitNanos > 0) { |
|
874 splitNanos -= NANOS_PER_DAY; |
|
875 totalDays++; |
|
876 } |
|
877 if (totalDays == days && splitNanos == nanos) { |
|
878 return this; |
|
879 } |
|
880 return create(years, months, Math.toIntExact(totalDays), splitNanos); |
|
881 } |
|
882 |
|
883 /** |
|
884 * Returns a copy of this period with any days converted to hours using a 24 hour day. |
|
885 * <p> |
|
886 * The days unit is reduced to zero, with the hours unit increased by 24 times the |
|
887 * days unit to compensate. Other units are unaffected. |
|
888 * For example, a period of {@code P2DT4H} will be normalized to {@code PT52H}. |
|
889 * <p> |
|
890 * This instance is immutable and unaffected by this method call. |
|
891 * |
|
892 * @return a {@code Period} based on this period with days normalized to hours, not null |
|
893 * @throws ArithmeticException if numeric overflow occurs |
|
894 */ |
|
895 public Period normalizedDaysToHours() { |
|
896 if (days == 0) { |
|
897 return this; |
|
898 } |
|
899 return create(years, months, 0, Math.addExact(Math.multiplyExact(days, NANOS_PER_DAY), nanos)); |
|
900 } |
|
901 |
|
902 /** |
|
903 * Returns a copy of this period with the years and months normalized using a 12 month year. |
|
904 * <p> |
|
905 * This normalizes the years and months units, leaving other units unchanged. |
|
906 * The months unit is adjusted to have an absolute value less than 11, |
703 * The months unit is adjusted to have an absolute value less than 11, |
907 * with the years unit being adjusted to compensate. |
704 * with the years unit being adjusted to compensate. For example, a period of |
908 * For example, a period of {@code P1Y15M} will be normalized to {@code P2Y3M}. |
705 * "1 Year and 15 months" will be normalized to "2 years and 3 months". |
909 * <p> |
706 * <p> |
910 * The sign of the years and months units will be the same after normalization. |
707 * The sign of the years and months units will be the same after normalization. |
911 * For example, a period of {@code P1Y-25M} will be normalized to {@code P-1Y-1M}. |
708 * For example, a period of "1 year and -25 months" will be normalized to |
912 * <p> |
709 * "-1 year and -1 month". |
913 * This normalization uses a 12 month year it is not valid for all calendar systems. |
710 * <p> |
914 * <p> |
711 * This normalization uses a 12 month year which is not valid for all calendar systems. |
915 * This instance is immutable and unaffected by this method call. |
712 * <p> |
916 * |
713 * This instance is immutable and unaffected by this method call. |
917 * @return a {@code Period} based on this period with years and months normalized, not null |
714 * |
918 * @throws ArithmeticException if numeric overflow occurs |
715 * @return a {@code Period} based on this period with excess months normalized to years, not null |
919 */ |
716 * @throws ArithmeticException if numeric overflow occurs |
920 public Period normalizedMonthsISO() { |
717 */ |
921 long totalMonths = years * 12L + months; // no overflow |
718 public Period normalized() { |
|
719 long totalMonths = toTotalMonths(); |
922 long splitYears = totalMonths / 12; |
720 long splitYears = totalMonths / 12; |
923 int splitMonths = (int) (totalMonths % 12); // no overflow |
721 int splitMonths = (int) (totalMonths % 12); // no overflow |
924 if (splitYears == years && splitMonths == months) { |
722 if (splitYears == years && splitMonths == months) { |
925 return this; |
723 return this; |
926 } |
724 } |
927 return create(Math.toIntExact(splitYears), splitMonths, days, nanos); |
725 return create(Math.toIntExact(splitYears), splitMonths, days); |
928 } |
726 } |
929 |
727 |
930 //------------------------------------------------------------------------- |
728 /** |
931 /** |
729 * Gets the total number of months in this period using a 12 month year. |
932 * Converts this period to one that only has date units. |
730 * <p> |
933 * <p> |
731 * This returns the total number of months in the period by multiplying the |
934 * The resulting period will have the same years, months and days as this period |
732 * number of years by 12 and adding the number of months. |
935 * but the time units will all be zero. No normalization occurs in the calculation. |
733 * <p> |
936 * For example, a period of {@code P1Y3MT12H} will be converted to {@code P1Y3M}. |
734 * This uses a 12 month year which is not valid for all calendar systems. |
937 * <p> |
735 * <p> |
938 * This instance is immutable and unaffected by this method call. |
736 * This instance is immutable and unaffected by this method call. |
939 * |
737 * |
940 * @return a {@code Period} based on this period with the time units set to zero, not null |
738 * @return the total number of months in the period, may be negative |
941 */ |
739 */ |
942 public Period toDateOnly() { |
740 public long toTotalMonths() { |
943 if (nanos == 0) { |
741 return years * 12L + months; // no overflow |
944 return this; |
|
945 } |
|
946 return create(years, months, days, 0); |
|
947 } |
742 } |
948 |
743 |
949 //------------------------------------------------------------------------- |
744 //------------------------------------------------------------------------- |
950 /** |
745 /** |
951 * Adds this period to the specified temporal object. |
746 * Adds this period to the specified temporal object. |
952 * <p> |
747 * <p> |
953 * This returns a temporal object of the same observable type as the input |
748 * This returns a temporal object of the same observable type as the input |
954 * with this period added. |
749 * with this period added. |
955 * <p> |
750 * <p> |
956 * In most cases, it is clearer to reverse the calling pattern by using |
751 * In most cases, it is clearer to reverse the calling pattern by using |
957 * {@link Temporal#plus(TemporalAdder)}. |
752 * {@link Temporal#plus(TemporalAmount)}. |
958 * <pre> |
753 * <pre> |
959 * // these two lines are equivalent, but the second approach is recommended |
754 * // these two lines are equivalent, but the second approach is recommended |
960 * dateTime = thisPeriod.addTo(dateTime); |
755 * dateTime = thisPeriod.addTo(dateTime); |
961 * dateTime = dateTime.plus(thisPeriod); |
756 * dateTime = dateTime.plus(thisPeriod); |
962 * </pre> |
757 * </pre> |
963 * <p> |
758 * <p> |
964 * The calculation will add the years, then months, then days, then nanos. |
759 * The calculation will add the years, then months, then days. |
965 * Only non-zero amounts will be added. |
760 * Only non-zero amounts will be added. |
966 * If the date-time has a calendar system with a fixed number of months in a |
761 * If the date-time has a calendar system with a fixed number of months in a |
967 * year, then the years and months will be combined before being added. |
762 * year, then the years and months will be combined before being added. |
968 * <p> |
763 * <p> |
969 * This instance is immutable and unaffected by this method call. |
764 * This instance is immutable and unaffected by this method call. |