jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java
changeset 15658 55b829ca2334
child 16852 60207b2b4b42
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.chrono;
       
    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.time.temporal.ChronoField;
       
    76 import java.time.temporal.ChronoUnit;
       
    77 import java.time.temporal.Temporal;
       
    78 import java.time.temporal.TemporalAdjuster;
       
    79 import java.time.temporal.TemporalField;
       
    80 import java.time.temporal.TemporalUnit;
       
    81 import java.time.temporal.ValueRange;
       
    82 import java.util.Objects;
       
    83 
       
    84 /**
       
    85  * A date-time without a time-zone for the calendar neutral API.
       
    86  * <p>
       
    87  * {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often
       
    88  * viewed as year-month-day-hour-minute-second. This object can also access other
       
    89  * fields such as day-of-year, day-of-week and week-of-year.
       
    90  * <p>
       
    91  * This class stores all date and time fields, to a precision of nanoseconds.
       
    92  * It does not store or represent a time-zone. For example, the value
       
    93  * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
       
    94  *
       
    95  * <h3>Specification for implementors</h3>
       
    96  * This class is immutable and thread-safe.
       
    97  *
       
    98  * @param <D> the concrete type for the date of this date-time
       
    99  * @since 1.8
       
   100  */
       
   101 final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
       
   102         implements  ChronoLocalDateTime<D>, Temporal, TemporalAdjuster, Serializable {
       
   103 
       
   104     /**
       
   105      * Serialization version.
       
   106      */
       
   107     private static final long serialVersionUID = 4556003607393004514L;
       
   108     /**
       
   109      * Hours per day.
       
   110      */
       
   111     static final int HOURS_PER_DAY = 24;
       
   112     /**
       
   113      * Minutes per hour.
       
   114      */
       
   115     static final int MINUTES_PER_HOUR = 60;
       
   116     /**
       
   117      * Minutes per day.
       
   118      */
       
   119     static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
       
   120     /**
       
   121      * Seconds per minute.
       
   122      */
       
   123     static final int SECONDS_PER_MINUTE = 60;
       
   124     /**
       
   125      * Seconds per hour.
       
   126      */
       
   127     static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
       
   128     /**
       
   129      * Seconds per day.
       
   130      */
       
   131     static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
       
   132     /**
       
   133      * Milliseconds per day.
       
   134      */
       
   135     static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
       
   136     /**
       
   137      * Microseconds per day.
       
   138      */
       
   139     static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
       
   140     /**
       
   141      * Nanos per second.
       
   142      */
       
   143     static final long NANOS_PER_SECOND = 1000_000_000L;
       
   144     /**
       
   145      * Nanos per minute.
       
   146      */
       
   147     static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
       
   148     /**
       
   149      * Nanos per hour.
       
   150      */
       
   151     static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
       
   152     /**
       
   153      * Nanos per day.
       
   154      */
       
   155     static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
       
   156 
       
   157     /**
       
   158      * The date part.
       
   159      */
       
   160     private final D date;
       
   161     /**
       
   162      * The time part.
       
   163      */
       
   164     private final LocalTime time;
       
   165 
       
   166     //-----------------------------------------------------------------------
       
   167     /**
       
   168      * Obtains an instance of {@code ChronoLocalDateTime} from a date and time.
       
   169      *
       
   170      * @param date  the local date, not null
       
   171      * @param time  the local time, not null
       
   172      * @return the local date-time, not null
       
   173      */
       
   174     static ChronoLocalDateTimeImpl<?> of(ChronoLocalDate<?> date, LocalTime time) {
       
   175         return new ChronoLocalDateTimeImpl(date, time);
       
   176     }
       
   177 
       
   178     /**
       
   179      * Constructor.
       
   180      *
       
   181      * @param date  the date part of the date-time, not null
       
   182      * @param time  the time part of the date-time, not null
       
   183      */
       
   184     private ChronoLocalDateTimeImpl(D date, LocalTime time) {
       
   185         Objects.requireNonNull(date, "date");
       
   186         Objects.requireNonNull(time, "time");
       
   187         this.date = date;
       
   188         this.time = time;
       
   189     }
       
   190 
       
   191     /**
       
   192      * Returns a copy of this date-time with the new date and time, checking
       
   193      * to see if a new object is in fact required.
       
   194      *
       
   195      * @param newDate  the date of the new date-time, not null
       
   196      * @param newTime  the time of the new date-time, not null
       
   197      * @return the date-time, not null
       
   198      */
       
   199     private ChronoLocalDateTimeImpl<D> with(Temporal newDate, LocalTime newTime) {
       
   200         if (date == newDate && time == newTime) {
       
   201             return this;
       
   202         }
       
   203         // Validate that the new Temporal is a ChronoLocalDate (and not something else)
       
   204         D cd = (D)date.getChronology().ensureChronoLocalDate(newDate);
       
   205         return new ChronoLocalDateTimeImpl<>((D)cd, newTime);
       
   206     }
       
   207 
       
   208     //-----------------------------------------------------------------------
       
   209     @Override
       
   210     public D toLocalDate() {
       
   211         return date;
       
   212     }
       
   213 
       
   214     @Override
       
   215     public LocalTime toLocalTime() {
       
   216         return time;
       
   217     }
       
   218 
       
   219     //-----------------------------------------------------------------------
       
   220     @Override
       
   221     public boolean isSupported(TemporalField field) {
       
   222         if (field instanceof ChronoField) {
       
   223             ChronoField f = (ChronoField) field;
       
   224             return f.isDateField() || f.isTimeField();
       
   225         }
       
   226         return field != null && field.isSupportedBy(this);
       
   227     }
       
   228 
       
   229     @Override
       
   230     public ValueRange range(TemporalField field) {
       
   231         if (field instanceof ChronoField) {
       
   232             ChronoField f = (ChronoField) field;
       
   233             return (f.isTimeField() ? time.range(field) : date.range(field));
       
   234         }
       
   235         return field.rangeRefinedBy(this);
       
   236     }
       
   237 
       
   238     @Override
       
   239     public int get(TemporalField field) {
       
   240         if (field instanceof ChronoField) {
       
   241             ChronoField f = (ChronoField) field;
       
   242             return (f.isTimeField() ? time.get(field) : date.get(field));
       
   243         }
       
   244         return range(field).checkValidIntValue(getLong(field), field);
       
   245     }
       
   246 
       
   247     @Override
       
   248     public long getLong(TemporalField field) {
       
   249         if (field instanceof ChronoField) {
       
   250             ChronoField f = (ChronoField) field;
       
   251             return (f.isTimeField() ? time.getLong(field) : date.getLong(field));
       
   252         }
       
   253         return field.getFrom(this);
       
   254     }
       
   255 
       
   256     //-----------------------------------------------------------------------
       
   257     @SuppressWarnings("unchecked")
       
   258     @Override
       
   259     public ChronoLocalDateTimeImpl<D> with(TemporalAdjuster adjuster) {
       
   260         if (adjuster instanceof ChronoLocalDate) {
       
   261             // The Chronology is checked in with(date,time)
       
   262             return with((ChronoLocalDate<D>) adjuster, time);
       
   263         } else if (adjuster instanceof LocalTime) {
       
   264             return with(date, (LocalTime) adjuster);
       
   265         } else if (adjuster instanceof ChronoLocalDateTimeImpl) {
       
   266             return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster));
       
   267         }
       
   268         return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this)));
       
   269     }
       
   270 
       
   271     @Override
       
   272     public ChronoLocalDateTimeImpl<D> with(TemporalField field, long newValue) {
       
   273         if (field instanceof ChronoField) {
       
   274             ChronoField f = (ChronoField) field;
       
   275             if (f.isTimeField()) {
       
   276                 return with(date, time.with(field, newValue));
       
   277             } else {
       
   278                 return with(date.with(field, newValue), time);
       
   279             }
       
   280         }
       
   281         return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(field.adjustInto(this, newValue)));
       
   282     }
       
   283 
       
   284     //-----------------------------------------------------------------------
       
   285     @Override
       
   286     public ChronoLocalDateTimeImpl<D> plus(long amountToAdd, TemporalUnit unit) {
       
   287         if (unit instanceof ChronoUnit) {
       
   288             ChronoUnit f = (ChronoUnit) unit;
       
   289             switch (f) {
       
   290                 case NANOS: return plusNanos(amountToAdd);
       
   291                 case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
       
   292                 case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000);
       
   293                 case SECONDS: return plusSeconds(amountToAdd);
       
   294                 case MINUTES: return plusMinutes(amountToAdd);
       
   295                 case HOURS: return plusHours(amountToAdd);
       
   296                 case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
       
   297             }
       
   298             return with(date.plus(amountToAdd, unit), time);
       
   299         }
       
   300         return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(unit.addTo(this, amountToAdd)));
       
   301     }
       
   302 
       
   303     private ChronoLocalDateTimeImpl<D> plusDays(long days) {
       
   304         return with(date.plus(days, ChronoUnit.DAYS), time);
       
   305     }
       
   306 
       
   307     private ChronoLocalDateTimeImpl<D> plusHours(long hours) {
       
   308         return plusWithOverflow(date, hours, 0, 0, 0);
       
   309     }
       
   310 
       
   311     private ChronoLocalDateTimeImpl<D> plusMinutes(long minutes) {
       
   312         return plusWithOverflow(date, 0, minutes, 0, 0);
       
   313     }
       
   314 
       
   315     ChronoLocalDateTimeImpl<D> plusSeconds(long seconds) {
       
   316         return plusWithOverflow(date, 0, 0, seconds, 0);
       
   317     }
       
   318 
       
   319     private ChronoLocalDateTimeImpl<D> plusNanos(long nanos) {
       
   320         return plusWithOverflow(date, 0, 0, 0, nanos);
       
   321     }
       
   322 
       
   323     //-----------------------------------------------------------------------
       
   324     private ChronoLocalDateTimeImpl<D> plusWithOverflow(ChronoLocalDate<?> newDate, long hours, long minutes, long seconds, long nanos) {
       
   325         // 9223372036854775808 long, 2147483648 int
       
   326         if ((hours | minutes | seconds | nanos) == 0) {
       
   327             return with(newDate, time);
       
   328         }
       
   329         long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
       
   330                 seconds / SECONDS_PER_DAY +                //   max/24*60*60
       
   331                 minutes / MINUTES_PER_DAY +                //   max/24*60
       
   332                 hours / HOURS_PER_DAY;                     //   max/24
       
   333         long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
       
   334                 (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
       
   335                 (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
       
   336                 (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
       
   337         long curNoD = time.toNanoOfDay();                          //   max  86400000000000
       
   338         totNanos = totNanos + curNoD;                              // total 432000000000000
       
   339         totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
       
   340         long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
       
   341         LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
       
   342         return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime);
       
   343     }
       
   344 
       
   345     //-----------------------------------------------------------------------
       
   346     @Override
       
   347     public ChronoZonedDateTime<D> atZone(ZoneId zone) {
       
   348         return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
       
   349     }
       
   350 
       
   351     //-----------------------------------------------------------------------
       
   352     @Override
       
   353     public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
       
   354         if (endDateTime instanceof ChronoLocalDateTime == false) {
       
   355             throw new DateTimeException("Unable to calculate period between objects of two different types");
       
   356         }
       
   357         @SuppressWarnings("unchecked")
       
   358         ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) endDateTime;
       
   359         if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
       
   360             throw new DateTimeException("Unable to calculate period between two different chronologies");
       
   361         }
       
   362         if (unit instanceof ChronoUnit) {
       
   363             ChronoUnit f = (ChronoUnit) unit;
       
   364             if (f.isTimeUnit()) {
       
   365                 long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
       
   366                 switch (f) {
       
   367                     case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
       
   368                     case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
       
   369                     case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
       
   370                     case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
       
   371                     case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
       
   372                     case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
       
   373                     case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
       
   374                 }
       
   375                 return Math.addExact(amount, time.periodUntil(end.toLocalTime(), unit));
       
   376             }
       
   377             D endDate = end.toLocalDate();
       
   378             if (end.toLocalTime().isBefore(time)) {
       
   379                 endDate = (D)endDate.minus(1, ChronoUnit.DAYS);
       
   380             }
       
   381             return date.periodUntil(endDate, unit);
       
   382         }
       
   383         return unit.between(this, endDateTime);
       
   384     }
       
   385 
       
   386     //-----------------------------------------------------------------------
       
   387     private Object writeReplace() {
       
   388         return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
       
   389     }
       
   390 
       
   391     /**
       
   392      * Defend against malicious streams.
       
   393      * @return never
       
   394      * @throws InvalidObjectException always
       
   395      */
       
   396     private Object readResolve() throws ObjectStreamException {
       
   397         throw new InvalidObjectException("Deserialization via serialization delegate");
       
   398     }
       
   399 
       
   400     void writeExternal(ObjectOutput out) throws IOException {
       
   401         out.writeObject(date);
       
   402         out.writeObject(time);
       
   403     }
       
   404 
       
   405     static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
       
   406         ChronoLocalDate date = (ChronoLocalDate) in.readObject();
       
   407         LocalTime time = (LocalTime) in.readObject();
       
   408         return date.atTime(time);
       
   409     }
       
   410 
       
   411     //-----------------------------------------------------------------------
       
   412     @Override
       
   413     public boolean equals(Object obj) {
       
   414         if (this == obj) {
       
   415             return true;
       
   416         }
       
   417         if (obj instanceof ChronoLocalDateTime) {
       
   418             return compareTo((ChronoLocalDateTime<?>) obj) == 0;
       
   419         }
       
   420         return false;
       
   421     }
       
   422 
       
   423     @Override
       
   424     public int hashCode() {
       
   425         return toLocalDate().hashCode() ^ toLocalTime().hashCode();
       
   426     }
       
   427 
       
   428     @Override
       
   429     public String toString() {
       
   430         return toLocalDate().toString() + 'T' + toLocalTime().toString();
       
   431     }
       
   432 
       
   433 }