src/share/classes/java/time/chrono/ChronoDateImpl.java

Print this page




  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&lt;Chronology&gt; 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&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
  98  *        for (Chronology chrono : chronos) {
  99  *            ChronoLocalDate&lt;?&gt; 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&lt;?&gt; 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&lt;?&gt; now1 = Chronology.of("Hijrah").dateNow();
 114  *        ChronoLocalDate&lt;?&gt; first = now1.with(ChronoField.DAY_OF_MONTH, 1)
 115  *                .with(ChronoField.MONTH_OF_YEAR, 1);
 116  *        ChronoLocalDate&lt;?&gt; 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()