1/*2 * Copyright 2001-2010 Stephen Colebourne3 *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 at7 *8 * http://www.apache.org/licenses/LICENSE-2.09 *10 * Unless required by applicable law or agreed to in writing, software11 * 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 and14 * limitations under the License.15 */16package org.joda.time;
1718import org.joda.convert.FromString;
19import org.joda.convert.ToString;
20import org.joda.time.base.BaseSingleFieldPeriod;
21import org.joda.time.field.FieldUtils;
22import org.joda.time.format.ISOPeriodFormat;
23import org.joda.time.format.PeriodFormatter;
2425/**26 * An immutable time period representing a number of days.27 * <p>28 * <code>Days</code> is an immutable period that can only store days.29 * It does not store years, months or hours for example. As such it is a30 * type-safe way of representing a number of days in an application.31 * <p>32 * The number of days is set in the constructor, and may be queried using33 * <code>getDays()</code>. Basic mathematical operations are provided -34 * <code>plus()</code>, <code>minus()</code>, <code>multipliedBy()</code> and35 * <code>dividedBy()</code>.36 * <p>37 * <code>Days</code> is thread-safe and immutable.38 *39 * @author Stephen Colebourne40 * @since 1.441 */42publicfinalclassDaysextendsBaseSingleFieldPeriod {
4344/** Constant representing zero days. */45publicstaticfinalDays ZERO = newDays(0);
46/** Constant representing one day. */47publicstaticfinalDays ONE = newDays(1);
48/** Constant representing two days. */49publicstaticfinalDays TWO = newDays(2);
50/** Constant representing three days. */51publicstaticfinalDays THREE = newDays(3);
52/** Constant representing four days. */53publicstaticfinalDays FOUR = newDays(4);
54/** Constant representing five days. */55publicstaticfinalDays FIVE = newDays(5);
56/** Constant representing six days. */57publicstaticfinalDays SIX = newDays(6);
58/** Constant representing seven days. */59publicstaticfinalDays SEVEN = newDays(7);
60/** Constant representing the maximum number of days that can be stored in this object. */61publicstaticfinalDays MAX_VALUE = newDays(Integer.MAX_VALUE);
62/** Constant representing the minimum number of days that can be stored in this object. */63publicstaticfinalDays MIN_VALUE = newDays(Integer.MIN_VALUE);
6465/** The paser to use for this class. */66privatestaticfinalPeriodFormatter PARSER = ISOPeriodFormat.standard().withParseType(PeriodType.days());
67/** Serialization version. */68privatestaticfinallong serialVersionUID = 87525275727380865L;
6970//-----------------------------------------------------------------------71/**72 * Obtains an instance of <code>Days</code> that may be cached.73 * <code>Days</code> is immutable, so instances can be cached and shared.74 * This factory method provides access to shared instances.75 *76 * @param days the number of days to obtain an instance for77 * @return the instance of Days78 */79publicstaticDays days(int days) {
80switch (days) {
81case 0:
82return ZERO;
83case 1:
84return ONE;
85case 2:
86return TWO;
87case 3:
88return THREE;
89case 4:
90return FOUR;
91case 5:
92return FIVE;
93case 6:
94return SIX;
95case 7:
96return SEVEN;
97case Integer.MAX_VALUE:
98return MAX_VALUE;
99case Integer.MIN_VALUE:
100return MIN_VALUE;
101default:
102returnnewDays(days);
103 }
104 }
105106//-----------------------------------------------------------------------107/**108 * Creates a <code>Days</code> representing the number of whole days109 * between the two specified datetimes. This method corectly handles110 * any daylight savings time changes that may occur during the interval.111 *112 * @param start the start instant, must not be null113 * @param end the end instant, must not be null114 * @return the period in days115 * @throws IllegalArgumentException if the instants are null or invalid116 */117publicstaticDays daysBetween(ReadableInstant start, ReadableInstant end) {
118int amount = BaseSingleFieldPeriod.between(start, end, DurationFieldType.days());
119return Days.days(amount);
120 }
121122/**123 * Creates a <code>Days</code> representing the number of whole days124 * between the two specified partial datetimes.125 * <p>126 * The two partials must contain the same fields, for example you can specify127 * two <code>LocalDate</code> objects.128 *129 * @param start the start partial date, must not be null130 * @param end the end partial date, must not be null131 * @return the period in days132 * @throws IllegalArgumentException if the partials are null or invalid133 */134publicstaticDays daysBetween(ReadablePartial start, ReadablePartial end) {
135if (start instanceof LocalDate && end instanceof LocalDate) {
136Chronology chrono = DateTimeUtils.getChronology(start.getChronology());
137int days = chrono.days().getDifference(
138 ((LocalDate) end).getLocalMillis(), ((LocalDate) start).getLocalMillis());
139return Days.days(days);
140 }
141int amount = BaseSingleFieldPeriod.between(start, end, ZERO);
142return Days.days(amount);
143 }
144145/**146 * Creates a <code>Days</code> representing the number of whole days147 * in the specified interval. This method corectly handles any daylight148 * savings time changes that may occur during the interval.149 *150 * @param interval the interval to extract days from, null returns zero151 * @return the period in days152 * @throws IllegalArgumentException if the partials are null or invalid153 */154publicstaticDays daysIn(ReadableInterval interval) {
155if (interval == null) {
156return Days.ZERO;
157 }
158int amount = BaseSingleFieldPeriod.between(interval.getStart(), interval.getEnd(), DurationFieldType.days());
159return Days.days(amount);
160 }
161162/**163 * Creates a new <code>Days</code> representing the number of complete164 * standard length days in the specified period.165 * <p>166 * This factory method converts all fields from the period to hours using standardised167 * durations for each field. Only those fields which have a precise duration in168 * the ISO UTC chronology can be converted.169 * <ul>170 * <li>One week consists of 7 days.171 * <li>One day consists of 24 hours.172 * <li>One hour consists of 60 minutes.173 * <li>One minute consists of 60 seconds.174 * <li>One second consists of 1000 milliseconds.175 * </ul>176 * Months and Years are imprecise and periods containing these values cannot be converted.177 *178 * @param period the period to get the number of hours from, null returns zero179 * @return the period in days180 * @throws IllegalArgumentException if the period contains imprecise duration values181 */182publicstaticDays standardDaysIn(ReadablePeriod period) {
183int amount = BaseSingleFieldPeriod.standardPeriodIn(period, DateTimeConstants.MILLIS_PER_DAY);
184return Days.days(amount);
185 }
186187/**188 * Creates a new <code>Days</code> by parsing a string in the ISO8601 format 'PnD'.189 * <p>190 * The parse will accept the full ISO syntax of PnYnMnWnDTnHnMnS however only the191 * days component may be non-zero. If any other component is non-zero, an exception192 * will be thrown.193 *194 * @param periodStr the period string, null returns zero195 * @return the period in days196 * @throws IllegalArgumentException if the string format is invalid197 */198 @FromString
199publicstaticDays parseDays(String periodStr) {
200if (periodStr == null) {
201return Days.ZERO;
202 }
203Period p = PARSER.parsePeriod(periodStr);
204return Days.days(p.getDays());
205 }
206207//-----------------------------------------------------------------------208/**209 * Creates a new instance representing a number of days.210 * You should consider using the factory method {@link #days(int)}211 * instead of the constructor.212 *213 * @param days the number of days to represent214 */215privateDays(int days) {
216super(days);
217 }
218219/**220 * Resolves singletons.221 * 222 * @return the singleton instance223 */224private Object readResolve() {
225return Days.days(getValue());
226 }
227228//-----------------------------------------------------------------------229/**230 * Gets the duration field type, which is <code>days</code>.231 *232 * @return the period type233 */234publicDurationFieldType getFieldType() {
235return DurationFieldType.days();
236 }
237238/**239 * Gets the period type, which is <code>days</code>.240 *241 * @return the period type242 */243publicPeriodType getPeriodType() {
244return PeriodType.days();
245 }
246247//-----------------------------------------------------------------------248/**249 * Converts this period in days to a period in weeks assuming a250 * 7 day week.251 * <p>252 * This method allows you to convert between different types of period.253 * However to achieve this it makes the assumption that all weeks are254 * 7 days long.255 * This may not be true for some unusual chronologies. However, it is included256 * as it is a useful operation for many applications and business rules.257 * 258 * @return a period representing the number of weeks for this number of days259 */260publicWeeks toStandardWeeks() {
261return Weeks.weeks(getValue() / DateTimeConstants.DAYS_PER_WEEK);
262 }
263264/**265 * Converts this period in days to a period in hours assuming a266 * 24 hour day.267 * <p>268 * This method allows you to convert between different types of period.269 * However to achieve this it makes the assumption that all days are 24 hours long.270 * This is not true when daylight savings is considered and may also not271 * be true for some unusual chronologies. However, it is included272 * as it is a useful operation for many applications and business rules.273 * 274 * @return a period representing the number of hours for this number of days275 * @throws ArithmeticException if the number of hours is too large to be represented276 */277publicHours toStandardHours() {
278return Hours.hours(FieldUtils.safeMultiply(getValue(), DateTimeConstants.HOURS_PER_DAY));
279 }
280281/**282 * Converts this period in days to a period in minutes assuming a283 * 24 hour day and 60 minute hour.284 * <p>285 * This method allows you to convert between different types of period.286 * However to achieve this it makes the assumption that all days are 24 hours287 * long and all hours are 60 minutes long.288 * This is not true when daylight savings is considered and may also not289 * be true for some unusual chronologies. However, it is included290 * as it is a useful operation for many applications and business rules.291 * 292 * @return a period representing the number of minutes for this number of days293 * @throws ArithmeticException if the number of minutes is too large to be represented294 */295publicMinutes toStandardMinutes() {
296return Minutes.minutes(FieldUtils.safeMultiply(getValue(), DateTimeConstants.MINUTES_PER_DAY));
297 }
298299/**300 * Converts this period in days to a period in seconds assuming a301 * 24 hour day, 60 minute hour and 60 second minute.302 * <p>303 * This method allows you to convert between different types of period.304 * However to achieve this it makes the assumption that all days are 24 hours305 * long, all hours are 60 minutes long and all minutes are 60 seconds long.306 * This is not true when daylight savings is considered and may also not307 * be true for some unusual chronologies. However, it is included308 * as it is a useful operation for many applications and business rules.309 * 310 * @return a period representing the number of seconds for this number of days311 * @throws ArithmeticException if the number of seconds is too large to be represented312 */313publicSeconds toStandardSeconds() {
314return Seconds.seconds(FieldUtils.safeMultiply(getValue(), DateTimeConstants.SECONDS_PER_DAY));
315 }
316317//-----------------------------------------------------------------------318/**319 * Converts this period in days to a duration in milliseconds assuming a320 * 24 hour day, 60 minute hour and 60 second minute.321 * <p>322 * This method allows you to convert from a period to a duration.323 * However to achieve this it makes the assumption that all days are 24 hours324 * long, all hours are 60 minutes and all minutes are 60 seconds.325 * This is not true when daylight savings time is considered, and may also326 * not be true for some unusual chronologies. However, it is included as it327 * is a useful operation for many applications and business rules.328 * 329 * @return a duration equivalent to this number of days330 */331publicDuration toStandardDuration() {
332long days = getValue(); // assign to a long333returnnewDuration(days * DateTimeConstants.MILLIS_PER_DAY);
334 }
335336//-----------------------------------------------------------------------337/**338 * Gets the number of days that this period represents.339 *340 * @return the number of days in the period341 */342publicint getDays() {
343return getValue();
344 }
345346//-----------------------------------------------------------------------347/**348 * Returns a new instance with the specified number of days added.349 * <p>350 * This instance is immutable and unaffected by this method call.351 *352 * @param days the amount of days to add, may be negative353 * @return the new period plus the specified number of days354 * @throws ArithmeticException if the result overflows an int355 */356publicDays plus(int days) {
357if (days == 0) {
358returnthis;
359 }
360return Days.days(FieldUtils.safeAdd(getValue(), days));
361 }
362363/**364 * Returns a new instance with the specified number of days added.365 * <p>366 * This instance is immutable and unaffected by this method call.367 *368 * @param days the amount of days to add, may be negative, null means zero369 * @return the new period plus the specified number of days370 * @throws ArithmeticException if the result overflows an int371 */372publicDays plus(Days days) {
373if (days == null) {
374returnthis;
375 }
376return plus(days.getValue());
377 }
378379//-----------------------------------------------------------------------380/**381 * Returns a new instance with the specified number of days taken away.382 * <p>383 * This instance is immutable and unaffected by this method call.384 *385 * @param days the amount of days to take away, may be negative386 * @return the new period minus the specified number of days387 * @throws ArithmeticException if the result overflows an int388 */389publicDays minus(int days) {
390return plus(FieldUtils.safeNegate(days));
391 }
392393/**394 * Returns a new instance with the specified number of days taken away.395 * <p>396 * This instance is immutable and unaffected by this method call.397 *398 * @param days the amount of days to take away, may be negative, null means zero399 * @return the new period minus the specified number of days400 * @throws ArithmeticException if the result overflows an int401 */402publicDays minus(Days days) {
403if (days == null) {
404returnthis;
405 }
406return minus(days.getValue());
407 }
408409//-----------------------------------------------------------------------410/**411 * Returns a new instance with the days multiplied by the specified scalar.412 * <p>413 * This instance is immutable and unaffected by this method call.414 *415 * @param scalar the amount to multiply by, may be negative416 * @return the new period multiplied by the specified scalar417 * @throws ArithmeticException if the result overflows an int418 */419publicDays multipliedBy(int scalar) {
420return Days.days(FieldUtils.safeMultiply(getValue(), scalar));
421 }
422423/**424 * Returns a new instance with the days divided by the specified divisor.425 * The calculation uses integer division, thus 3 divided by 2 is 1.426 * <p>427 * This instance is immutable and unaffected by this method call.428 *429 * @param divisor the amount to divide by, may be negative430 * @return the new period divided by the specified divisor431 * @throws ArithmeticException if the divisor is zero432 */433publicDays dividedBy(int divisor) {
434if (divisor == 1) {
435returnthis;
436 }
437return Days.days(getValue() / divisor);
438 }
439440//-----------------------------------------------------------------------441/**442 * Returns a new instance with the days value negated.443 *444 * @return the new period with a negated value445 * @throws ArithmeticException if the result overflows an int446 */447publicDays negated() {
448return Days.days(FieldUtils.safeNegate(getValue()));
449 }
450451//-----------------------------------------------------------------------452/**453 * Is this days instance greater than the specified number of days.454 *455 * @param other the other period, null means zero456 * @return true if this days instance is greater than the specified one457 */458publicboolean isGreaterThan(Days other) {
459if (other == null) {
460return getValue() > 0;
461 }
462return getValue() > other.getValue();
463 }
464465/**466 * Is this days instance less than the specified number of days.467 *468 * @param other the other period, null means zero469 * @return true if this days instance is less than the specified one470 */471publicboolean isLessThan(Days other) {
472if (other == null) {
473return getValue() < 0;
474 }
475return getValue() < other.getValue();
476 }
477478//-----------------------------------------------------------------------479/**480 * Gets this instance as a String in the ISO8601 duration format.481 * <p>482 * For example, "P4D" represents 4 days.483 *484 * @return the value as an ISO8601 string485 */486 @ToString
487public String toString() {
488return"P" + String.valueOf(getValue()) + "D";
489 }
490491 }