42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57 package java.time.chrono;
58
59 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
60 import static java.time.temporal.ChronoField.ERA;
61 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
62 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
63
64 import java.io.Serializable;
65 import java.time.DateTimeException;
66 import java.time.LocalDate;
67 import java.time.LocalTime;
68 import java.time.chrono.Chronology;
69 import java.time.chrono.ChronoLocalDate;
70 import java.time.chrono.ChronoLocalDateTime;
71 import java.time.temporal.ChronoUnit;
72 import java.time.temporal.Temporal;
73 import java.time.temporal.TemporalAdjuster;
74 import java.time.temporal.TemporalUnit;
75
76 /**
77 * A date expressed in terms of a standard year-month-day calendar system.
78 * <p>
79 * This class is used by applications seeking to handle dates in non-ISO calendar systems.
80 * For example, the Japanese, Minguo, Thai Buddhist and others.
81 * <p>
82 * {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
83 * The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between
84 * the fields and this class allows the resulting date to be manipulated.
85 * <p>
86 * Note that not all calendar systems are suitable for use with this class.
87 * For example, the Mayan calendar uses a system that bears no relation to years, months and days.
88 * <p>
89 * The API design encourages the use of {@code LocalDate} for the majority of the application.
90 * This includes code to read and write from a persistent data store, such as a database,
91 * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
92 * at the user interface level to deal with localized input/output.
93 *
94 * <P>Example: </p>
95 * <pre>
96 * System.out.printf("Example()%n");
97 * // Enumerate the list of available calendars and print today for each
98 * Set<Chronology> chronos = Chronology.getAvailableChronologies();
99 * for (Chronology chrono : chronos) {
100 * ChronoLocalDate<?> date = chrono.dateNow();
101 * System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
102 * }
103 *
104 * // Print the Hijrah date and calendar
105 * ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow();
106 * int day = date.get(ChronoField.DAY_OF_MONTH);
107 * int dow = date.get(ChronoField.DAY_OF_WEEK);
108 * int month = date.get(ChronoField.MONTH_OF_YEAR);
109 * int year = date.get(ChronoField.YEAR);
110 * System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
111 * dow, day, month, year);
112
113 * // Print today's date and the last day of the year
114 * ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow();
115 * ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1)
116 * .with(ChronoField.MONTH_OF_YEAR, 1);
117 * ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS)
118 * .minus(1, ChronoUnit.DAYS);
119 * System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
120 * first, last);
121 * </pre>
122 *
123 * <h3>Adding Calendars</h3>
124 * <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
125 * to represent a date instance and an implementation of {@code Chronology}
126 * to be the factory for the ChronoLocalDate subclass.
127 * </p>
128 * <p> To permit the discovery of the additional calendar types the implementation of
129 * {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface
130 * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
131 * The subclass must function according to the {@code Chronology} class description and must provide its
132 * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
133 *
134 * <h3>Specification for implementors</h3>
135 * This abstract class must be implemented with care to ensure other classes operate correctly.
136 * All implementations that can be instantiated must be final, immutable and thread-safe.
137 * Subclasses should be Serializable wherever possible.
151 * Creates an instance.
152 */
153 ChronoDateImpl() {
154 }
155
156 //-----------------------------------------------------------------------
157 @Override
158 public D plus(long amountToAdd, TemporalUnit unit) {
159 if (unit instanceof ChronoUnit) {
160 ChronoUnit f = (ChronoUnit) unit;
161 switch (f) {
162 case DAYS: return plusDays(amountToAdd);
163 case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
164 case MONTHS: return plusMonths(amountToAdd);
165 case YEARS: return plusYears(amountToAdd);
166 case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
167 case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
168 case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
169 case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
170 }
171 throw new DateTimeException("Unsupported unit: " + unit.getName());
172 }
173 return ChronoLocalDate.super.plus(amountToAdd, unit);
174 }
175
176 //-----------------------------------------------------------------------
177 /**
178 * Returns a copy of this date with the specified period in years added.
179 * <p>
180 * This adds the specified period in years to the date.
181 * In some cases, adding years can cause the resulting date to become invalid.
182 * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
183 * that the result is valid. Typically this will select the last valid day of the month.
184 * <p>
185 * This instance is immutable and unaffected by this method call.
186 *
187 * @param yearsToAdd the years to add, may be negative
188 * @return a date based on this one with the years added, not null
189 * @throws DateTimeException if the result exceeds the supported date range
190 */
191 abstract D plusYears(long yearsToAdd);
306 * The default implementation uses {@link #plusDays(long)}.
307 * <p>
308 * This instance is immutable and unaffected by this method call.
309 *
310 * @param daysToSubtract the days to subtract, may be negative
311 * @return a date based on this one with the days subtracted, not null
312 * @throws DateTimeException if the result exceeds the supported date range
313 */
314 D minusDays(long daysToSubtract) {
315 return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
316 }
317
318 //-----------------------------------------------------------------------
319 /**
320 * {@inheritDoc}
321 * @throws DateTimeException {@inheritDoc}
322 * @throws ArithmeticException {@inheritDoc}
323 */
324 @Override
325 public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
326 if (endDateTime instanceof ChronoLocalDate == false) {
327 throw new DateTimeException("Unable to calculate period between objects of two different types");
328 }
329 ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
330 if (getChronology().equals(end.getChronology()) == false) {
331 throw new DateTimeException("Unable to calculate period between two different chronologies");
332 }
333 if (unit instanceof ChronoUnit) {
334 return LocalDate.from(this).periodUntil(end, unit); // TODO: this is wrong
335 }
336 return unit.between(this, endDateTime);
337 }
338
339 @Override
340 public boolean equals(Object obj) {
341 if (this == obj) {
342 return true;
343 }
344 if (obj instanceof ChronoLocalDate) {
345 return compareTo((ChronoLocalDate<?>) obj) == 0;
346 }
347 return false;
348 }
349
350 @Override
351 public int hashCode() {
352 long epDay = toEpochDay();
353 return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
354 }
355
356 @Override
357 public String toString() {
358 // getLong() reduces chances of exceptions in toString()
|
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
49 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57 package java.time.chrono;
58
59 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
60 import static java.time.temporal.ChronoField.ERA;
61 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
62 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
63 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
64
65 import java.io.Serializable;
66 import java.time.DateTimeException;
67 import java.time.temporal.ChronoUnit;
68 import java.time.temporal.Temporal;
69 import java.time.temporal.TemporalAdjuster;
70 import java.time.temporal.TemporalUnit;
71 import java.time.temporal.UnsupportedTemporalTypeException;
72 import java.time.temporal.ValueRange;
73 import java.util.Objects;
74
75 /**
76 * A date expressed in terms of a standard year-month-day calendar system.
77 * <p>
78 * This class is used by applications seeking to handle dates in non-ISO calendar systems.
79 * For example, the Japanese, Minguo, Thai Buddhist and others.
80 * <p>
81 * {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
82 * The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between
83 * the fields and this class allows the resulting date to be manipulated.
84 * <p>
85 * Note that not all calendar systems are suitable for use with this class.
86 * For example, the Mayan calendar uses a system that bears no relation to years, months and days.
87 * <p>
88 * The API design encourages the use of {@code LocalDate} for the majority of the application.
89 * This includes code to read and write from a persistent data store, such as a database,
90 * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
91 * at the user interface level to deal with localized input/output.
92 *
93 * <P>Example: </p>
94 * <pre>
95 * System.out.printf("Example()%n");
96 * // Enumerate the list of available calendars and print today for each
97 * Set<Chronology> chronos = Chronology.getAvailableChronologies();
98 * for (Chronology chrono : chronos) {
99 * ChronoLocalDate<?> date = chrono.dateNow();
100 * System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
101 * }
102 *
103 * // Print the Hijrah date and calendar
104 * ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow();
105 * int day = date.get(ChronoField.DAY_OF_MONTH);
106 * int dow = date.get(ChronoField.DAY_OF_WEEK);
107 * int month = date.get(ChronoField.MONTH_OF_YEAR);
108 * int year = date.get(ChronoField.YEAR);
109 * System.out.printf(" Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
110 * dow, day, month, year);
111
112 * // Print today's date and the last day of the year
113 * ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow();
114 * ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1)
115 * .with(ChronoField.MONTH_OF_YEAR, 1);
116 * ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS)
117 * .minus(1, ChronoUnit.DAYS);
118 * System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
119 * first, last);
120 * </pre>
121 *
122 * <h3>Adding Calendars</h3>
123 * <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
124 * to represent a date instance and an implementation of {@code Chronology}
125 * to be the factory for the ChronoLocalDate subclass.
126 * </p>
127 * <p> To permit the discovery of the additional calendar types the implementation of
128 * {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface
129 * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
130 * The subclass must function according to the {@code Chronology} class description and must provide its
131 * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
132 *
133 * <h3>Specification for implementors</h3>
134 * This abstract class must be implemented with care to ensure other classes operate correctly.
135 * All implementations that can be instantiated must be final, immutable and thread-safe.
136 * Subclasses should be Serializable wherever possible.
150 * Creates an instance.
151 */
152 ChronoDateImpl() {
153 }
154
155 //-----------------------------------------------------------------------
156 @Override
157 public D plus(long amountToAdd, TemporalUnit unit) {
158 if (unit instanceof ChronoUnit) {
159 ChronoUnit f = (ChronoUnit) unit;
160 switch (f) {
161 case DAYS: return plusDays(amountToAdd);
162 case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
163 case MONTHS: return plusMonths(amountToAdd);
164 case YEARS: return plusYears(amountToAdd);
165 case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
166 case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
167 case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
168 case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
169 }
170 throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
171 }
172 return ChronoLocalDate.super.plus(amountToAdd, unit);
173 }
174
175 //-----------------------------------------------------------------------
176 /**
177 * Returns a copy of this date with the specified period in years added.
178 * <p>
179 * This adds the specified period in years to the date.
180 * In some cases, adding years can cause the resulting date to become invalid.
181 * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
182 * that the result is valid. Typically this will select the last valid day of the month.
183 * <p>
184 * This instance is immutable and unaffected by this method call.
185 *
186 * @param yearsToAdd the years to add, may be negative
187 * @return a date based on this one with the years added, not null
188 * @throws DateTimeException if the result exceeds the supported date range
189 */
190 abstract D plusYears(long yearsToAdd);
305 * The default implementation uses {@link #plusDays(long)}.
306 * <p>
307 * This instance is immutable and unaffected by this method call.
308 *
309 * @param daysToSubtract the days to subtract, may be negative
310 * @return a date based on this one with the days subtracted, not null
311 * @throws DateTimeException if the result exceeds the supported date range
312 */
313 D minusDays(long daysToSubtract) {
314 return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
315 }
316
317 //-----------------------------------------------------------------------
318 /**
319 * {@inheritDoc}
320 * @throws DateTimeException {@inheritDoc}
321 * @throws ArithmeticException {@inheritDoc}
322 */
323 @Override
324 public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
325 Objects.requireNonNull(endDateTime, "endDateTime");
326 Objects.requireNonNull(unit, "unit");
327 if (endDateTime instanceof ChronoLocalDate == false) {
328 throw new DateTimeException("Unable to calculate period between objects of two different types");
329 }
330 ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
331 if (getChronology().equals(end.getChronology()) == false) {
332 throw new DateTimeException("Unable to calculate period between two different chronologies");
333 }
334 if (unit instanceof ChronoUnit) {
335 switch ((ChronoUnit) unit) {
336 case DAYS: return daysUntil(end);
337 case WEEKS: return daysUntil(end) / 7;
338 case MONTHS: return monthsUntil(end);
339 case YEARS: return monthsUntil(end) / 12;
340 case DECADES: return monthsUntil(end) / 120;
341 case CENTURIES: return monthsUntil(end) / 1200;
342 case MILLENNIA: return monthsUntil(end) / 12000;
343 case ERAS: return end.getLong(ERA) - getLong(ERA);
344 }
345 throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
346 }
347 return unit.between(this, endDateTime);
348 }
349
350 private long daysUntil(ChronoLocalDate<?> end) {
351 return end.toEpochDay() - toEpochDay(); // no overflow
352 }
353
354 private long monthsUntil(ChronoLocalDate<?> end) {
355 ValueRange range = getChronology().range(MONTH_OF_YEAR);
356 if (range.getMaximum() != 12) {
357 throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year");
358 }
359 long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH); // no overflow
360 long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH); // no overflow
361 return (packed2 - packed1) / 32;
362 }
363
364 @Override
365 public boolean equals(Object obj) {
366 if (this == obj) {
367 return true;
368 }
369 if (obj instanceof ChronoLocalDate) {
370 return compareTo((ChronoLocalDate<?>) obj) == 0;
371 }
372 return false;
373 }
374
375 @Override
376 public int hashCode() {
377 long epDay = toEpochDay();
378 return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
379 }
380
381 @Override
382 public String toString() {
383 // getLong() reduces chances of exceptions in toString()
|