Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/time/chrono/ChronoPeriodImpl.java
41159 views
1
/*
2
* Copyright (c) 2013, 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
* Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
28
*
29
* All rights reserved.
30
*
31
* Redistribution and use in source and binary forms, with or without
32
* modification, are permitted provided that the following conditions are met:
33
*
34
* * Redistributions of source code must retain the above copyright notice,
35
* this list of conditions and the following disclaimer.
36
*
37
* * Redistributions in binary form must reproduce the above copyright notice,
38
* this list of conditions and the following disclaimer in the documentation
39
* and/or other materials provided with the distribution.
40
*
41
* * Neither the name of JSR-310 nor the names of its contributors
42
* may be used to endorse or promote products derived from this software
43
* without specific prior written permission.
44
*
45
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
49
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56
*/
57
package java.time.chrono;
58
59
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
60
import static java.time.temporal.ChronoUnit.DAYS;
61
import static java.time.temporal.ChronoUnit.MONTHS;
62
import static java.time.temporal.ChronoUnit.YEARS;
63
64
import java.io.DataInput;
65
import java.io.DataOutput;
66
import java.io.IOException;
67
import java.io.InvalidObjectException;
68
import java.io.ObjectInputStream;
69
import java.io.ObjectStreamException;
70
import java.io.Serializable;
71
import java.time.DateTimeException;
72
import java.time.temporal.ChronoUnit;
73
import java.time.temporal.Temporal;
74
import java.time.temporal.TemporalAccessor;
75
import java.time.temporal.TemporalAmount;
76
import java.time.temporal.TemporalQueries;
77
import java.time.temporal.TemporalUnit;
78
import java.time.temporal.UnsupportedTemporalTypeException;
79
import java.time.temporal.ValueRange;
80
import java.util.List;
81
import java.util.Objects;
82
83
/**
84
* A period expressed in terms of a standard year-month-day calendar system.
85
* <p>
86
* This class is used by applications seeking to handle dates in non-ISO calendar systems.
87
* For example, the Japanese, Minguo, Thai Buddhist and others.
88
*
89
* @implSpec
90
* This class is immutable nad thread-safe.
91
*
92
* @since 1.8
93
*/
94
final class ChronoPeriodImpl
95
implements ChronoPeriod, Serializable {
96
// this class is only used by JDK chronology implementations and makes assumptions based on that fact
97
98
/**
99
* Serialization version.
100
*/
101
@java.io.Serial
102
private static final long serialVersionUID = 57387258289L;
103
104
/**
105
* The set of supported units.
106
*/
107
private static final List<TemporalUnit> SUPPORTED_UNITS = List.of(YEARS, MONTHS, DAYS);
108
109
/**
110
* The chronology.
111
*/
112
@SuppressWarnings("serial") // Not statically typed as Serializable
113
private final Chronology chrono;
114
/**
115
* The number of years.
116
*/
117
final int years;
118
/**
119
* The number of months.
120
*/
121
final int months;
122
/**
123
* The number of days.
124
*/
125
final int days;
126
127
/**
128
* Creates an instance.
129
*/
130
ChronoPeriodImpl(Chronology chrono, int years, int months, int days) {
131
Objects.requireNonNull(chrono, "chrono");
132
this.chrono = chrono;
133
this.years = years;
134
this.months = months;
135
this.days = days;
136
}
137
138
//-----------------------------------------------------------------------
139
@Override
140
public long get(TemporalUnit unit) {
141
if (unit == ChronoUnit.YEARS) {
142
return years;
143
} else if (unit == ChronoUnit.MONTHS) {
144
return months;
145
} else if (unit == ChronoUnit.DAYS) {
146
return days;
147
} else {
148
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
149
}
150
}
151
152
@Override
153
public List<TemporalUnit> getUnits() {
154
return ChronoPeriodImpl.SUPPORTED_UNITS;
155
}
156
157
@Override
158
public Chronology getChronology() {
159
return chrono;
160
}
161
162
//-----------------------------------------------------------------------
163
@Override
164
public boolean isZero() {
165
return years == 0 && months == 0 && days == 0;
166
}
167
168
@Override
169
public boolean isNegative() {
170
return years < 0 || months < 0 || days < 0;
171
}
172
173
//-----------------------------------------------------------------------
174
@Override
175
public ChronoPeriod plus(TemporalAmount amountToAdd) {
176
ChronoPeriodImpl amount = validateAmount(amountToAdd);
177
return new ChronoPeriodImpl(
178
chrono,
179
Math.addExact(years, amount.years),
180
Math.addExact(months, amount.months),
181
Math.addExact(days, amount.days));
182
}
183
184
@Override
185
public ChronoPeriod minus(TemporalAmount amountToSubtract) {
186
ChronoPeriodImpl amount = validateAmount(amountToSubtract);
187
return new ChronoPeriodImpl(
188
chrono,
189
Math.subtractExact(years, amount.years),
190
Math.subtractExact(months, amount.months),
191
Math.subtractExact(days, amount.days));
192
}
193
194
/**
195
* Obtains an instance of {@code ChronoPeriodImpl} from a temporal amount.
196
*
197
* @param amount the temporal amount to convert, not null
198
* @return the period, not null
199
*/
200
private ChronoPeriodImpl validateAmount(TemporalAmount amount) {
201
Objects.requireNonNull(amount, "amount");
202
if (!(amount instanceof ChronoPeriodImpl period)) {
203
throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass());
204
}
205
if (!(chrono.equals(period.getChronology()))) {
206
throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId());
207
}
208
return period;
209
}
210
211
//-----------------------------------------------------------------------
212
@Override
213
public ChronoPeriod multipliedBy(int scalar) {
214
if (this.isZero() || scalar == 1) {
215
return this;
216
}
217
return new ChronoPeriodImpl(
218
chrono,
219
Math.multiplyExact(years, scalar),
220
Math.multiplyExact(months, scalar),
221
Math.multiplyExact(days, scalar));
222
}
223
224
//-----------------------------------------------------------------------
225
@Override
226
public ChronoPeriod normalized() {
227
long monthRange = monthRange();
228
if (monthRange > 0) {
229
long totalMonths = years * monthRange + months;
230
long splitYears = totalMonths / monthRange;
231
int splitMonths = (int) (totalMonths % monthRange); // no overflow
232
if (splitYears == years && splitMonths == months) {
233
return this;
234
}
235
return new ChronoPeriodImpl(chrono, Math.toIntExact(splitYears), splitMonths, days);
236
237
}
238
return this;
239
}
240
241
/**
242
* Calculates the range of months.
243
*
244
* @return the month range, -1 if not fixed range
245
*/
246
private long monthRange() {
247
ValueRange startRange = chrono.range(MONTH_OF_YEAR);
248
if (startRange.isFixed() && startRange.isIntValue()) {
249
return startRange.getMaximum() - startRange.getMinimum() + 1;
250
}
251
return -1;
252
}
253
254
//-------------------------------------------------------------------------
255
@Override
256
public Temporal addTo(Temporal temporal) {
257
validateChrono(temporal);
258
if (months == 0) {
259
if (years != 0) {
260
temporal = temporal.plus(years, YEARS);
261
}
262
} else {
263
long monthRange = monthRange();
264
if (monthRange > 0) {
265
temporal = temporal.plus(years * monthRange + months, MONTHS);
266
} else {
267
if (years != 0) {
268
temporal = temporal.plus(years, YEARS);
269
}
270
temporal = temporal.plus(months, MONTHS);
271
}
272
}
273
if (days != 0) {
274
temporal = temporal.plus(days, DAYS);
275
}
276
return temporal;
277
}
278
279
280
281
@Override
282
public Temporal subtractFrom(Temporal temporal) {
283
validateChrono(temporal);
284
if (months == 0) {
285
if (years != 0) {
286
temporal = temporal.minus(years, YEARS);
287
}
288
} else {
289
long monthRange = monthRange();
290
if (monthRange > 0) {
291
temporal = temporal.minus(years * monthRange + months, MONTHS);
292
} else {
293
if (years != 0) {
294
temporal = temporal.minus(years, YEARS);
295
}
296
temporal = temporal.minus(months, MONTHS);
297
}
298
}
299
if (days != 0) {
300
temporal = temporal.minus(days, DAYS);
301
}
302
return temporal;
303
}
304
305
/**
306
* Validates that the temporal has the correct chronology.
307
*/
308
private void validateChrono(TemporalAccessor temporal) {
309
Objects.requireNonNull(temporal, "temporal");
310
Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
311
if (temporalChrono != null && chrono.equals(temporalChrono) == false) {
312
throw new DateTimeException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + temporalChrono.getId());
313
}
314
}
315
316
//-----------------------------------------------------------------------
317
@Override
318
public boolean equals(Object obj) {
319
if (this == obj) {
320
return true;
321
}
322
return (obj instanceof ChronoPeriodImpl other)
323
&& years == other.years && months == other.months
324
&& days == other.days && chrono.equals(other.chrono);
325
}
326
327
@Override
328
public int hashCode() {
329
return (years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16)) ^ chrono.hashCode();
330
}
331
332
//-----------------------------------------------------------------------
333
@Override
334
public String toString() {
335
if (isZero()) {
336
return getChronology().toString() + " P0D";
337
} else {
338
StringBuilder buf = new StringBuilder();
339
buf.append(getChronology().toString()).append(' ').append('P');
340
if (years != 0) {
341
buf.append(years).append('Y');
342
}
343
if (months != 0) {
344
buf.append(months).append('M');
345
}
346
if (days != 0) {
347
buf.append(days).append('D');
348
}
349
return buf.toString();
350
}
351
}
352
353
//-----------------------------------------------------------------------
354
/**
355
* Writes the Chronology using a
356
* <a href="{@docRoot}/serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
357
* <pre>
358
* out.writeByte(12); // identifies this as a ChronoPeriodImpl
359
* out.writeUTF(getId()); // the chronology
360
* out.writeInt(years);
361
* out.writeInt(months);
362
* out.writeInt(days);
363
* </pre>
364
*
365
* @return the instance of {@code Ser}, not null
366
*/
367
@java.io.Serial
368
protected Object writeReplace() {
369
return new Ser(Ser.CHRONO_PERIOD_TYPE, this);
370
}
371
372
/**
373
* Defend against malicious streams.
374
*
375
* @param s the stream to read
376
* @throws InvalidObjectException always
377
*/
378
@java.io.Serial
379
private void readObject(ObjectInputStream s) throws ObjectStreamException {
380
throw new InvalidObjectException("Deserialization via serialization delegate");
381
}
382
383
void writeExternal(DataOutput out) throws IOException {
384
out.writeUTF(chrono.getId());
385
out.writeInt(years);
386
out.writeInt(months);
387
out.writeInt(days);
388
}
389
390
static ChronoPeriodImpl readExternal(DataInput in) throws IOException {
391
Chronology chrono = Chronology.of(in.readUTF());
392
int years = in.readInt();
393
int months = in.readInt();
394
int days = in.readInt();
395
return new ChronoPeriodImpl(chrono, years, months, days);
396
}
397
398
}
399
400