• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.chrono;
33 
34 import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY;
35 import static org.threeten.bp.temporal.ChronoField.NANO_OF_DAY;
36 import static org.threeten.bp.temporal.ChronoUnit.NANOS;
37 
38 import java.util.Comparator;
39 
40 import org.threeten.bp.DateTimeException;
41 import org.threeten.bp.Instant;
42 import org.threeten.bp.LocalDate;
43 import org.threeten.bp.LocalDateTime;
44 import org.threeten.bp.LocalTime;
45 import org.threeten.bp.ZoneId;
46 import org.threeten.bp.ZoneOffset;
47 import org.threeten.bp.format.DateTimeFormatter;
48 import org.threeten.bp.jdk8.DefaultInterfaceTemporal;
49 import org.threeten.bp.jdk8.Jdk8Methods;
50 import org.threeten.bp.temporal.ChronoField;
51 import org.threeten.bp.temporal.Temporal;
52 import org.threeten.bp.temporal.TemporalAccessor;
53 import org.threeten.bp.temporal.TemporalAdjuster;
54 import org.threeten.bp.temporal.TemporalAmount;
55 import org.threeten.bp.temporal.TemporalField;
56 import org.threeten.bp.temporal.TemporalQueries;
57 import org.threeten.bp.temporal.TemporalQuery;
58 import org.threeten.bp.temporal.TemporalUnit;
59 import org.threeten.bp.zone.ZoneRules;
60 
61 /**
62  * A date-time without a time-zone in an arbitrary chronology, intended
63  * for advanced globalization use cases.
64  * <p>
65  * <b>Most applications should declare method signatures, fields and variables
66  * as {@link LocalDateTime}, not this interface.</b>
67  * <p>
68  * A {@code ChronoLocalDateTime} is the abstract representation of a local date-time
69  * where the {@code Chronology chronology}, or calendar system, is pluggable.
70  * The date-time is defined in terms of fields expressed by {@link TemporalField},
71  * where most common implementations are defined in {@link ChronoField}.
72  * The chronology defines how the calendar system operates and the meaning of
73  * the standard fields.
74  *
75  * <h4>When to use this interface</h4>
76  * The design of the API encourages the use of {@code LocalDateTime} rather than this
77  * interface, even in the case where the application needs to deal with multiple
78  * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
79  * <p>
80  * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
81  * before using this interface.
82  *
83  * <h3>Specification for implementors</h3>
84  * This interface must be implemented with care to ensure other classes operate correctly.
85  * All implementations that can be instantiated must be final, immutable and thread-safe.
86  * Subclasses should be Serializable wherever possible.
87  * <p>
88  * In JDK 8, this is an interface with default methods.
89  * Since there are no default methods in JDK 7, an abstract class is used.
90  *
91  * @param <D> the date type
92  */
93 public abstract class ChronoLocalDateTime<D extends ChronoLocalDate>
94         extends DefaultInterfaceTemporal
95         implements Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
96 
97     /**
98      * Gets a comparator that compares {@code ChronoLocalDateTime} in
99      * time-line order ignoring the chronology.
100      * <p>
101      * This comparator differs from the comparison in {@link #compareTo} in that it
102      * only compares the underlying date-time and not the chronology.
103      * This allows dates in different calendar systems to be compared based
104      * on the position of the date-time on the local time-line.
105      * The underlying comparison is equivalent to comparing the epoch-day and nano-of-day.
106      *
107      * @return a comparator that compares in time-line order ignoring the chronology
108      * @see #isAfter
109      * @see #isBefore
110      * @see #isEqual
111      */
timeLineOrder()112     public static Comparator<ChronoLocalDateTime<?>> timeLineOrder() {
113         return DATE_TIME_COMPARATOR;
114     }
115     private static final Comparator<ChronoLocalDateTime<?>> DATE_TIME_COMPARATOR =
116             new Comparator<ChronoLocalDateTime<?>>() {
117         @Override
118         public int compare(ChronoLocalDateTime<?> datetime1, ChronoLocalDateTime<?> datetime2) {
119             int cmp = Jdk8Methods.compareLongs(datetime1.toLocalDate().toEpochDay(), datetime2.toLocalDate().toEpochDay());
120             if (cmp == 0) {
121                 cmp = Jdk8Methods.compareLongs(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay());
122             }
123             return cmp;
124         }
125     };
126 
127     //-----------------------------------------------------------------------
128     /**
129      * Obtains an instance of {@code ChronoLocalDateTime} from a temporal object.
130      * <p>
131      * This obtains a local date-time based on the specified temporal.
132      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
133      * which this factory converts to an instance of {@code ChronoLocalDateTime}.
134      * <p>
135      * The conversion extracts and combines the chronology and the date-time
136      * from the temporal object. The behavior is equivalent to using
137      * {@link Chronology#localDateTime(TemporalAccessor)} with the extracted chronology.
138      * Implementations are permitted to perform optimizations such as accessing
139      * those fields that are equivalent to the relevant objects.
140      * <p>
141      * This method matches the signature of the functional interface {@link TemporalQuery}
142      * allowing it to be used as a query via method reference, {@code ChronoLocalDateTime::from}.
143      *
144      * @param temporal  the temporal object to convert, not null
145      * @return the date-time, not null
146      * @throws DateTimeException if unable to convert to a {@code ChronoLocalDateTime}
147      * @see Chronology#localDateTime(TemporalAccessor)
148      */
from(TemporalAccessor temporal)149     public static ChronoLocalDateTime<?> from(TemporalAccessor temporal) {
150         Jdk8Methods.requireNonNull(temporal, "temporal");
151         if (temporal instanceof ChronoLocalDateTime) {
152             return (ChronoLocalDateTime<?>) temporal;
153         }
154         Chronology chrono = temporal.query(TemporalQueries.chronology());
155         if (chrono == null) {
156             throw new DateTimeException("No Chronology found to create ChronoLocalDateTime: " + temporal.getClass());
157         }
158         return chrono.localDateTime(temporal);
159     }
160 
161     //-----------------------------------------------------------------------
162     /**
163      * Gets the chronology of this date-time.
164      * <p>
165      * The {@code Chronology} represents the calendar system in use.
166      * The era and other fields in {@link ChronoField} are defined by the chronology.
167      *
168      * @return the chronology, not null
169      */
getChronology()170     public Chronology getChronology() {
171         return toLocalDate().getChronology();
172     }
173 
174     /**
175      * Gets the local date part of this date-time.
176      * <p>
177      * This returns a local date with the same year, month and day
178      * as this date-time.
179      *
180      * @return the date part of this date-time, not null
181      */
toLocalDate()182     public abstract D toLocalDate() ;
183 
184     /**
185      * Gets the local time part of this date-time.
186      * <p>
187      * This returns a local time with the same hour, minute, second and
188      * nanosecond as this date-time.
189      *
190      * @return the time part of this date-time, not null
191      */
toLocalTime()192     public abstract LocalTime toLocalTime();
193 
194     //-------------------------------------------------------------------------
195     // override for covariant return type
196     @Override
with(TemporalAdjuster adjuster)197     public ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) {
198         return toLocalDate().getChronology().ensureChronoLocalDateTime(super.with(adjuster));
199     }
200 
201     @Override
with(TemporalField field, long newValue)202     public abstract ChronoLocalDateTime<D> with(TemporalField field, long newValue);
203 
204     @Override
plus(TemporalAmount amount)205     public ChronoLocalDateTime<D> plus(TemporalAmount amount) {
206         return toLocalDate().getChronology().ensureChronoLocalDateTime(super.plus(amount));
207     }
208 
209     @Override
plus(long amountToAdd, TemporalUnit unit)210     public abstract ChronoLocalDateTime<D> plus(long amountToAdd, TemporalUnit unit);
211 
212     @Override
minus(TemporalAmount amount)213     public ChronoLocalDateTime<D> minus(TemporalAmount amount) {
214         return toLocalDate().getChronology().ensureChronoLocalDateTime(super.minus(amount));
215     }
216 
217     @Override
minus(long amountToSubtract, TemporalUnit unit)218     public ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
219         return toLocalDate().getChronology().ensureChronoLocalDateTime(super.minus(amountToSubtract, unit));
220     }
221 
222     //-----------------------------------------------------------------------
223     @SuppressWarnings("unchecked")
224     @Override
query(TemporalQuery<R> query)225     public <R> R query(TemporalQuery<R> query) {
226         if (query == TemporalQueries.chronology()) {
227             return (R) getChronology();
228         } else if (query == TemporalQueries.precision()) {
229             return (R) NANOS;
230         } else if (query == TemporalQueries.localDate()) {
231             return (R) LocalDate.ofEpochDay(toLocalDate().toEpochDay());
232         } else if (query == TemporalQueries.localTime()) {
233             return (R) toLocalTime();
234         } else if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId() || query == TemporalQueries.offset()) {
235             return null;
236         }
237         return super.query(query);
238     }
239 
240     @Override
adjustInto(Temporal temporal)241     public Temporal adjustInto(Temporal temporal) {
242         return temporal
243                 .with(EPOCH_DAY, toLocalDate().toEpochDay())
244                 .with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
245     }
246 
247     /**
248      * Formats this date-time using the specified formatter.
249      * <p>
250      * This date-time will be passed to the formatter to produce a string.
251      * <p>
252      * The default implementation must behave as follows:
253      * <pre>
254      *  return formatter.format(this);
255      * </pre>
256      *
257      * @param formatter  the formatter to use, not null
258      * @return the formatted date-time string, not null
259      * @throws DateTimeException if an error occurs during printing
260      */
format(DateTimeFormatter formatter)261     public String format(DateTimeFormatter formatter) {
262         Jdk8Methods.requireNonNull(formatter, "formatter");
263         return formatter.format(this);
264     }
265 
266     //-----------------------------------------------------------------------
267     /**
268      * Combines this time with a time-zone to create a {@code ChronoZonedDateTime}.
269      * <p>
270      * This returns a {@code ChronoZonedDateTime} formed from this date-time at the
271      * specified time-zone. The result will match this date-time as closely as possible.
272      * Time-zone rules, such as daylight savings, mean that not every local date-time
273      * is valid for the specified zone, thus the local date-time may be adjusted.
274      * <p>
275      * The local date-time is resolved to a single instant on the time-line.
276      * This is achieved by finding a valid offset from UTC/Greenwich for the local
277      * date-time as defined by the {@link ZoneRules rules} of the zone ID.
278      *<p>
279      * In most cases, there is only one valid offset for a local date-time.
280      * In the case of an overlap, where clocks are set back, there are two valid offsets.
281      * This method uses the earlier offset typically corresponding to "summer".
282      * <p>
283      * In the case of a gap, where clocks jump forward, there is no valid offset.
284      * Instead, the local date-time is adjusted to be later by the length of the gap.
285      * For a typical one hour daylight savings change, the local date-time will be
286      * moved one hour later into the offset typically corresponding to "summer".
287      * <p>
288      * To obtain the later offset during an overlap, call
289      * {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
290      *
291      * @param zone  the time-zone to use, not null
292      * @return the zoned date-time formed from this date-time, not null
293      */
atZone(ZoneId zone)294     public abstract ChronoZonedDateTime<D> atZone(ZoneId zone);
295 
296     //-----------------------------------------------------------------------
297     /**
298      * Converts this date-time to an {@code Instant}.
299      * <p>
300      * This combines this local date-time and the specified offset to form
301      * an {@code Instant}.
302      *
303      * @param offset  the offset to use for the conversion, not null
304      * @return an {@code Instant} representing the same instant, not null
305      */
toInstant(ZoneOffset offset)306     public Instant toInstant(ZoneOffset offset) {
307         return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano());
308     }
309 
310     /**
311      * Converts this date-time to the number of seconds from the epoch
312      * of 1970-01-01T00:00:00Z.
313      * <p>
314      * This combines this local date-time and the specified offset to calculate the
315      * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
316      * Instants on the time-line after the epoch are positive, earlier are negative.
317      *
318      * @param offset  the offset to use for the conversion, not null
319      * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
320      */
toEpochSecond(ZoneOffset offset)321     public long toEpochSecond(ZoneOffset offset) {
322         Jdk8Methods.requireNonNull(offset, "offset");
323         long epochDay = toLocalDate().toEpochDay();
324         long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
325         secs -= offset.getTotalSeconds();
326         return secs;
327     }
328 
329     //-----------------------------------------------------------------------
330     /**
331      * Compares this date-time to another date-time, including the chronology.
332      * <p>
333      * The comparison is based first on the underlying time-line date-time, then
334      * on the chronology.
335      * It is "consistent with equals", as defined by {@link Comparable}.
336      * <p>
337      * For example, the following is the comparator order:
338      * <ol>
339      * <li>{@code 2012-12-03T12:00 (ISO)}</li>
340      * <li>{@code 2012-12-04T12:00 (ISO)}</li>
341      * <li>{@code 2555-12-04T12:00 (ThaiBuddhist)}</li>
342      * <li>{@code 2012-12-05T12:00 (ISO)}</li>
343      * </ol>
344      * Values #2 and #3 represent the same date-time on the time-line.
345      * When two values represent the same date-time, the chronology ID is compared to distinguish them.
346      * This step is needed to make the ordering "consistent with equals".
347      * <p>
348      * If all the date-time objects being compared are in the same chronology, then the
349      * additional chronology stage is not required and only the local date-time is used.
350      *
351      * @param other  the other date-time to compare to, not null
352      * @return the comparator value, negative if less, positive if greater
353      */
354     @Override
compareTo(ChronoLocalDateTime<?> other)355     public int compareTo(ChronoLocalDateTime<?> other) {
356         int cmp = toLocalDate().compareTo(other.toLocalDate());
357         if (cmp == 0) {
358             cmp = toLocalTime().compareTo(other.toLocalTime());
359             if (cmp == 0) {
360                 cmp = getChronology().compareTo(other.getChronology());
361             }
362         }
363         return cmp;
364     }
365 
366     /**
367      * Checks if this date-time is after the specified date-time ignoring the chronology.
368      * <p>
369      * This method differs from the comparison in {@link #compareTo} in that it
370      * only compares the underlying date-time and not the chronology.
371      * This allows dates in different calendar systems to be compared based
372      * on the time-line position.
373      *
374      * @param other  the other date-time to compare to, not null
375      * @return true if this is after the specified date-time
376      */
isAfter(ChronoLocalDateTime<?> other)377     public boolean isAfter(ChronoLocalDateTime<?> other) {
378         long thisEpDay = this.toLocalDate().toEpochDay();
379         long otherEpDay = other.toLocalDate().toEpochDay();
380         return thisEpDay > otherEpDay ||
381             (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay());
382     }
383 
384     /**
385      * Checks if this date-time is before the specified date-time ignoring the chronology.
386      * <p>
387      * This method differs from the comparison in {@link #compareTo} in that it
388      * only compares the underlying date-time and not the chronology.
389      * This allows dates in different calendar systems to be compared based
390      * on the time-line position.
391      *
392      * @param other  the other date-time to compare to, not null
393      * @return true if this is before the specified date-time
394      */
isBefore(ChronoLocalDateTime<?> other)395     public boolean isBefore(ChronoLocalDateTime<?> other) {
396         long thisEpDay = this.toLocalDate().toEpochDay();
397         long otherEpDay = other.toLocalDate().toEpochDay();
398         return thisEpDay < otherEpDay ||
399             (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay());
400     }
401 
402     /**
403      * Checks if this date-time is equal to the specified date-time ignoring the chronology.
404      * <p>
405      * This method differs from the comparison in {@link #compareTo} in that it
406      * only compares the underlying date and time and not the chronology.
407      * This allows date-times in different calendar systems to be compared based
408      * on the time-line position.
409      *
410      * @param other  the other date-time to compare to, not null
411      * @return true if the underlying date-time is equal to the specified date-time on the timeline
412      */
isEqual(ChronoLocalDateTime<?> other)413     public boolean isEqual(ChronoLocalDateTime<?> other) {
414         // Do the time check first, it is cheaper than computing EPOCH day.
415         return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() &&
416                this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay();
417     }
418 
419     //-----------------------------------------------------------------------
420     /**
421      * Checks if this date-time is equal to another date-time, including the chronology.
422      * <p>
423      * Compares this date-time with another ensuring that the date-time and chronology are the same.
424      *
425      * @param obj  the object to check, null returns false
426      * @return true if this is equal to the other date
427      */
428     @Override
equals(Object obj)429     public boolean equals(Object obj) {
430         if (this == obj) {
431             return true;
432         }
433         if (obj instanceof ChronoLocalDateTime) {
434             return compareTo((ChronoLocalDateTime<?>) obj) == 0;
435         }
436         return false;
437     }
438 
439     /**
440      * A hash code for this date-time.
441      *
442      * @return a suitable hash code
443      */
444     @Override
hashCode()445     public int hashCode() {
446         return toLocalDate().hashCode() ^ toLocalTime().hashCode();
447     }
448 
449     //-----------------------------------------------------------------------
450     /**
451      * Outputs this date-time as a {@code String}.
452      * <p>
453      * The output will include the full local date-time and the chronology ID.
454      *
455      * @return a string representation of this date-time, not null
456      */
457     @Override
toString()458     public String toString() {
459         return toLocalDate().toString() + 'T' + toLocalTime().toString();
460     }
461 
462 }
463