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