Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/time/OffsetTime.java
41152 views
1
/*
2
* Copyright (c) 2012, 2019, 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;
63
64
import static java.time.LocalTime.NANOS_PER_HOUR;
65
import static java.time.LocalTime.NANOS_PER_MINUTE;
66
import static java.time.LocalTime.NANOS_PER_SECOND;
67
import static java.time.LocalTime.SECONDS_PER_DAY;
68
import static java.time.temporal.ChronoField.NANO_OF_DAY;
69
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
70
import static java.time.temporal.ChronoUnit.NANOS;
71
72
import java.io.IOException;
73
import java.io.ObjectInput;
74
import java.io.ObjectOutput;
75
import java.io.InvalidObjectException;
76
import java.io.ObjectInputStream;
77
import java.io.Serializable;
78
import java.time.format.DateTimeFormatter;
79
import java.time.format.DateTimeParseException;
80
import java.time.temporal.ChronoField;
81
import java.time.temporal.ChronoUnit;
82
import java.time.temporal.Temporal;
83
import java.time.temporal.TemporalAccessor;
84
import java.time.temporal.TemporalAdjuster;
85
import java.time.temporal.TemporalAmount;
86
import java.time.temporal.TemporalField;
87
import java.time.temporal.TemporalQueries;
88
import java.time.temporal.TemporalQuery;
89
import java.time.temporal.TemporalUnit;
90
import java.time.temporal.UnsupportedTemporalTypeException;
91
import java.time.temporal.ValueRange;
92
import java.time.zone.ZoneRules;
93
import java.util.Objects;
94
95
/**
96
* A time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
97
* such as {@code 10:15:30+01:00}.
98
* <p>
99
* {@code OffsetTime} is an immutable date-time object that represents a time, often
100
* viewed as hour-minute-second-offset.
101
* This class stores all time fields, to a precision of nanoseconds,
102
* as well as a zone offset.
103
* For example, the value "13:45:30.123456789+02:00" can be stored
104
* in an {@code OffsetTime}.
105
* <p>
106
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
107
* class; programmers should treat instances that are
108
* {@linkplain #equals(Object) equal} as interchangeable and should not
109
* use instances for synchronization, or unpredictable behavior may
110
* occur. For example, in a future release, synchronization may fail.
111
* The {@code equals} method should be used for comparisons.
112
*
113
* @implSpec
114
* This class is immutable and thread-safe.
115
*
116
* @since 1.8
117
*/
118
@jdk.internal.ValueBased
119
public final class OffsetTime
120
implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable {
121
122
/**
123
* The minimum supported {@code OffsetTime}, '00:00:00+18:00'.
124
* This is the time of midnight at the start of the day in the maximum offset
125
* (larger offsets are earlier on the time-line).
126
* This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}.
127
* This could be used by an application as a "far past" date.
128
*/
129
public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX);
130
/**
131
* The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'.
132
* This is the time just before midnight at the end of the day in the minimum offset
133
* (larger negative offsets are later on the time-line).
134
* This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}.
135
* This could be used by an application as a "far future" date.
136
*/
137
public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN);
138
139
/**
140
* Serialization version.
141
*/
142
@java.io.Serial
143
private static final long serialVersionUID = 7264499704384272492L;
144
145
/**
146
* The local date-time.
147
*/
148
private final LocalTime time;
149
/**
150
* The offset from UTC/Greenwich.
151
*/
152
private final ZoneOffset offset;
153
154
//-----------------------------------------------------------------------
155
/**
156
* Obtains the current time from the system clock in the default time-zone.
157
* <p>
158
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
159
* time-zone to obtain the current time.
160
* The offset will be calculated from the time-zone in the clock.
161
* <p>
162
* Using this method will prevent the ability to use an alternate clock for testing
163
* because the clock is hard-coded.
164
*
165
* @return the current time using the system clock and default time-zone, not null
166
*/
167
public static OffsetTime now() {
168
return now(Clock.systemDefaultZone());
169
}
170
171
/**
172
* Obtains the current time from the system clock in the specified time-zone.
173
* <p>
174
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
175
* Specifying the time-zone avoids dependence on the default time-zone.
176
* The offset will be calculated from the specified time-zone.
177
* <p>
178
* Using this method will prevent the ability to use an alternate clock for testing
179
* because the clock is hard-coded.
180
*
181
* @param zone the zone ID to use, not null
182
* @return the current time using the system clock, not null
183
*/
184
public static OffsetTime now(ZoneId zone) {
185
return now(Clock.system(zone));
186
}
187
188
/**
189
* Obtains the current time from the specified clock.
190
* <p>
191
* This will query the specified clock to obtain the current time.
192
* The offset will be calculated from the time-zone in the clock.
193
* <p>
194
* Using this method allows the use of an alternate clock for testing.
195
* The alternate clock may be introduced using {@link Clock dependency injection}.
196
*
197
* @param clock the clock to use, not null
198
* @return the current time, not null
199
*/
200
public static OffsetTime now(Clock clock) {
201
Objects.requireNonNull(clock, "clock");
202
final Instant now = clock.instant(); // called once
203
return ofInstant(now, clock.getZone().getRules().getOffset(now));
204
}
205
206
//-----------------------------------------------------------------------
207
/**
208
* Obtains an instance of {@code OffsetTime} from a local time and an offset.
209
*
210
* @param time the local time, not null
211
* @param offset the zone offset, not null
212
* @return the offset time, not null
213
*/
214
public static OffsetTime of(LocalTime time, ZoneOffset offset) {
215
return new OffsetTime(time, offset);
216
}
217
218
/**
219
* Obtains an instance of {@code OffsetTime} from an hour, minute, second and nanosecond.
220
* <p>
221
* This creates an offset time with the four specified fields.
222
* <p>
223
* This method exists primarily for writing test cases.
224
* Non test-code will typically use other methods to create an offset time.
225
* {@code LocalTime} has two additional convenience variants of the
226
* equivalent factory method taking fewer arguments.
227
* They are not provided here to reduce the footprint of the API.
228
*
229
* @param hour the hour-of-day to represent, from 0 to 23
230
* @param minute the minute-of-hour to represent, from 0 to 59
231
* @param second the second-of-minute to represent, from 0 to 59
232
* @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999
233
* @param offset the zone offset, not null
234
* @return the offset time, not null
235
* @throws DateTimeException if the value of any field is out of range
236
*/
237
public static OffsetTime of(int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) {
238
return new OffsetTime(LocalTime.of(hour, minute, second, nanoOfSecond), offset);
239
}
240
241
//-----------------------------------------------------------------------
242
/**
243
* Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
244
* <p>
245
* This creates an offset time with the same instant as that specified.
246
* Finding the offset from UTC/Greenwich is simple as there is only one valid
247
* offset for each instant.
248
* <p>
249
* The date component of the instant is dropped during the conversion.
250
* This means that the conversion can never fail due to the instant being
251
* out of the valid range of dates.
252
*
253
* @param instant the instant to create the time from, not null
254
* @param zone the time-zone, which may be an offset, not null
255
* @return the offset time, not null
256
*/
257
public static OffsetTime ofInstant(Instant instant, ZoneId zone) {
258
Objects.requireNonNull(instant, "instant");
259
Objects.requireNonNull(zone, "zone");
260
ZoneRules rules = zone.getRules();
261
ZoneOffset offset = rules.getOffset(instant);
262
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
263
int secsOfDay = Math.floorMod(localSecond, SECONDS_PER_DAY);
264
LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano());
265
return new OffsetTime(time, offset);
266
}
267
268
//-----------------------------------------------------------------------
269
/**
270
* Obtains an instance of {@code OffsetTime} from a temporal object.
271
* <p>
272
* This obtains an offset time based on the specified temporal.
273
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
274
* which this factory converts to an instance of {@code OffsetTime}.
275
* <p>
276
* The conversion extracts and combines the {@code ZoneOffset} and the
277
* {@code LocalTime} from the temporal object.
278
* Implementations are permitted to perform optimizations such as accessing
279
* those fields that are equivalent to the relevant objects.
280
* <p>
281
* This method matches the signature of the functional interface {@link TemporalQuery}
282
* allowing it to be used as a query via method reference, {@code OffsetTime::from}.
283
*
284
* @param temporal the temporal object to convert, not null
285
* @return the offset time, not null
286
* @throws DateTimeException if unable to convert to an {@code OffsetTime}
287
*/
288
public static OffsetTime from(TemporalAccessor temporal) {
289
if (temporal instanceof OffsetTime) {
290
return (OffsetTime) temporal;
291
}
292
try {
293
LocalTime time = LocalTime.from(temporal);
294
ZoneOffset offset = ZoneOffset.from(temporal);
295
return new OffsetTime(time, offset);
296
} catch (DateTimeException ex) {
297
throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " +
298
temporal + " of type " + temporal.getClass().getName(), ex);
299
}
300
}
301
302
//-----------------------------------------------------------------------
303
/**
304
* Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}.
305
* <p>
306
* The string must represent a valid time and is parsed using
307
* {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME}.
308
*
309
* @param text the text to parse such as "10:15:30+01:00", not null
310
* @return the parsed local time, not null
311
* @throws DateTimeParseException if the text cannot be parsed
312
*/
313
public static OffsetTime parse(CharSequence text) {
314
return parse(text, DateTimeFormatter.ISO_OFFSET_TIME);
315
}
316
317
/**
318
* Obtains an instance of {@code OffsetTime} from a text string using a specific formatter.
319
* <p>
320
* The text is parsed using the formatter, returning a time.
321
*
322
* @param text the text to parse, not null
323
* @param formatter the formatter to use, not null
324
* @return the parsed offset time, not null
325
* @throws DateTimeParseException if the text cannot be parsed
326
*/
327
public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) {
328
Objects.requireNonNull(formatter, "formatter");
329
return formatter.parse(text, OffsetTime::from);
330
}
331
332
//-----------------------------------------------------------------------
333
/**
334
* Constructor.
335
*
336
* @param time the local time, not null
337
* @param offset the zone offset, not null
338
*/
339
private OffsetTime(LocalTime time, ZoneOffset offset) {
340
this.time = Objects.requireNonNull(time, "time");
341
this.offset = Objects.requireNonNull(offset, "offset");
342
}
343
344
/**
345
* Returns a new time based on this one, returning {@code this} where possible.
346
*
347
* @param time the time to create with, not null
348
* @param offset the zone offset to create with, not null
349
*/
350
private OffsetTime with(LocalTime time, ZoneOffset offset) {
351
if (this.time == time && this.offset.equals(offset)) {
352
return this;
353
}
354
return new OffsetTime(time, offset);
355
}
356
357
//-----------------------------------------------------------------------
358
/**
359
* Checks if the specified field is supported.
360
* <p>
361
* This checks if this time can be queried for the specified field.
362
* If false, then calling the {@link #range(TemporalField) range},
363
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
364
* methods will throw an exception.
365
* <p>
366
* If the field is a {@link ChronoField} then the query is implemented here.
367
* The supported fields are:
368
* <ul>
369
* <li>{@code NANO_OF_SECOND}
370
* <li>{@code NANO_OF_DAY}
371
* <li>{@code MICRO_OF_SECOND}
372
* <li>{@code MICRO_OF_DAY}
373
* <li>{@code MILLI_OF_SECOND}
374
* <li>{@code MILLI_OF_DAY}
375
* <li>{@code SECOND_OF_MINUTE}
376
* <li>{@code SECOND_OF_DAY}
377
* <li>{@code MINUTE_OF_HOUR}
378
* <li>{@code MINUTE_OF_DAY}
379
* <li>{@code HOUR_OF_AMPM}
380
* <li>{@code CLOCK_HOUR_OF_AMPM}
381
* <li>{@code HOUR_OF_DAY}
382
* <li>{@code CLOCK_HOUR_OF_DAY}
383
* <li>{@code AMPM_OF_DAY}
384
* <li>{@code OFFSET_SECONDS}
385
* </ul>
386
* All other {@code ChronoField} instances will return false.
387
* <p>
388
* If the field is not a {@code ChronoField}, then the result of this method
389
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
390
* passing {@code this} as the argument.
391
* Whether the field is supported is determined by the field.
392
*
393
* @param field the field to check, null returns false
394
* @return true if the field is supported on this time, false if not
395
*/
396
@Override
397
public boolean isSupported(TemporalField field) {
398
if (field instanceof ChronoField) {
399
return field.isTimeBased() || field == OFFSET_SECONDS;
400
}
401
return field != null && field.isSupportedBy(this);
402
}
403
404
/**
405
* Checks if the specified unit is supported.
406
* <p>
407
* This checks if the specified unit can be added to, or subtracted from, this offset-time.
408
* If false, then calling the {@link #plus(long, TemporalUnit)} and
409
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
410
* <p>
411
* If the unit is a {@link ChronoUnit} then the query is implemented here.
412
* The supported units are:
413
* <ul>
414
* <li>{@code NANOS}
415
* <li>{@code MICROS}
416
* <li>{@code MILLIS}
417
* <li>{@code SECONDS}
418
* <li>{@code MINUTES}
419
* <li>{@code HOURS}
420
* <li>{@code HALF_DAYS}
421
* </ul>
422
* All other {@code ChronoUnit} instances will return false.
423
* <p>
424
* If the unit is not a {@code ChronoUnit}, then the result of this method
425
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
426
* passing {@code this} as the argument.
427
* Whether the unit is supported is determined by the unit.
428
*
429
* @param unit the unit to check, null returns false
430
* @return true if the unit can be added/subtracted, false if not
431
*/
432
@Override // override for Javadoc
433
public boolean isSupported(TemporalUnit unit) {
434
if (unit instanceof ChronoUnit) {
435
return unit.isTimeBased();
436
}
437
return unit != null && unit.isSupportedBy(this);
438
}
439
440
//-----------------------------------------------------------------------
441
/**
442
* Gets the range of valid values for the specified field.
443
* <p>
444
* The range object expresses the minimum and maximum valid values for a field.
445
* This time is used to enhance the accuracy of the returned range.
446
* If it is not possible to return the range, because the field is not supported
447
* or for some other reason, an exception is thrown.
448
* <p>
449
* If the field is a {@link ChronoField} then the query is implemented here.
450
* The {@link #isSupported(TemporalField) supported fields} will return
451
* appropriate range instances.
452
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
453
* <p>
454
* If the field is not a {@code ChronoField}, then the result of this method
455
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
456
* passing {@code this} as the argument.
457
* Whether the range can be obtained is determined by the field.
458
*
459
* @param field the field to query the range for, not null
460
* @return the range of valid values for the field, not null
461
* @throws DateTimeException if the range for the field cannot be obtained
462
* @throws UnsupportedTemporalTypeException if the field is not supported
463
*/
464
@Override
465
public ValueRange range(TemporalField field) {
466
if (field instanceof ChronoField) {
467
if (field == OFFSET_SECONDS) {
468
return field.range();
469
}
470
return time.range(field);
471
}
472
return field.rangeRefinedBy(this);
473
}
474
475
/**
476
* Gets the value of the specified field from this time as an {@code int}.
477
* <p>
478
* This queries this time for the value of the specified field.
479
* The returned value will always be within the valid range of values for the field.
480
* If it is not possible to return the value, because the field is not supported
481
* or for some other reason, an exception is thrown.
482
* <p>
483
* If the field is a {@link ChronoField} then the query is implemented here.
484
* The {@link #isSupported(TemporalField) supported fields} will return valid
485
* values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
486
* which are too large to fit in an {@code int} and throw an {@code UnsupportedTemporalTypeException}.
487
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
488
* <p>
489
* If the field is not a {@code ChronoField}, then the result of this method
490
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
491
* passing {@code this} as the argument. Whether the value can be obtained,
492
* and what the value represents, is determined by the field.
493
*
494
* @param field the field to get, not null
495
* @return the value for the field
496
* @throws DateTimeException if a value for the field cannot be obtained or
497
* the value is outside the range of valid values for the field
498
* @throws UnsupportedTemporalTypeException if the field is not supported or
499
* the range of values exceeds an {@code int}
500
* @throws ArithmeticException if numeric overflow occurs
501
*/
502
@Override // override for Javadoc
503
public int get(TemporalField field) {
504
return Temporal.super.get(field);
505
}
506
507
/**
508
* Gets the value of the specified field from this time as a {@code long}.
509
* <p>
510
* This queries this time for the value of the specified field.
511
* If it is not possible to return the value, because the field is not supported
512
* or for some other reason, an exception is thrown.
513
* <p>
514
* If the field is a {@link ChronoField} then the query is implemented here.
515
* The {@link #isSupported(TemporalField) supported fields} will return valid
516
* values based on this time.
517
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
518
* <p>
519
* If the field is not a {@code ChronoField}, then the result of this method
520
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
521
* passing {@code this} as the argument. Whether the value can be obtained,
522
* and what the value represents, is determined by the field.
523
*
524
* @param field the field to get, not null
525
* @return the value for the field
526
* @throws DateTimeException if a value for the field cannot be obtained
527
* @throws UnsupportedTemporalTypeException if the field is not supported
528
* @throws ArithmeticException if numeric overflow occurs
529
*/
530
@Override
531
public long getLong(TemporalField field) {
532
if (field instanceof ChronoField) {
533
if (field == OFFSET_SECONDS) {
534
return offset.getTotalSeconds();
535
}
536
return time.getLong(field);
537
}
538
return field.getFrom(this);
539
}
540
541
//-----------------------------------------------------------------------
542
/**
543
* Gets the zone offset, such as '+01:00'.
544
* <p>
545
* This is the offset of the local time from UTC/Greenwich.
546
*
547
* @return the zone offset, not null
548
*/
549
public ZoneOffset getOffset() {
550
return offset;
551
}
552
553
/**
554
* Returns a copy of this {@code OffsetTime} with the specified offset ensuring
555
* that the result has the same local time.
556
* <p>
557
* This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}.
558
* No calculation is needed or performed.
559
* For example, if this time represents {@code 10:30+02:00} and the offset specified is
560
* {@code +03:00}, then this method will return {@code 10:30+03:00}.
561
* <p>
562
* To take into account the difference between the offsets, and adjust the time fields,
563
* use {@link #withOffsetSameInstant}.
564
* <p>
565
* This instance is immutable and unaffected by this method call.
566
*
567
* @param offset the zone offset to change to, not null
568
* @return an {@code OffsetTime} based on this time with the requested offset, not null
569
*/
570
public OffsetTime withOffsetSameLocal(ZoneOffset offset) {
571
return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset);
572
}
573
574
/**
575
* Returns a copy of this {@code OffsetTime} with the specified offset ensuring
576
* that the result is at the same instant on an implied day.
577
* <p>
578
* This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime}
579
* adjusted by the difference between the two offsets.
580
* This will result in the old and new objects representing the same instant on an implied day.
581
* This is useful for finding the local time in a different offset.
582
* For example, if this time represents {@code 10:30+02:00} and the offset specified is
583
* {@code +03:00}, then this method will return {@code 11:30+03:00}.
584
* <p>
585
* To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
586
* <p>
587
* This instance is immutable and unaffected by this method call.
588
*
589
* @param offset the zone offset to change to, not null
590
* @return an {@code OffsetTime} based on this time with the requested offset, not null
591
*/
592
public OffsetTime withOffsetSameInstant(ZoneOffset offset) {
593
if (offset.equals(this.offset)) {
594
return this;
595
}
596
int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
597
LocalTime adjusted = time.plusSeconds(difference);
598
return new OffsetTime(adjusted, offset);
599
}
600
601
//-----------------------------------------------------------------------
602
/**
603
* Gets the {@code LocalTime} part of this date-time.
604
* <p>
605
* This returns a {@code LocalTime} with the same hour, minute, second and
606
* nanosecond as this date-time.
607
*
608
* @return the time part of this date-time, not null
609
*/
610
public LocalTime toLocalTime() {
611
return time;
612
}
613
614
//-----------------------------------------------------------------------
615
/**
616
* Gets the hour-of-day field.
617
*
618
* @return the hour-of-day, from 0 to 23
619
*/
620
public int getHour() {
621
return time.getHour();
622
}
623
624
/**
625
* Gets the minute-of-hour field.
626
*
627
* @return the minute-of-hour, from 0 to 59
628
*/
629
public int getMinute() {
630
return time.getMinute();
631
}
632
633
/**
634
* Gets the second-of-minute field.
635
*
636
* @return the second-of-minute, from 0 to 59
637
*/
638
public int getSecond() {
639
return time.getSecond();
640
}
641
642
/**
643
* Gets the nano-of-second field.
644
*
645
* @return the nano-of-second, from 0 to 999,999,999
646
*/
647
public int getNano() {
648
return time.getNano();
649
}
650
651
//-----------------------------------------------------------------------
652
/**
653
* Returns an adjusted copy of this time.
654
* <p>
655
* This returns an {@code OffsetTime}, based on this one, with the time adjusted.
656
* The adjustment takes place using the specified adjuster strategy object.
657
* Read the documentation of the adjuster to understand what adjustment will be made.
658
* <p>
659
* A simple adjuster might simply set the one of the fields, such as the hour field.
660
* A more complex adjuster might set the time to the last hour of the day.
661
* <p>
662
* The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster},
663
* thus this method can be used to change the time or offset:
664
* <pre>
665
* result = offsetTime.with(time);
666
* result = offsetTime.with(offset);
667
* </pre>
668
* <p>
669
* The result of this method is obtained by invoking the
670
* {@link TemporalAdjuster#adjustInto(Temporal)} method on the
671
* specified adjuster passing {@code this} as the argument.
672
* <p>
673
* This instance is immutable and unaffected by this method call.
674
*
675
* @param adjuster the adjuster to use, not null
676
* @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null
677
* @throws DateTimeException if the adjustment cannot be made
678
* @throws ArithmeticException if numeric overflow occurs
679
*/
680
@Override
681
public OffsetTime with(TemporalAdjuster adjuster) {
682
// optimizations
683
if (adjuster instanceof LocalTime) {
684
return with((LocalTime) adjuster, offset);
685
} else if (adjuster instanceof ZoneOffset) {
686
return with(time, (ZoneOffset) adjuster);
687
} else if (adjuster instanceof OffsetTime) {
688
return (OffsetTime) adjuster;
689
}
690
return (OffsetTime) adjuster.adjustInto(this);
691
}
692
693
/**
694
* Returns a copy of this time with the specified field set to a new value.
695
* <p>
696
* This returns an {@code OffsetTime}, based on this one, with the value
697
* for the specified field changed.
698
* This can be used to change any supported field, such as the hour, minute or second.
699
* If it is not possible to set the value, because the field is not supported or for
700
* some other reason, an exception is thrown.
701
* <p>
702
* If the field is a {@link ChronoField} then the adjustment is implemented here.
703
* <p>
704
* The {@code OFFSET_SECONDS} field will return a time with the specified offset.
705
* The local time is unaltered. If the new offset value is outside the valid range
706
* then a {@code DateTimeException} will be thrown.
707
* <p>
708
* The other {@link #isSupported(TemporalField) supported fields} will behave as per
709
* the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}.
710
* In this case, the offset is not part of the calculation and will be unchanged.
711
* <p>
712
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
713
* <p>
714
* If the field is not a {@code ChronoField}, then the result of this method
715
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
716
* passing {@code this} as the argument. In this case, the field determines
717
* whether and how to adjust the instant.
718
* <p>
719
* This instance is immutable and unaffected by this method call.
720
*
721
* @param field the field to set in the result, not null
722
* @param newValue the new value of the field in the result
723
* @return an {@code OffsetTime} based on {@code this} with the specified field set, not null
724
* @throws DateTimeException if the field cannot be set
725
* @throws UnsupportedTemporalTypeException if the field is not supported
726
* @throws ArithmeticException if numeric overflow occurs
727
*/
728
@Override
729
public OffsetTime with(TemporalField field, long newValue) {
730
if (field instanceof ChronoField) {
731
if (field == OFFSET_SECONDS) {
732
ChronoField f = (ChronoField) field;
733
return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
734
}
735
return with(time.with(field, newValue), offset);
736
}
737
return field.adjustInto(this, newValue);
738
}
739
740
//-----------------------------------------------------------------------
741
/**
742
* Returns a copy of this {@code OffsetTime} with the hour-of-day altered.
743
* <p>
744
* The offset does not affect the calculation and will be the same in the result.
745
* <p>
746
* This instance is immutable and unaffected by this method call.
747
*
748
* @param hour the hour-of-day to set in the result, from 0 to 23
749
* @return an {@code OffsetTime} based on this time with the requested hour, not null
750
* @throws DateTimeException if the hour value is invalid
751
*/
752
public OffsetTime withHour(int hour) {
753
return with(time.withHour(hour), offset);
754
}
755
756
/**
757
* Returns a copy of this {@code OffsetTime} with the minute-of-hour altered.
758
* <p>
759
* The offset does not affect the calculation and will be the same in the result.
760
* <p>
761
* This instance is immutable and unaffected by this method call.
762
*
763
* @param minute the minute-of-hour to set in the result, from 0 to 59
764
* @return an {@code OffsetTime} based on this time with the requested minute, not null
765
* @throws DateTimeException if the minute value is invalid
766
*/
767
public OffsetTime withMinute(int minute) {
768
return with(time.withMinute(minute), offset);
769
}
770
771
/**
772
* Returns a copy of this {@code OffsetTime} with the second-of-minute altered.
773
* <p>
774
* The offset does not affect the calculation and will be the same in the result.
775
* <p>
776
* This instance is immutable and unaffected by this method call.
777
*
778
* @param second the second-of-minute to set in the result, from 0 to 59
779
* @return an {@code OffsetTime} based on this time with the requested second, not null
780
* @throws DateTimeException if the second value is invalid
781
*/
782
public OffsetTime withSecond(int second) {
783
return with(time.withSecond(second), offset);
784
}
785
786
/**
787
* Returns a copy of this {@code OffsetTime} with the nano-of-second altered.
788
* <p>
789
* The offset does not affect the calculation and will be the same in the result.
790
* <p>
791
* This instance is immutable and unaffected by this method call.
792
*
793
* @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999
794
* @return an {@code OffsetTime} based on this time with the requested nanosecond, not null
795
* @throws DateTimeException if the nanos value is invalid
796
*/
797
public OffsetTime withNano(int nanoOfSecond) {
798
return with(time.withNano(nanoOfSecond), offset);
799
}
800
801
//-----------------------------------------------------------------------
802
/**
803
* Returns a copy of this {@code OffsetTime} with the time truncated.
804
* <p>
805
* Truncation returns a copy of the original time with fields
806
* smaller than the specified unit set to zero.
807
* For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
808
* will set the second-of-minute and nano-of-second field to zero.
809
* <p>
810
* The unit must have a {@linkplain TemporalUnit#getDuration() duration}
811
* that divides into the length of a standard day without remainder.
812
* This includes all supplied time units on {@link ChronoUnit} and
813
* {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
814
* <p>
815
* The offset does not affect the calculation and will be the same in the result.
816
* <p>
817
* This instance is immutable and unaffected by this method call.
818
*
819
* @param unit the unit to truncate to, not null
820
* @return an {@code OffsetTime} based on this time with the time truncated, not null
821
* @throws DateTimeException if unable to truncate
822
* @throws UnsupportedTemporalTypeException if the unit is not supported
823
*/
824
public OffsetTime truncatedTo(TemporalUnit unit) {
825
return with(time.truncatedTo(unit), offset);
826
}
827
828
//-----------------------------------------------------------------------
829
/**
830
* Returns a copy of this time with the specified amount added.
831
* <p>
832
* This returns an {@code OffsetTime}, based on this one, with the specified amount added.
833
* The amount is typically {@link Duration} but may be any other type implementing
834
* the {@link TemporalAmount} interface.
835
* <p>
836
* The calculation is delegated to the amount object by calling
837
* {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
838
* to implement the addition in any way it wishes, however it typically
839
* calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
840
* of the amount implementation to determine if it can be successfully added.
841
* <p>
842
* This instance is immutable and unaffected by this method call.
843
*
844
* @param amountToAdd the amount to add, not null
845
* @return an {@code OffsetTime} based on this time with the addition made, not null
846
* @throws DateTimeException if the addition cannot be made
847
* @throws ArithmeticException if numeric overflow occurs
848
*/
849
@Override
850
public OffsetTime plus(TemporalAmount amountToAdd) {
851
return (OffsetTime) amountToAdd.addTo(this);
852
}
853
854
/**
855
* Returns a copy of this time with the specified amount added.
856
* <p>
857
* This returns an {@code OffsetTime}, based on this one, with the amount
858
* in terms of the unit added. If it is not possible to add the amount, because the
859
* unit is not supported or for some other reason, an exception is thrown.
860
* <p>
861
* If the field is a {@link ChronoUnit} then the addition is implemented by
862
* {@link LocalTime#plus(long, TemporalUnit)}.
863
* The offset is not part of the calculation and will be unchanged in the result.
864
* <p>
865
* If the field is not a {@code ChronoUnit}, then the result of this method
866
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
867
* passing {@code this} as the argument. In this case, the unit determines
868
* whether and how to perform the addition.
869
* <p>
870
* This instance is immutable and unaffected by this method call.
871
*
872
* @param amountToAdd the amount of the unit to add to the result, may be negative
873
* @param unit the unit of the amount to add, not null
874
* @return an {@code OffsetTime} based on this time with the specified amount added, not null
875
* @throws DateTimeException if the addition cannot be made
876
* @throws UnsupportedTemporalTypeException if the unit is not supported
877
* @throws ArithmeticException if numeric overflow occurs
878
*/
879
@Override
880
public OffsetTime plus(long amountToAdd, TemporalUnit unit) {
881
if (unit instanceof ChronoUnit) {
882
return with(time.plus(amountToAdd, unit), offset);
883
}
884
return unit.addTo(this, amountToAdd);
885
}
886
887
//-----------------------------------------------------------------------
888
/**
889
* Returns a copy of this {@code OffsetTime} with the specified number of hours added.
890
* <p>
891
* This adds the specified number of hours to this time, returning a new time.
892
* The calculation wraps around midnight.
893
* <p>
894
* This instance is immutable and unaffected by this method call.
895
*
896
* @param hours the hours to add, may be negative
897
* @return an {@code OffsetTime} based on this time with the hours added, not null
898
*/
899
public OffsetTime plusHours(long hours) {
900
return with(time.plusHours(hours), offset);
901
}
902
903
/**
904
* Returns a copy of this {@code OffsetTime} with the specified number of minutes added.
905
* <p>
906
* This adds the specified number of minutes to this time, returning a new time.
907
* The calculation wraps around midnight.
908
* <p>
909
* This instance is immutable and unaffected by this method call.
910
*
911
* @param minutes the minutes to add, may be negative
912
* @return an {@code OffsetTime} based on this time with the minutes added, not null
913
*/
914
public OffsetTime plusMinutes(long minutes) {
915
return with(time.plusMinutes(minutes), offset);
916
}
917
918
/**
919
* Returns a copy of this {@code OffsetTime} with the specified number of seconds added.
920
* <p>
921
* This adds the specified number of seconds to this time, returning a new time.
922
* The calculation wraps around midnight.
923
* <p>
924
* This instance is immutable and unaffected by this method call.
925
*
926
* @param seconds the seconds to add, may be negative
927
* @return an {@code OffsetTime} based on this time with the seconds added, not null
928
*/
929
public OffsetTime plusSeconds(long seconds) {
930
return with(time.plusSeconds(seconds), offset);
931
}
932
933
/**
934
* Returns a copy of this {@code OffsetTime} with the specified number of nanoseconds added.
935
* <p>
936
* This adds the specified number of nanoseconds to this time, returning a new time.
937
* The calculation wraps around midnight.
938
* <p>
939
* This instance is immutable and unaffected by this method call.
940
*
941
* @param nanos the nanos to add, may be negative
942
* @return an {@code OffsetTime} based on this time with the nanoseconds added, not null
943
*/
944
public OffsetTime plusNanos(long nanos) {
945
return with(time.plusNanos(nanos), offset);
946
}
947
948
//-----------------------------------------------------------------------
949
/**
950
* Returns a copy of this time with the specified amount subtracted.
951
* <p>
952
* This returns an {@code OffsetTime}, based on this one, with the specified amount subtracted.
953
* The amount is typically {@link Duration} but may be any other type implementing
954
* the {@link TemporalAmount} interface.
955
* <p>
956
* The calculation is delegated to the amount object by calling
957
* {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
958
* to implement the subtraction in any way it wishes, however it typically
959
* calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
960
* of the amount implementation to determine if it can be successfully subtracted.
961
* <p>
962
* This instance is immutable and unaffected by this method call.
963
*
964
* @param amountToSubtract the amount to subtract, not null
965
* @return an {@code OffsetTime} based on this time with the subtraction made, not null
966
* @throws DateTimeException if the subtraction cannot be made
967
* @throws ArithmeticException if numeric overflow occurs
968
*/
969
@Override
970
public OffsetTime minus(TemporalAmount amountToSubtract) {
971
return (OffsetTime) amountToSubtract.subtractFrom(this);
972
}
973
974
/**
975
* Returns a copy of this time with the specified amount subtracted.
976
* <p>
977
* This returns an {@code OffsetTime}, based on this one, with the amount
978
* in terms of the unit subtracted. If it is not possible to subtract the amount,
979
* because the unit is not supported or for some other reason, an exception is thrown.
980
* <p>
981
* This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
982
* See that method for a full description of how addition, and thus subtraction, works.
983
* <p>
984
* This instance is immutable and unaffected by this method call.
985
*
986
* @param amountToSubtract the amount of the unit to subtract from the result, may be negative
987
* @param unit the unit of the amount to subtract, not null
988
* @return an {@code OffsetTime} based on this time with the specified amount subtracted, not null
989
* @throws DateTimeException if the subtraction cannot be made
990
* @throws UnsupportedTemporalTypeException if the unit is not supported
991
* @throws ArithmeticException if numeric overflow occurs
992
*/
993
@Override
994
public OffsetTime minus(long amountToSubtract, TemporalUnit unit) {
995
return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
996
}
997
998
//-----------------------------------------------------------------------
999
/**
1000
* Returns a copy of this {@code OffsetTime} with the specified number of hours subtracted.
1001
* <p>
1002
* This subtracts the specified number of hours from this time, returning a new time.
1003
* The calculation wraps around midnight.
1004
* <p>
1005
* This instance is immutable and unaffected by this method call.
1006
*
1007
* @param hours the hours to subtract, may be negative
1008
* @return an {@code OffsetTime} based on this time with the hours subtracted, not null
1009
*/
1010
public OffsetTime minusHours(long hours) {
1011
return with(time.minusHours(hours), offset);
1012
}
1013
1014
/**
1015
* Returns a copy of this {@code OffsetTime} with the specified number of minutes subtracted.
1016
* <p>
1017
* This subtracts the specified number of minutes from this time, returning a new time.
1018
* The calculation wraps around midnight.
1019
* <p>
1020
* This instance is immutable and unaffected by this method call.
1021
*
1022
* @param minutes the minutes to subtract, may be negative
1023
* @return an {@code OffsetTime} based on this time with the minutes subtracted, not null
1024
*/
1025
public OffsetTime minusMinutes(long minutes) {
1026
return with(time.minusMinutes(minutes), offset);
1027
}
1028
1029
/**
1030
* Returns a copy of this {@code OffsetTime} with the specified number of seconds subtracted.
1031
* <p>
1032
* This subtracts the specified number of seconds from this time, returning a new time.
1033
* The calculation wraps around midnight.
1034
* <p>
1035
* This instance is immutable and unaffected by this method call.
1036
*
1037
* @param seconds the seconds to subtract, may be negative
1038
* @return an {@code OffsetTime} based on this time with the seconds subtracted, not null
1039
*/
1040
public OffsetTime minusSeconds(long seconds) {
1041
return with(time.minusSeconds(seconds), offset);
1042
}
1043
1044
/**
1045
* Returns a copy of this {@code OffsetTime} with the specified number of nanoseconds subtracted.
1046
* <p>
1047
* This subtracts the specified number of nanoseconds from this time, returning a new time.
1048
* The calculation wraps around midnight.
1049
* <p>
1050
* This instance is immutable and unaffected by this method call.
1051
*
1052
* @param nanos the nanos to subtract, may be negative
1053
* @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null
1054
*/
1055
public OffsetTime minusNanos(long nanos) {
1056
return with(time.minusNanos(nanos), offset);
1057
}
1058
1059
//-----------------------------------------------------------------------
1060
/**
1061
* Queries this time using the specified query.
1062
* <p>
1063
* This queries this time using the specified query strategy object.
1064
* The {@code TemporalQuery} object defines the logic to be used to
1065
* obtain the result. Read the documentation of the query to understand
1066
* what the result of this method will be.
1067
* <p>
1068
* The result of this method is obtained by invoking the
1069
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
1070
* specified query passing {@code this} as the argument.
1071
*
1072
* @param <R> the type of the result
1073
* @param query the query to invoke, not null
1074
* @return the query result, null may be returned (defined by the query)
1075
* @throws DateTimeException if unable to query (defined by the query)
1076
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
1077
*/
1078
@SuppressWarnings("unchecked")
1079
@Override
1080
public <R> R query(TemporalQuery<R> query) {
1081
if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
1082
return (R) offset;
1083
} else if (query == TemporalQueries.zoneId() | query == TemporalQueries.chronology() || query == TemporalQueries.localDate()) {
1084
return null;
1085
} else if (query == TemporalQueries.localTime()) {
1086
return (R) time;
1087
} else if (query == TemporalQueries.precision()) {
1088
return (R) NANOS;
1089
}
1090
// inline TemporalAccessor.super.query(query) as an optimization
1091
// non-JDK classes are not permitted to make this optimization
1092
return query.queryFrom(this);
1093
}
1094
1095
/**
1096
* Adjusts the specified temporal object to have the same offset and time
1097
* as this object.
1098
* <p>
1099
* This returns a temporal object of the same observable type as the input
1100
* with the offset and time changed to be the same as this.
1101
* <p>
1102
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
1103
* twice, passing {@link ChronoField#NANO_OF_DAY} and
1104
* {@link ChronoField#OFFSET_SECONDS} as the fields.
1105
* <p>
1106
* In most cases, it is clearer to reverse the calling pattern by using
1107
* {@link Temporal#with(TemporalAdjuster)}:
1108
* <pre>
1109
* // these two lines are equivalent, but the second approach is recommended
1110
* temporal = thisOffsetTime.adjustInto(temporal);
1111
* temporal = temporal.with(thisOffsetTime);
1112
* </pre>
1113
* <p>
1114
* This instance is immutable and unaffected by this method call.
1115
*
1116
* @param temporal the target object to be adjusted, not null
1117
* @return the adjusted object, not null
1118
* @throws DateTimeException if unable to make the adjustment
1119
* @throws ArithmeticException if numeric overflow occurs
1120
*/
1121
@Override
1122
public Temporal adjustInto(Temporal temporal) {
1123
return temporal
1124
.with(NANO_OF_DAY, time.toNanoOfDay())
1125
.with(OFFSET_SECONDS, offset.getTotalSeconds());
1126
}
1127
1128
/**
1129
* Calculates the amount of time until another time in terms of the specified unit.
1130
* <p>
1131
* This calculates the amount of time between two {@code OffsetTime}
1132
* objects in terms of a single {@code TemporalUnit}.
1133
* The start and end points are {@code this} and the specified time.
1134
* The result will be negative if the end is before the start.
1135
* For example, the amount in hours between two times can be calculated
1136
* using {@code startTime.until(endTime, HOURS)}.
1137
* <p>
1138
* The {@code Temporal} passed to this method is converted to a
1139
* {@code OffsetTime} using {@link #from(TemporalAccessor)}.
1140
* If the offset differs between the two times, then the specified
1141
* end time is normalized to have the same offset as this time.
1142
* <p>
1143
* The calculation returns a whole number, representing the number of
1144
* complete units between the two times.
1145
* For example, the amount in hours between 11:30Z and 13:29Z will only
1146
* be one hour as it is one minute short of two hours.
1147
* <p>
1148
* There are two equivalent ways of using this method.
1149
* The first is to invoke this method.
1150
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
1151
* <pre>
1152
* // these two lines are equivalent
1153
* amount = start.until(end, MINUTES);
1154
* amount = MINUTES.between(start, end);
1155
* </pre>
1156
* The choice should be made based on which makes the code more readable.
1157
* <p>
1158
* The calculation is implemented in this method for {@link ChronoUnit}.
1159
* The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
1160
* {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
1161
* Other {@code ChronoUnit} values will throw an exception.
1162
* <p>
1163
* If the unit is not a {@code ChronoUnit}, then the result of this method
1164
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
1165
* passing {@code this} as the first argument and the converted input temporal
1166
* as the second argument.
1167
* <p>
1168
* This instance is immutable and unaffected by this method call.
1169
*
1170
* @param endExclusive the end time, exclusive, which is converted to an {@code OffsetTime}, not null
1171
* @param unit the unit to measure the amount in, not null
1172
* @return the amount of time between this time and the end time
1173
* @throws DateTimeException if the amount cannot be calculated, or the end
1174
* temporal cannot be converted to an {@code OffsetTime}
1175
* @throws UnsupportedTemporalTypeException if the unit is not supported
1176
* @throws ArithmeticException if numeric overflow occurs
1177
*/
1178
@Override
1179
public long until(Temporal endExclusive, TemporalUnit unit) {
1180
OffsetTime end = OffsetTime.from(endExclusive);
1181
if (unit instanceof ChronoUnit chronoUnit) {
1182
long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow
1183
switch (chronoUnit) {
1184
case NANOS: return nanosUntil;
1185
case MICROS: return nanosUntil / 1000;
1186
case MILLIS: return nanosUntil / 1000_000;
1187
case SECONDS: return nanosUntil / NANOS_PER_SECOND;
1188
case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
1189
case HOURS: return nanosUntil / NANOS_PER_HOUR;
1190
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
1191
}
1192
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
1193
}
1194
return unit.between(this, end);
1195
}
1196
1197
/**
1198
* Formats this time using the specified formatter.
1199
* <p>
1200
* This time will be passed to the formatter to produce a string.
1201
*
1202
* @param formatter the formatter to use, not null
1203
* @return the formatted time string, not null
1204
* @throws DateTimeException if an error occurs during printing
1205
*/
1206
public String format(DateTimeFormatter formatter) {
1207
Objects.requireNonNull(formatter, "formatter");
1208
return formatter.format(this);
1209
}
1210
1211
//-----------------------------------------------------------------------
1212
/**
1213
* Combines this time with a date to create an {@code OffsetDateTime}.
1214
* <p>
1215
* This returns an {@code OffsetDateTime} formed from this time and the specified date.
1216
* All possible combinations of date and time are valid.
1217
*
1218
* @param date the date to combine with, not null
1219
* @return the offset date-time formed from this time and the specified date, not null
1220
*/
1221
public OffsetDateTime atDate(LocalDate date) {
1222
return OffsetDateTime.of(date, time, offset);
1223
}
1224
1225
//-----------------------------------------------------------------------
1226
/**
1227
* Converts this time to epoch nanos based on 1970-01-01Z.
1228
*
1229
* @return the epoch nanos value
1230
*/
1231
private long toEpochNano() {
1232
long nod = time.toNanoOfDay();
1233
long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND;
1234
return nod - offsetNanos;
1235
}
1236
1237
/**
1238
* Converts this {@code OffsetTime} to the number of seconds since the epoch
1239
* of 1970-01-01T00:00:00Z.
1240
* <p>
1241
* This combines this offset time with the specified date to calculate the
1242
* epoch-second value, which is the number of elapsed seconds from
1243
* 1970-01-01T00:00:00Z.
1244
* Instants on the time-line after the epoch are positive, earlier
1245
* are negative.
1246
*
1247
* @param date the localdate, not null
1248
* @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
1249
* @since 9
1250
*/
1251
public long toEpochSecond(LocalDate date) {
1252
Objects.requireNonNull(date, "date");
1253
long epochDay = date.toEpochDay();
1254
long secs = epochDay * 86400 + time.toSecondOfDay();
1255
secs -= offset.getTotalSeconds();
1256
return secs;
1257
}
1258
1259
//-----------------------------------------------------------------------
1260
/**
1261
* Compares this {@code OffsetTime} to another time.
1262
* <p>
1263
* The comparison is based first on the UTC equivalent instant, then on the local time.
1264
* It is "consistent with equals", as defined by {@link Comparable}.
1265
* <p>
1266
* For example, the following is the comparator order:
1267
* <ol>
1268
* <li>{@code 10:30+01:00}</li>
1269
* <li>{@code 11:00+01:00}</li>
1270
* <li>{@code 12:00+02:00}</li>
1271
* <li>{@code 11:30+01:00}</li>
1272
* <li>{@code 12:00+01:00}</li>
1273
* <li>{@code 12:30+01:00}</li>
1274
* </ol>
1275
* Values #2 and #3 represent the same instant on the time-line.
1276
* When two values represent the same instant, the local time is compared
1277
* to distinguish them. This step is needed to make the ordering
1278
* consistent with {@code equals()}.
1279
* <p>
1280
* To compare the underlying local time of two {@code TemporalAccessor} instances,
1281
* use {@link ChronoField#NANO_OF_DAY} as a comparator.
1282
*
1283
* @param other the other time to compare to, not null
1284
* @return the comparator value, negative if less, positive if greater
1285
*/
1286
@Override
1287
public int compareTo(OffsetTime other) {
1288
if (offset.equals(other.offset)) {
1289
return time.compareTo(other.time);
1290
}
1291
int compare = Long.compare(toEpochNano(), other.toEpochNano());
1292
if (compare == 0) {
1293
compare = time.compareTo(other.time);
1294
}
1295
return compare;
1296
}
1297
1298
//-----------------------------------------------------------------------
1299
/**
1300
* Checks if the instant of this {@code OffsetTime} is after that of the
1301
* specified time applying both times to a common date.
1302
* <p>
1303
* This method differs from the comparison in {@link #compareTo} in that it
1304
* only compares the instant of the time. This is equivalent to converting both
1305
* times to an instant using the same date and comparing the instants.
1306
*
1307
* @param other the other time to compare to, not null
1308
* @return true if this is after the instant of the specified time
1309
*/
1310
public boolean isAfter(OffsetTime other) {
1311
return toEpochNano() > other.toEpochNano();
1312
}
1313
1314
/**
1315
* Checks if the instant of this {@code OffsetTime} is before that of the
1316
* specified time applying both times to a common date.
1317
* <p>
1318
* This method differs from the comparison in {@link #compareTo} in that it
1319
* only compares the instant of the time. This is equivalent to converting both
1320
* times to an instant using the same date and comparing the instants.
1321
*
1322
* @param other the other time to compare to, not null
1323
* @return true if this is before the instant of the specified time
1324
*/
1325
public boolean isBefore(OffsetTime other) {
1326
return toEpochNano() < other.toEpochNano();
1327
}
1328
1329
/**
1330
* Checks if the instant of this {@code OffsetTime} is equal to that of the
1331
* specified time applying both times to a common date.
1332
* <p>
1333
* This method differs from the comparison in {@link #compareTo} and {@link #equals}
1334
* in that it only compares the instant of the time. This is equivalent to converting both
1335
* times to an instant using the same date and comparing the instants.
1336
*
1337
* @param other the other time to compare to, not null
1338
* @return true if this is equal to the instant of the specified time
1339
*/
1340
public boolean isEqual(OffsetTime other) {
1341
return toEpochNano() == other.toEpochNano();
1342
}
1343
1344
//-----------------------------------------------------------------------
1345
/**
1346
* Checks if this time is equal to another time.
1347
* <p>
1348
* The comparison is based on the local-time and the offset.
1349
* To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}.
1350
* <p>
1351
* Only objects of type {@code OffsetTime} are compared, other types return false.
1352
* To compare the underlying local time of two {@code TemporalAccessor} instances,
1353
* use {@link ChronoField#NANO_OF_DAY} as a comparator.
1354
*
1355
* @param obj the object to check, null returns false
1356
* @return true if this is equal to the other time
1357
*/
1358
@Override
1359
public boolean equals(Object obj) {
1360
if (this == obj) {
1361
return true;
1362
}
1363
return (obj instanceof OffsetTime other)
1364
&& time.equals(other.time)
1365
&& offset.equals(other.offset);
1366
}
1367
1368
/**
1369
* A hash code for this time.
1370
*
1371
* @return a suitable hash code
1372
*/
1373
@Override
1374
public int hashCode() {
1375
return time.hashCode() ^ offset.hashCode();
1376
}
1377
1378
//-----------------------------------------------------------------------
1379
/**
1380
* Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}.
1381
* <p>
1382
* The output will be one of the following ISO-8601 formats:
1383
* <ul>
1384
* <li>{@code HH:mmXXXXX}</li>
1385
* <li>{@code HH:mm:ssXXXXX}</li>
1386
* <li>{@code HH:mm:ss.SSSXXXXX}</li>
1387
* <li>{@code HH:mm:ss.SSSSSSXXXXX}</li>
1388
* <li>{@code HH:mm:ss.SSSSSSSSSXXXXX}</li>
1389
* </ul>
1390
* The format used will be the shortest that outputs the full value of
1391
* the time where the omitted parts are implied to be zero.
1392
*
1393
* @return a string representation of this time, not null
1394
*/
1395
@Override
1396
public String toString() {
1397
return time.toString() + offset.toString();
1398
}
1399
1400
//-----------------------------------------------------------------------
1401
/**
1402
* Writes the object using a
1403
* <a href="{@docRoot}/serialized-form.html#java.time.Ser">dedicated serialized form</a>.
1404
* @serialData
1405
* <pre>
1406
* out.writeByte(9); // identifies an OffsetTime
1407
* // the <a href="{@docRoot}/serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
1408
* // the <a href="{@docRoot}/serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
1409
* </pre>
1410
*
1411
* @return the instance of {@code Ser}, not null
1412
*/
1413
@java.io.Serial
1414
private Object writeReplace() {
1415
return new Ser(Ser.OFFSET_TIME_TYPE, this);
1416
}
1417
1418
/**
1419
* Defend against malicious streams.
1420
*
1421
* @param s the stream to read
1422
* @throws InvalidObjectException always
1423
*/
1424
@java.io.Serial
1425
private void readObject(ObjectInputStream s) throws InvalidObjectException {
1426
throw new InvalidObjectException("Deserialization via serialization delegate");
1427
}
1428
1429
void writeExternal(ObjectOutput out) throws IOException {
1430
time.writeExternal(out);
1431
offset.writeExternal(out);
1432
}
1433
1434
static OffsetTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
1435
LocalTime time = LocalTime.readExternal(in);
1436
ZoneOffset offset = ZoneOffset.readExternal(in);
1437
return OffsetTime.of(time, offset);
1438
}
1439
1440
}
1441
1442