jdk/src/share/classes/java/time/temporal/ChronoLocalDateTimeImpl.java
changeset 15658 55b829ca2334
parent 15657 c588664d547e
child 15659 e575dab44ff5
equal deleted inserted replaced
15657:c588664d547e 15658:55b829ca2334
     1 /*
       
     2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 /*
       
    27  * This file is available under and governed by the GNU General Public
       
    28  * License version 2 only, as published by the Free Software Foundation.
       
    29  * However, the following notice accompanied the original version of this
       
    30  * file:
       
    31  *
       
    32  * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
       
    33  *
       
    34  * All rights reserved.
       
    35  *
       
    36  * Redistribution and use in source and binary forms, with or without
       
    37  * modification, are permitted provided that the following conditions are met:
       
    38  *
       
    39  *  * Redistributions of source code must retain the above copyright notice,
       
    40  *    this list of conditions and the following disclaimer.
       
    41  *
       
    42  *  * Redistributions in binary form must reproduce the above copyright notice,
       
    43  *    this list of conditions and the following disclaimer in the documentation
       
    44  *    and/or other materials provided with the distribution.
       
    45  *
       
    46  *  * Neither the name of JSR-310 nor the names of its contributors
       
    47  *    may be used to endorse or promote products derived from this software
       
    48  *    without specific prior written permission.
       
    49  *
       
    50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    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.
       
    61  */
       
    62 package java.time.temporal;
       
    63 
       
    64 import static java.time.temporal.ChronoField.EPOCH_DAY;
       
    65 
       
    66 import java.io.IOException;
       
    67 import java.io.InvalidObjectException;
       
    68 import java.io.ObjectInput;
       
    69 import java.io.ObjectOutput;
       
    70 import java.io.ObjectStreamException;
       
    71 import java.io.Serializable;
       
    72 import java.time.DateTimeException;
       
    73 import java.time.LocalTime;
       
    74 import java.time.ZoneId;
       
    75 import java.util.Objects;
       
    76 
       
    77 /**
       
    78  * A date-time without a time-zone for the calendar neutral API.
       
    79  * <p>
       
    80  * {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often
       
    81  * viewed as year-month-day-hour-minute-second. This object can also access other
       
    82  * fields such as day-of-year, day-of-week and week-of-year.
       
    83  * <p>
       
    84  * This class stores all date and time fields, to a precision of nanoseconds.
       
    85  * It does not store or represent a time-zone. For example, the value
       
    86  * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
       
    87  *
       
    88  * <h3>Specification for implementors</h3>
       
    89  * This class is immutable and thread-safe.
       
    90  *
       
    91  * @param <C> the chronology of this date
       
    92  * @since 1.8
       
    93  */
       
    94 final class ChronoLocalDateTimeImpl<C extends Chrono<C>>
       
    95         implements  ChronoLocalDateTime<C>, Temporal, TemporalAdjuster, Serializable {
       
    96 
       
    97     /**
       
    98      * Serialization version.
       
    99      */
       
   100     private static final long serialVersionUID = 4556003607393004514L;
       
   101     /**
       
   102      * Hours per day.
       
   103      */
       
   104     static final int HOURS_PER_DAY = 24;
       
   105     /**
       
   106      * Minutes per hour.
       
   107      */
       
   108     static final int MINUTES_PER_HOUR = 60;
       
   109     /**
       
   110      * Minutes per day.
       
   111      */
       
   112     static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
       
   113     /**
       
   114      * Seconds per minute.
       
   115      */
       
   116     static final int SECONDS_PER_MINUTE = 60;
       
   117     /**
       
   118      * Seconds per hour.
       
   119      */
       
   120     static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
       
   121     /**
       
   122      * Seconds per day.
       
   123      */
       
   124     static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
       
   125     /**
       
   126      * Milliseconds per day.
       
   127      */
       
   128     static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
       
   129     /**
       
   130      * Microseconds per day.
       
   131      */
       
   132     static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
       
   133     /**
       
   134      * Nanos per second.
       
   135      */
       
   136     static final long NANOS_PER_SECOND = 1000_000_000L;
       
   137     /**
       
   138      * Nanos per minute.
       
   139      */
       
   140     static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
       
   141     /**
       
   142      * Nanos per hour.
       
   143      */
       
   144     static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
       
   145     /**
       
   146      * Nanos per day.
       
   147      */
       
   148     static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
       
   149 
       
   150     /**
       
   151      * The date part.
       
   152      */
       
   153     private final ChronoLocalDate<C> date;
       
   154     /**
       
   155      * The time part.
       
   156      */
       
   157     private final LocalTime time;
       
   158 
       
   159     //-----------------------------------------------------------------------
       
   160     /**
       
   161      * Obtains an instance of {@code ChronoLocalDateTime} from a date and time.
       
   162      *
       
   163      * @param date  the local date, not null
       
   164      * @param time  the local time, not null
       
   165      * @return the local date-time, not null
       
   166      */
       
   167     static <R extends Chrono<R>> ChronoLocalDateTimeImpl<R> of(ChronoLocalDate<R> date, LocalTime time) {
       
   168         return new ChronoLocalDateTimeImpl<>(date, time);
       
   169     }
       
   170 
       
   171     /**
       
   172      * Constructor.
       
   173      *
       
   174      * @param date  the date part of the date-time, not null
       
   175      * @param time  the time part of the date-time, not null
       
   176      */
       
   177     private ChronoLocalDateTimeImpl(ChronoLocalDate<C> date, LocalTime time) {
       
   178         Objects.requireNonNull(date, "date");
       
   179         Objects.requireNonNull(time, "time");
       
   180         this.date = date;
       
   181         this.time = time;
       
   182     }
       
   183 
       
   184     /**
       
   185      * Returns a copy of this date-time with the new date and time, checking
       
   186      * to see if a new object is in fact required.
       
   187      *
       
   188      * @param newDate  the date of the new date-time, not null
       
   189      * @param newTime  the time of the new date-time, not null
       
   190      * @return the date-time, not null
       
   191      */
       
   192     private ChronoLocalDateTimeImpl<C> with(Temporal newDate, LocalTime newTime) {
       
   193         if (date == newDate && time == newTime) {
       
   194             return this;
       
   195         }
       
   196         // Validate that the new Temporal is a ChronoLocalDate (and not something else)
       
   197         ChronoLocalDate<C> cd = date.getChrono().ensureChronoLocalDate(newDate);
       
   198         return new ChronoLocalDateTimeImpl<>(cd, newTime);
       
   199     }
       
   200 
       
   201     //-----------------------------------------------------------------------
       
   202     @Override
       
   203     public ChronoLocalDate<C> getDate() {
       
   204         return date;
       
   205     }
       
   206 
       
   207     @Override
       
   208     public LocalTime getTime() {
       
   209         return time;
       
   210     }
       
   211 
       
   212     //-----------------------------------------------------------------------
       
   213     @Override
       
   214     public boolean isSupported(TemporalField field) {
       
   215         if (field instanceof ChronoField) {
       
   216             ChronoField f = (ChronoField) field;
       
   217             return f.isDateField() || f.isTimeField();
       
   218         }
       
   219         return field != null && field.doIsSupported(this);
       
   220     }
       
   221 
       
   222     @Override
       
   223     public ValueRange range(TemporalField field) {
       
   224         if (field instanceof ChronoField) {
       
   225             ChronoField f = (ChronoField) field;
       
   226             return (f.isTimeField() ? time.range(field) : date.range(field));
       
   227         }
       
   228         return field.doRange(this);
       
   229     }
       
   230 
       
   231     @Override
       
   232     public int get(TemporalField field) {
       
   233         if (field instanceof ChronoField) {
       
   234             ChronoField f = (ChronoField) field;
       
   235             return (f.isTimeField() ? time.get(field) : date.get(field));
       
   236         }
       
   237         return range(field).checkValidIntValue(getLong(field), field);
       
   238     }
       
   239 
       
   240     @Override
       
   241     public long getLong(TemporalField field) {
       
   242         if (field instanceof ChronoField) {
       
   243             ChronoField f = (ChronoField) field;
       
   244             return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
       
   245         }
       
   246         return field.doGet(this);
       
   247     }
       
   248 
       
   249     //-----------------------------------------------------------------------
       
   250     @SuppressWarnings("unchecked")
       
   251     @Override
       
   252     public ChronoLocalDateTimeImpl<C> with(TemporalAdjuster adjuster) {
       
   253         if (adjuster instanceof ChronoLocalDate) {
       
   254             // The Chrono is checked in with(date,time)
       
   255             return with((ChronoLocalDate<C>) adjuster, time);
       
   256         } else if (adjuster instanceof LocalTime) {
       
   257             return with(date, (LocalTime) adjuster);
       
   258         } else if (adjuster instanceof ChronoLocalDateTimeImpl) {
       
   259             return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster);
       
   260         }
       
   261         return date.getChrono().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
       
   262     }
       
   263 
       
   264     @Override
       
   265     public ChronoLocalDateTimeImpl<C> with(TemporalField field, long newValue) {
       
   266         if (field instanceof ChronoField) {
       
   267             ChronoField f = (ChronoField) field;
       
   268             if (f.isTimeField()) {
       
   269                 return with(date, time.with(field, newValue));
       
   270             } else {
       
   271                 return with(date.with(field, newValue), time);
       
   272             }
       
   273         }
       
   274         return date.getChrono().ensureChronoLocalDateTime(field.doWith(this, newValue));
       
   275     }
       
   276 
       
   277     //-----------------------------------------------------------------------
       
   278     @Override
       
   279     public ChronoLocalDateTimeImpl<C> plus(long amountToAdd, TemporalUnit unit) {
       
   280         if (unit instanceof ChronoUnit) {
       
   281             ChronoUnit f = (ChronoUnit) unit;
       
   282             switch (f) {
       
   283                 case NANOS: return plusNanos(amountToAdd);
       
   284                 case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
       
   285                 case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000);
       
   286                 case SECONDS: return plusSeconds(amountToAdd);
       
   287                 case MINUTES: return plusMinutes(amountToAdd);
       
   288                 case HOURS: return plusHours(amountToAdd);
       
   289                 case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
       
   290             }
       
   291             return with(date.plus(amountToAdd, unit), time);
       
   292         }
       
   293         return date.getChrono().ensureChronoLocalDateTime(unit.doPlus(this, amountToAdd));
       
   294     }
       
   295 
       
   296     private ChronoLocalDateTimeImpl<C> plusDays(long days) {
       
   297         return with(date.plus(days, ChronoUnit.DAYS), time);
       
   298     }
       
   299 
       
   300     private ChronoLocalDateTimeImpl<C> plusHours(long hours) {
       
   301         return plusWithOverflow(date, hours, 0, 0, 0);
       
   302     }
       
   303 
       
   304     private ChronoLocalDateTimeImpl<C> plusMinutes(long minutes) {
       
   305         return plusWithOverflow(date, 0, minutes, 0, 0);
       
   306     }
       
   307 
       
   308     ChronoLocalDateTimeImpl<C> plusSeconds(long seconds) {
       
   309         return plusWithOverflow(date, 0, 0, seconds, 0);
       
   310     }
       
   311 
       
   312     private ChronoLocalDateTimeImpl<C> plusNanos(long nanos) {
       
   313         return plusWithOverflow(date, 0, 0, 0, nanos);
       
   314     }
       
   315 
       
   316     //-----------------------------------------------------------------------
       
   317     private ChronoLocalDateTimeImpl<C> plusWithOverflow(ChronoLocalDate<C> newDate, long hours, long minutes, long seconds, long nanos) {
       
   318         // 9223372036854775808 long, 2147483648 int
       
   319         if ((hours | minutes | seconds | nanos) == 0) {
       
   320             return with(newDate, time);
       
   321         }
       
   322         long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
       
   323                 seconds / SECONDS_PER_DAY +                //   max/24*60*60
       
   324                 minutes / MINUTES_PER_DAY +                //   max/24*60
       
   325                 hours / HOURS_PER_DAY;                     //   max/24
       
   326         long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
       
   327                 (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
       
   328                 (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
       
   329                 (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
       
   330         long curNoD = time.toNanoOfDay();                          //   max  86400000000000
       
   331         totNanos = totNanos + curNoD;                              // total 432000000000000
       
   332         totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
       
   333         long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
       
   334         LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
       
   335         return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime);
       
   336     }
       
   337 
       
   338     //-----------------------------------------------------------------------
       
   339     @Override
       
   340     public ChronoZonedDateTime<C> atZone(ZoneId zone) {
       
   341         return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
       
   342     }
       
   343 
       
   344     //-----------------------------------------------------------------------
       
   345     @Override
       
   346     public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
       
   347         if (endDateTime instanceof ChronoLocalDateTime == false) {
       
   348             throw new DateTimeException("Unable to calculate period between objects of two different types");
       
   349         }
       
   350         @SuppressWarnings("unchecked")
       
   351         ChronoLocalDateTime<C> end = (ChronoLocalDateTime<C>) endDateTime;
       
   352         if (getDate().getChrono().equals(end.getDate().getChrono()) == false) {
       
   353             throw new DateTimeException("Unable to calculate period between two different chronologies");
       
   354         }
       
   355         if (unit instanceof ChronoUnit) {
       
   356             ChronoUnit f = (ChronoUnit) unit;
       
   357             if (f.isTimeUnit()) {
       
   358                 long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
       
   359                 switch (f) {
       
   360                     case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
       
   361                     case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
       
   362                     case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
       
   363                     case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
       
   364                     case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
       
   365                     case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
       
   366                     case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
       
   367                 }
       
   368                 return Math.addExact(amount, time.periodUntil(end.getTime(), unit));
       
   369             }
       
   370             ChronoLocalDate<C> endDate = end.getDate();
       
   371             if (end.getTime().isBefore(time)) {
       
   372                 endDate = endDate.minus(1, ChronoUnit.DAYS);
       
   373             }
       
   374             return date.periodUntil(endDate, unit);
       
   375         }
       
   376         return unit.between(this, endDateTime).getAmount();
       
   377     }
       
   378 
       
   379     //-----------------------------------------------------------------------
       
   380     private Object writeReplace() {
       
   381         return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
       
   382     }
       
   383 
       
   384     /**
       
   385      * Defend against malicious streams.
       
   386      * @return never
       
   387      * @throws InvalidObjectException always
       
   388      */
       
   389     private Object readResolve() throws ObjectStreamException {
       
   390         throw new InvalidObjectException("Deserialization via serialization delegate");
       
   391     }
       
   392 
       
   393     void writeExternal(ObjectOutput out) throws IOException {
       
   394         out.writeObject(date);
       
   395         out.writeObject(time);
       
   396     }
       
   397 
       
   398     static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
       
   399         ChronoLocalDate<?> date = (ChronoLocalDate<?>) in.readObject();
       
   400         LocalTime time = (LocalTime) in.readObject();
       
   401         return date.atTime(time);
       
   402     }
       
   403 
       
   404     //-----------------------------------------------------------------------
       
   405     @Override
       
   406     public boolean equals(Object obj) {
       
   407         if (this == obj) {
       
   408             return true;
       
   409         }
       
   410         if (obj instanceof ChronoLocalDateTime) {
       
   411             return compareTo((ChronoLocalDateTime<?>) obj) == 0;
       
   412         }
       
   413         return false;
       
   414     }
       
   415 
       
   416     @Override
       
   417     public int hashCode() {
       
   418         return getDate().hashCode() ^ getTime().hashCode();
       
   419     }
       
   420 
       
   421     @Override
       
   422     public String toString() {
       
   423         return getDate().toString() + 'T' + getTime().toString();
       
   424     }
       
   425 
       
   426 }