Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/time/YearMonth.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.temporal.ChronoField.ERA;
65
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
66
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
67
import static java.time.temporal.ChronoField.YEAR;
68
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
69
import static java.time.temporal.ChronoUnit.CENTURIES;
70
import static java.time.temporal.ChronoUnit.DECADES;
71
import static java.time.temporal.ChronoUnit.ERAS;
72
import static java.time.temporal.ChronoUnit.MILLENNIA;
73
import static java.time.temporal.ChronoUnit.MONTHS;
74
import static java.time.temporal.ChronoUnit.YEARS;
75
76
import java.io.DataInput;
77
import java.io.DataOutput;
78
import java.io.IOException;
79
import java.io.InvalidObjectException;
80
import java.io.ObjectInputStream;
81
import java.io.Serializable;
82
import java.time.chrono.Chronology;
83
import java.time.chrono.IsoChronology;
84
import java.time.format.DateTimeFormatter;
85
import java.time.format.DateTimeFormatterBuilder;
86
import java.time.format.DateTimeParseException;
87
import java.time.format.SignStyle;
88
import java.time.temporal.ChronoField;
89
import java.time.temporal.ChronoUnit;
90
import java.time.temporal.Temporal;
91
import java.time.temporal.TemporalAccessor;
92
import java.time.temporal.TemporalAdjuster;
93
import java.time.temporal.TemporalAmount;
94
import java.time.temporal.TemporalField;
95
import java.time.temporal.TemporalQueries;
96
import java.time.temporal.TemporalQuery;
97
import java.time.temporal.TemporalUnit;
98
import java.time.temporal.UnsupportedTemporalTypeException;
99
import java.time.temporal.ValueRange;
100
import java.util.Objects;
101
102
/**
103
* A year-month in the ISO-8601 calendar system, such as {@code 2007-12}.
104
* <p>
105
* {@code YearMonth} is an immutable date-time object that represents the combination
106
* of a year and month. Any field that can be derived from a year and month, such as
107
* quarter-of-year, can be obtained.
108
* <p>
109
* This class does not store or represent a day, time or time-zone.
110
* For example, the value "October 2007" can be stored in a {@code YearMonth}.
111
* <p>
112
* The ISO-8601 calendar system is the modern civil calendar system used today
113
* in most of the world. It is equivalent to the proleptic Gregorian calendar
114
* system, in which today's rules for leap years are applied for all time.
115
* For most applications written today, the ISO-8601 rules are entirely suitable.
116
* However, any application that makes use of historical dates, and requires them
117
* to be accurate will find the ISO-8601 approach unsuitable.
118
* <p>
119
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
120
* class; programmers should treat instances that are
121
* {@linkplain #equals(Object) equal} as interchangeable and should not
122
* use instances for synchronization, or unpredictable behavior may
123
* occur. For example, in a future release, synchronization may fail.
124
* The {@code equals} method should be used for comparisons.
125
*
126
* @implSpec
127
* This class is immutable and thread-safe.
128
*
129
* @since 1.8
130
*/
131
@jdk.internal.ValueBased
132
public final class YearMonth
133
implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable {
134
135
/**
136
* Serialization version.
137
*/
138
@java.io.Serial
139
private static final long serialVersionUID = 4183400860270640070L;
140
/**
141
* Parser.
142
*/
143
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
144
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
145
.appendLiteral('-')
146
.appendValue(MONTH_OF_YEAR, 2)
147
.toFormatter();
148
149
/**
150
* The year.
151
*/
152
private final int year;
153
/**
154
* The month-of-year, not null.
155
*/
156
private final int month;
157
158
//-----------------------------------------------------------------------
159
/**
160
* Obtains the current year-month from the system clock in the default time-zone.
161
* <p>
162
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
163
* time-zone to obtain the current year-month.
164
* <p>
165
* Using this method will prevent the ability to use an alternate clock for testing
166
* because the clock is hard-coded.
167
*
168
* @return the current year-month using the system clock and default time-zone, not null
169
*/
170
public static YearMonth now() {
171
return now(Clock.systemDefaultZone());
172
}
173
174
/**
175
* Obtains the current year-month from the system clock in the specified time-zone.
176
* <p>
177
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current year-month.
178
* Specifying the time-zone avoids dependence on the default time-zone.
179
* <p>
180
* Using this method will prevent the ability to use an alternate clock for testing
181
* because the clock is hard-coded.
182
*
183
* @param zone the zone ID to use, not null
184
* @return the current year-month using the system clock, not null
185
*/
186
public static YearMonth now(ZoneId zone) {
187
return now(Clock.system(zone));
188
}
189
190
/**
191
* Obtains the current year-month from the specified clock.
192
* <p>
193
* This will query the specified clock to obtain the current year-month.
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 year-month, not null
199
*/
200
public static YearMonth now(Clock clock) {
201
final LocalDate now = LocalDate.now(clock); // called once
202
return YearMonth.of(now.getYear(), now.getMonth());
203
}
204
205
//-----------------------------------------------------------------------
206
/**
207
* Obtains an instance of {@code YearMonth} from a year and month.
208
*
209
* @param year the year to represent, from MIN_YEAR to MAX_YEAR
210
* @param month the month-of-year to represent, not null
211
* @return the year-month, not null
212
* @throws DateTimeException if the year value is invalid
213
*/
214
public static YearMonth of(int year, Month month) {
215
Objects.requireNonNull(month, "month");
216
return of(year, month.getValue());
217
}
218
219
/**
220
* Obtains an instance of {@code YearMonth} from a year and month.
221
*
222
* @param year the year to represent, from MIN_YEAR to MAX_YEAR
223
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
224
* @return the year-month, not null
225
* @throws DateTimeException if either field value is invalid
226
*/
227
public static YearMonth of(int year, int month) {
228
YEAR.checkValidValue(year);
229
MONTH_OF_YEAR.checkValidValue(month);
230
return new YearMonth(year, month);
231
}
232
233
//-----------------------------------------------------------------------
234
/**
235
* Obtains an instance of {@code YearMonth} from a temporal object.
236
* <p>
237
* This obtains a year-month based on the specified temporal.
238
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
239
* which this factory converts to an instance of {@code YearMonth}.
240
* <p>
241
* The conversion extracts the {@link ChronoField#YEAR YEAR} and
242
* {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields.
243
* The extraction is only permitted if the temporal object has an ISO
244
* chronology, or can be converted to a {@code LocalDate}.
245
* <p>
246
* This method matches the signature of the functional interface {@link TemporalQuery}
247
* allowing it to be used as a query via method reference, {@code YearMonth::from}.
248
*
249
* @param temporal the temporal object to convert, not null
250
* @return the year-month, not null
251
* @throws DateTimeException if unable to convert to a {@code YearMonth}
252
*/
253
public static YearMonth from(TemporalAccessor temporal) {
254
if (temporal instanceof YearMonth) {
255
return (YearMonth) temporal;
256
}
257
Objects.requireNonNull(temporal, "temporal");
258
try {
259
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
260
temporal = LocalDate.from(temporal);
261
}
262
return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR));
263
} catch (DateTimeException ex) {
264
throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " +
265
temporal + " of type " + temporal.getClass().getName(), ex);
266
}
267
}
268
269
//-----------------------------------------------------------------------
270
/**
271
* Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}.
272
* <p>
273
* The string must represent a valid year-month.
274
* The format must be {@code uuuu-MM}.
275
* Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
276
*
277
* @param text the text to parse such as "2007-12", not null
278
* @return the parsed year-month, not null
279
* @throws DateTimeParseException if the text cannot be parsed
280
*/
281
public static YearMonth parse(CharSequence text) {
282
return parse(text, PARSER);
283
}
284
285
/**
286
* Obtains an instance of {@code YearMonth} from a text string using a specific formatter.
287
* <p>
288
* The text is parsed using the formatter, returning a year-month.
289
*
290
* @param text the text to parse, not null
291
* @param formatter the formatter to use, not null
292
* @return the parsed year-month, not null
293
* @throws DateTimeParseException if the text cannot be parsed
294
*/
295
public static YearMonth parse(CharSequence text, DateTimeFormatter formatter) {
296
Objects.requireNonNull(formatter, "formatter");
297
return formatter.parse(text, YearMonth::from);
298
}
299
300
//-----------------------------------------------------------------------
301
/**
302
* Constructor.
303
*
304
* @param year the year to represent, validated from MIN_YEAR to MAX_YEAR
305
* @param month the month-of-year to represent, validated from 1 (January) to 12 (December)
306
*/
307
private YearMonth(int year, int month) {
308
this.year = year;
309
this.month = month;
310
}
311
312
/**
313
* Returns a copy of this year-month with the new year and month, checking
314
* to see if a new object is in fact required.
315
*
316
* @param newYear the year to represent, validated from MIN_YEAR to MAX_YEAR
317
* @param newMonth the month-of-year to represent, validated not null
318
* @return the year-month, not null
319
*/
320
private YearMonth with(int newYear, int newMonth) {
321
if (year == newYear && month == newMonth) {
322
return this;
323
}
324
return new YearMonth(newYear, newMonth);
325
}
326
327
//-----------------------------------------------------------------------
328
/**
329
* Checks if the specified field is supported.
330
* <p>
331
* This checks if this year-month can be queried for the specified field.
332
* If false, then calling the {@link #range(TemporalField) range},
333
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
334
* methods will throw an exception.
335
* <p>
336
* If the field is a {@link ChronoField} then the query is implemented here.
337
* The supported fields are:
338
* <ul>
339
* <li>{@code MONTH_OF_YEAR}
340
* <li>{@code PROLEPTIC_MONTH}
341
* <li>{@code YEAR_OF_ERA}
342
* <li>{@code YEAR}
343
* <li>{@code ERA}
344
* </ul>
345
* All other {@code ChronoField} instances will return false.
346
* <p>
347
* If the field is not a {@code ChronoField}, then the result of this method
348
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
349
* passing {@code this} as the argument.
350
* Whether the field is supported is determined by the field.
351
*
352
* @param field the field to check, null returns false
353
* @return true if the field is supported on this year-month, false if not
354
*/
355
@Override
356
public boolean isSupported(TemporalField field) {
357
if (field instanceof ChronoField) {
358
return field == YEAR || field == MONTH_OF_YEAR ||
359
field == PROLEPTIC_MONTH || field == YEAR_OF_ERA || field == ERA;
360
}
361
return field != null && field.isSupportedBy(this);
362
}
363
364
/**
365
* Checks if the specified unit is supported.
366
* <p>
367
* This checks if the specified unit can be added to, or subtracted from, this year-month.
368
* If false, then calling the {@link #plus(long, TemporalUnit)} and
369
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
370
* <p>
371
* If the unit is a {@link ChronoUnit} then the query is implemented here.
372
* The supported units are:
373
* <ul>
374
* <li>{@code MONTHS}
375
* <li>{@code YEARS}
376
* <li>{@code DECADES}
377
* <li>{@code CENTURIES}
378
* <li>{@code MILLENNIA}
379
* <li>{@code ERAS}
380
* </ul>
381
* All other {@code ChronoUnit} instances will return false.
382
* <p>
383
* If the unit is not a {@code ChronoUnit}, then the result of this method
384
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
385
* passing {@code this} as the argument.
386
* Whether the unit is supported is determined by the unit.
387
*
388
* @param unit the unit to check, null returns false
389
* @return true if the unit can be added/subtracted, false if not
390
*/
391
@Override
392
public boolean isSupported(TemporalUnit unit) {
393
if (unit instanceof ChronoUnit) {
394
return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
395
}
396
return unit != null && unit.isSupportedBy(this);
397
}
398
399
//-----------------------------------------------------------------------
400
/**
401
* Gets the range of valid values for the specified field.
402
* <p>
403
* The range object expresses the minimum and maximum valid values for a field.
404
* This year-month is used to enhance the accuracy of the returned range.
405
* If it is not possible to return the range, because the field is not supported
406
* or for some other reason, an exception is thrown.
407
* <p>
408
* If the field is a {@link ChronoField} then the query is implemented here.
409
* The {@link #isSupported(TemporalField) supported fields} will return
410
* appropriate range instances.
411
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
412
* <p>
413
* If the field is not a {@code ChronoField}, then the result of this method
414
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
415
* passing {@code this} as the argument.
416
* Whether the range can be obtained is determined by the field.
417
*
418
* @param field the field to query the range for, not null
419
* @return the range of valid values for the field, not null
420
* @throws DateTimeException if the range for the field cannot be obtained
421
* @throws UnsupportedTemporalTypeException if the field is not supported
422
*/
423
@Override
424
public ValueRange range(TemporalField field) {
425
if (field == YEAR_OF_ERA) {
426
return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
427
}
428
return Temporal.super.range(field);
429
}
430
431
/**
432
* Gets the value of the specified field from this year-month as an {@code int}.
433
* <p>
434
* This queries this year-month for the value of the specified field.
435
* The returned value will always be within the valid range of values for the field.
436
* If it is not possible to return the value, because the field is not supported
437
* or for some other reason, an exception is thrown.
438
* <p>
439
* If the field is a {@link ChronoField} then the query is implemented here.
440
* The {@link #isSupported(TemporalField) supported fields} will return valid
441
* values based on this year-month, except {@code PROLEPTIC_MONTH} which is too
442
* large to fit in an {@code int} and throw a {@code DateTimeException}.
443
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
444
* <p>
445
* If the field is not a {@code ChronoField}, then the result of this method
446
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
447
* passing {@code this} as the argument. Whether the value can be obtained,
448
* and what the value represents, is determined by the field.
449
*
450
* @param field the field to get, not null
451
* @return the value for the field
452
* @throws DateTimeException if a value for the field cannot be obtained or
453
* the value is outside the range of valid values for the field
454
* @throws UnsupportedTemporalTypeException if the field is not supported or
455
* the range of values exceeds an {@code int}
456
* @throws ArithmeticException if numeric overflow occurs
457
*/
458
@Override // override for Javadoc
459
public int get(TemporalField field) {
460
return range(field).checkValidIntValue(getLong(field), field);
461
}
462
463
/**
464
* Gets the value of the specified field from this year-month as a {@code long}.
465
* <p>
466
* This queries this year-month for the value of the specified field.
467
* If it is not possible to return the value, because the field is not supported
468
* or for some other reason, an exception is thrown.
469
* <p>
470
* If the field is a {@link ChronoField} then the query is implemented here.
471
* The {@link #isSupported(TemporalField) supported fields} will return valid
472
* values based on this year-month.
473
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
474
* <p>
475
* If the field is not a {@code ChronoField}, then the result of this method
476
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
477
* passing {@code this} as the argument. Whether the value can be obtained,
478
* and what the value represents, is determined by the field.
479
*
480
* @param field the field to get, not null
481
* @return the value for the field
482
* @throws DateTimeException if a value for the field cannot be obtained
483
* @throws UnsupportedTemporalTypeException if the field is not supported
484
* @throws ArithmeticException if numeric overflow occurs
485
*/
486
@Override
487
public long getLong(TemporalField field) {
488
if (field instanceof ChronoField chronoField) {
489
switch (chronoField) {
490
case MONTH_OF_YEAR: return month;
491
case PROLEPTIC_MONTH: return getProlepticMonth();
492
case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
493
case YEAR: return year;
494
case ERA: return (year < 1 ? 0 : 1);
495
}
496
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
497
}
498
return field.getFrom(this);
499
}
500
501
private long getProlepticMonth() {
502
return (year * 12L + month - 1);
503
}
504
505
//-----------------------------------------------------------------------
506
/**
507
* Gets the year field.
508
* <p>
509
* This method returns the primitive {@code int} value for the year.
510
* <p>
511
* The year returned by this method is proleptic as per {@code get(YEAR)}.
512
*
513
* @return the year, from MIN_YEAR to MAX_YEAR
514
*/
515
public int getYear() {
516
return year;
517
}
518
519
/**
520
* Gets the month-of-year field from 1 to 12.
521
* <p>
522
* This method returns the month as an {@code int} from 1 to 12.
523
* Application code is frequently clearer if the enum {@link Month}
524
* is used by calling {@link #getMonth()}.
525
*
526
* @return the month-of-year, from 1 to 12
527
* @see #getMonth()
528
*/
529
public int getMonthValue() {
530
return month;
531
}
532
533
/**
534
* Gets the month-of-year field using the {@code Month} enum.
535
* <p>
536
* This method returns the enum {@link Month} for the month.
537
* This avoids confusion as to what {@code int} values mean.
538
* If you need access to the primitive {@code int} value then the enum
539
* provides the {@link Month#getValue() int value}.
540
*
541
* @return the month-of-year, not null
542
* @see #getMonthValue()
543
*/
544
public Month getMonth() {
545
return Month.of(month);
546
}
547
548
//-----------------------------------------------------------------------
549
/**
550
* Checks if the year is a leap year, according to the ISO proleptic
551
* calendar system rules.
552
* <p>
553
* This method applies the current rules for leap years across the whole time-line.
554
* In general, a year is a leap year if it is divisible by four without
555
* remainder. However, years divisible by 100, are not leap years, with
556
* the exception of years divisible by 400 which are.
557
* <p>
558
* For example, 1904 is a leap year it is divisible by 4.
559
* 1900 was not a leap year as it is divisible by 100, however 2000 was a
560
* leap year as it is divisible by 400.
561
* <p>
562
* The calculation is proleptic - applying the same rules into the far future and far past.
563
* This is historically inaccurate, but is correct for the ISO-8601 standard.
564
*
565
* @return true if the year is leap, false otherwise
566
*/
567
public boolean isLeapYear() {
568
return IsoChronology.INSTANCE.isLeapYear(year);
569
}
570
571
/**
572
* Checks if the day-of-month is valid for this year-month.
573
* <p>
574
* This method checks whether this year and month and the input day form
575
* a valid date.
576
*
577
* @param dayOfMonth the day-of-month to validate, from 1 to 31, invalid value returns false
578
* @return true if the day is valid for this year-month
579
*/
580
public boolean isValidDay(int dayOfMonth) {
581
return dayOfMonth >= 1 && dayOfMonth <= lengthOfMonth();
582
}
583
584
/**
585
* Returns the length of the month, taking account of the year.
586
* <p>
587
* This returns the length of the month in days.
588
* For example, a date in January would return 31.
589
*
590
* @return the length of the month in days, from 28 to 31
591
*/
592
public int lengthOfMonth() {
593
return getMonth().length(isLeapYear());
594
}
595
596
/**
597
* Returns the length of the year.
598
* <p>
599
* This returns the length of the year in days, either 365 or 366.
600
*
601
* @return 366 if the year is leap, 365 otherwise
602
*/
603
public int lengthOfYear() {
604
return (isLeapYear() ? 366 : 365);
605
}
606
607
//-----------------------------------------------------------------------
608
/**
609
* Returns an adjusted copy of this year-month.
610
* <p>
611
* This returns a {@code YearMonth}, based on this one, with the year-month adjusted.
612
* The adjustment takes place using the specified adjuster strategy object.
613
* Read the documentation of the adjuster to understand what adjustment will be made.
614
* <p>
615
* A simple adjuster might simply set the one of the fields, such as the year field.
616
* A more complex adjuster might set the year-month to the next month that
617
* Halley's comet will pass the Earth.
618
* <p>
619
* The result of this method is obtained by invoking the
620
* {@link TemporalAdjuster#adjustInto(Temporal)} method on the
621
* specified adjuster passing {@code this} as the argument.
622
* <p>
623
* This instance is immutable and unaffected by this method call.
624
*
625
* @param adjuster the adjuster to use, not null
626
* @return a {@code YearMonth} based on {@code this} with the adjustment made, not null
627
* @throws DateTimeException if the adjustment cannot be made
628
* @throws ArithmeticException if numeric overflow occurs
629
*/
630
@Override
631
public YearMonth with(TemporalAdjuster adjuster) {
632
return (YearMonth) adjuster.adjustInto(this);
633
}
634
635
/**
636
* Returns a copy of this year-month with the specified field set to a new value.
637
* <p>
638
* This returns a {@code YearMonth}, based on this one, with the value
639
* for the specified field changed.
640
* This can be used to change any supported field, such as the year or month.
641
* If it is not possible to set the value, because the field is not supported or for
642
* some other reason, an exception is thrown.
643
* <p>
644
* If the field is a {@link ChronoField} then the adjustment is implemented here.
645
* The supported fields behave as follows:
646
* <ul>
647
* <li>{@code MONTH_OF_YEAR} -
648
* Returns a {@code YearMonth} with the specified month-of-year.
649
* The year will be unchanged.
650
* <li>{@code PROLEPTIC_MONTH} -
651
* Returns a {@code YearMonth} with the specified proleptic-month.
652
* This completely replaces the year and month of this object.
653
* <li>{@code YEAR_OF_ERA} -
654
* Returns a {@code YearMonth} with the specified year-of-era
655
* The month and era will be unchanged.
656
* <li>{@code YEAR} -
657
* Returns a {@code YearMonth} with the specified year.
658
* The month will be unchanged.
659
* <li>{@code ERA} -
660
* Returns a {@code YearMonth} with the specified era.
661
* The month and year-of-era will be unchanged.
662
* </ul>
663
* <p>
664
* In all cases, if the new value is outside the valid range of values for the field
665
* then a {@code DateTimeException} will be thrown.
666
* <p>
667
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
668
* <p>
669
* If the field is not a {@code ChronoField}, then the result of this method
670
* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
671
* passing {@code this} as the argument. In this case, the field determines
672
* whether and how to adjust the instant.
673
* <p>
674
* This instance is immutable and unaffected by this method call.
675
*
676
* @param field the field to set in the result, not null
677
* @param newValue the new value of the field in the result
678
* @return a {@code YearMonth} based on {@code this} with the specified field set, not null
679
* @throws DateTimeException if the field cannot be set
680
* @throws UnsupportedTemporalTypeException if the field is not supported
681
* @throws ArithmeticException if numeric overflow occurs
682
*/
683
@Override
684
public YearMonth with(TemporalField field, long newValue) {
685
if (field instanceof ChronoField chronoField) {
686
chronoField.checkValidValue(newValue);
687
switch (chronoField) {
688
case MONTH_OF_YEAR: return withMonth((int) newValue);
689
case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
690
case YEAR_OF_ERA: return withYear((int) (year < 1 ? 1 - newValue : newValue));
691
case YEAR: return withYear((int) newValue);
692
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
693
}
694
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
695
}
696
return field.adjustInto(this, newValue);
697
}
698
699
//-----------------------------------------------------------------------
700
/**
701
* Returns a copy of this {@code YearMonth} with the year altered.
702
* <p>
703
* This instance is immutable and unaffected by this method call.
704
*
705
* @param year the year to set in the returned year-month, from MIN_YEAR to MAX_YEAR
706
* @return a {@code YearMonth} based on this year-month with the requested year, not null
707
* @throws DateTimeException if the year value is invalid
708
*/
709
public YearMonth withYear(int year) {
710
YEAR.checkValidValue(year);
711
return with(year, month);
712
}
713
714
/**
715
* Returns a copy of this {@code YearMonth} with the month-of-year altered.
716
* <p>
717
* This instance is immutable and unaffected by this method call.
718
*
719
* @param month the month-of-year to set in the returned year-month, from 1 (January) to 12 (December)
720
* @return a {@code YearMonth} based on this year-month with the requested month, not null
721
* @throws DateTimeException if the month-of-year value is invalid
722
*/
723
public YearMonth withMonth(int month) {
724
MONTH_OF_YEAR.checkValidValue(month);
725
return with(year, month);
726
}
727
728
//-----------------------------------------------------------------------
729
/**
730
* Returns a copy of this year-month with the specified amount added.
731
* <p>
732
* This returns a {@code YearMonth}, based on this one, with the specified amount added.
733
* The amount is typically {@link Period} but may be any other type implementing
734
* the {@link TemporalAmount} interface.
735
* <p>
736
* The calculation is delegated to the amount object by calling
737
* {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
738
* to implement the addition in any way it wishes, however it typically
739
* calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
740
* of the amount implementation to determine if it can be successfully added.
741
* <p>
742
* This instance is immutable and unaffected by this method call.
743
*
744
* @param amountToAdd the amount to add, not null
745
* @return a {@code YearMonth} based on this year-month with the addition made, not null
746
* @throws DateTimeException if the addition cannot be made
747
* @throws ArithmeticException if numeric overflow occurs
748
*/
749
@Override
750
public YearMonth plus(TemporalAmount amountToAdd) {
751
return (YearMonth) amountToAdd.addTo(this);
752
}
753
754
/**
755
* Returns a copy of this year-month with the specified amount added.
756
* <p>
757
* This returns a {@code YearMonth}, based on this one, with the amount
758
* in terms of the unit added. If it is not possible to add the amount, because the
759
* unit is not supported or for some other reason, an exception is thrown.
760
* <p>
761
* If the field is a {@link ChronoUnit} then the addition is implemented here.
762
* The supported fields behave as follows:
763
* <ul>
764
* <li>{@code MONTHS} -
765
* Returns a {@code YearMonth} with the specified number of months added.
766
* This is equivalent to {@link #plusMonths(long)}.
767
* <li>{@code YEARS} -
768
* Returns a {@code YearMonth} with the specified number of years added.
769
* This is equivalent to {@link #plusYears(long)}.
770
* <li>{@code DECADES} -
771
* Returns a {@code YearMonth} with the specified number of decades added.
772
* This is equivalent to calling {@link #plusYears(long)} with the amount
773
* multiplied by 10.
774
* <li>{@code CENTURIES} -
775
* Returns a {@code YearMonth} with the specified number of centuries added.
776
* This is equivalent to calling {@link #plusYears(long)} with the amount
777
* multiplied by 100.
778
* <li>{@code MILLENNIA} -
779
* Returns a {@code YearMonth} with the specified number of millennia added.
780
* This is equivalent to calling {@link #plusYears(long)} with the amount
781
* multiplied by 1,000.
782
* <li>{@code ERAS} -
783
* Returns a {@code YearMonth} with the specified number of eras added.
784
* Only two eras are supported so the amount must be one, zero or minus one.
785
* If the amount is non-zero then the year is changed such that the year-of-era
786
* is unchanged.
787
* </ul>
788
* <p>
789
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
790
* <p>
791
* If the field is not a {@code ChronoUnit}, then the result of this method
792
* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
793
* passing {@code this} as the argument. In this case, the unit determines
794
* whether and how to perform the addition.
795
* <p>
796
* This instance is immutable and unaffected by this method call.
797
*
798
* @param amountToAdd the amount of the unit to add to the result, may be negative
799
* @param unit the unit of the amount to add, not null
800
* @return a {@code YearMonth} based on this year-month with the specified amount added, not null
801
* @throws DateTimeException if the addition cannot be made
802
* @throws UnsupportedTemporalTypeException if the unit is not supported
803
* @throws ArithmeticException if numeric overflow occurs
804
*/
805
@Override
806
public YearMonth plus(long amountToAdd, TemporalUnit unit) {
807
if (unit instanceof ChronoUnit chronoUnit) {
808
switch (chronoUnit) {
809
case MONTHS: return plusMonths(amountToAdd);
810
case YEARS: return plusYears(amountToAdd);
811
case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
812
case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
813
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
814
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
815
}
816
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
817
}
818
return unit.addTo(this, amountToAdd);
819
}
820
821
/**
822
* Returns a copy of this {@code YearMonth} with the specified number of years added.
823
* <p>
824
* This instance is immutable and unaffected by this method call.
825
*
826
* @param yearsToAdd the years to add, may be negative
827
* @return a {@code YearMonth} based on this year-month with the years added, not null
828
* @throws DateTimeException if the result exceeds the supported range
829
*/
830
public YearMonth plusYears(long yearsToAdd) {
831
if (yearsToAdd == 0) {
832
return this;
833
}
834
int newYear = YEAR.checkValidIntValue(year + yearsToAdd); // safe overflow
835
return with(newYear, month);
836
}
837
838
/**
839
* Returns a copy of this {@code YearMonth} with the specified number of months added.
840
* <p>
841
* This instance is immutable and unaffected by this method call.
842
*
843
* @param monthsToAdd the months to add, may be negative
844
* @return a {@code YearMonth} based on this year-month with the months added, not null
845
* @throws DateTimeException if the result exceeds the supported range
846
*/
847
public YearMonth plusMonths(long monthsToAdd) {
848
if (monthsToAdd == 0) {
849
return this;
850
}
851
long monthCount = year * 12L + (month - 1);
852
long calcMonths = monthCount + monthsToAdd; // safe overflow
853
int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
854
int newMonth = Math.floorMod(calcMonths, 12) + 1;
855
return with(newYear, newMonth);
856
}
857
858
//-----------------------------------------------------------------------
859
/**
860
* Returns a copy of this year-month with the specified amount subtracted.
861
* <p>
862
* This returns a {@code YearMonth}, based on this one, with the specified amount subtracted.
863
* The amount is typically {@link Period} but may be any other type implementing
864
* the {@link TemporalAmount} interface.
865
* <p>
866
* The calculation is delegated to the amount object by calling
867
* {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
868
* to implement the subtraction in any way it wishes, however it typically
869
* calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
870
* of the amount implementation to determine if it can be successfully subtracted.
871
* <p>
872
* This instance is immutable and unaffected by this method call.
873
*
874
* @param amountToSubtract the amount to subtract, not null
875
* @return a {@code YearMonth} based on this year-month with the subtraction made, not null
876
* @throws DateTimeException if the subtraction cannot be made
877
* @throws ArithmeticException if numeric overflow occurs
878
*/
879
@Override
880
public YearMonth minus(TemporalAmount amountToSubtract) {
881
return (YearMonth) amountToSubtract.subtractFrom(this);
882
}
883
884
/**
885
* Returns a copy of this year-month with the specified amount subtracted.
886
* <p>
887
* This returns a {@code YearMonth}, based on this one, with the amount
888
* in terms of the unit subtracted. If it is not possible to subtract the amount,
889
* because the unit is not supported or for some other reason, an exception is thrown.
890
* <p>
891
* This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
892
* See that method for a full description of how addition, and thus subtraction, works.
893
* <p>
894
* This instance is immutable and unaffected by this method call.
895
*
896
* @param amountToSubtract the amount of the unit to subtract from the result, may be negative
897
* @param unit the unit of the amount to subtract, not null
898
* @return a {@code YearMonth} based on this year-month with the specified amount subtracted, not null
899
* @throws DateTimeException if the subtraction cannot be made
900
* @throws UnsupportedTemporalTypeException if the unit is not supported
901
* @throws ArithmeticException if numeric overflow occurs
902
*/
903
@Override
904
public YearMonth minus(long amountToSubtract, TemporalUnit unit) {
905
return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
906
}
907
908
/**
909
* Returns a copy of this {@code YearMonth} with the specified number of years subtracted.
910
* <p>
911
* This instance is immutable and unaffected by this method call.
912
*
913
* @param yearsToSubtract the years to subtract, may be negative
914
* @return a {@code YearMonth} based on this year-month with the years subtracted, not null
915
* @throws DateTimeException if the result exceeds the supported range
916
*/
917
public YearMonth minusYears(long yearsToSubtract) {
918
return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
919
}
920
921
/**
922
* Returns a copy of this {@code YearMonth} with the specified number of months subtracted.
923
* <p>
924
* This instance is immutable and unaffected by this method call.
925
*
926
* @param monthsToSubtract the months to subtract, may be negative
927
* @return a {@code YearMonth} based on this year-month with the months subtracted, not null
928
* @throws DateTimeException if the result exceeds the supported range
929
*/
930
public YearMonth minusMonths(long monthsToSubtract) {
931
return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
932
}
933
934
//-----------------------------------------------------------------------
935
/**
936
* Queries this year-month using the specified query.
937
* <p>
938
* This queries this year-month using the specified query strategy object.
939
* The {@code TemporalQuery} object defines the logic to be used to
940
* obtain the result. Read the documentation of the query to understand
941
* what the result of this method will be.
942
* <p>
943
* The result of this method is obtained by invoking the
944
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
945
* specified query passing {@code this} as the argument.
946
*
947
* @param <R> the type of the result
948
* @param query the query to invoke, not null
949
* @return the query result, null may be returned (defined by the query)
950
* @throws DateTimeException if unable to query (defined by the query)
951
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
952
*/
953
@SuppressWarnings("unchecked")
954
@Override
955
public <R> R query(TemporalQuery<R> query) {
956
if (query == TemporalQueries.chronology()) {
957
return (R) IsoChronology.INSTANCE;
958
} else if (query == TemporalQueries.precision()) {
959
return (R) MONTHS;
960
}
961
return Temporal.super.query(query);
962
}
963
964
/**
965
* Adjusts the specified temporal object to have this year-month.
966
* <p>
967
* This returns a temporal object of the same observable type as the input
968
* with the year and month changed to be the same as this.
969
* <p>
970
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
971
* passing {@link ChronoField#PROLEPTIC_MONTH} as the field.
972
* If the specified temporal object does not use the ISO calendar system then
973
* a {@code DateTimeException} is thrown.
974
* <p>
975
* In most cases, it is clearer to reverse the calling pattern by using
976
* {@link Temporal#with(TemporalAdjuster)}:
977
* <pre>
978
* // these two lines are equivalent, but the second approach is recommended
979
* temporal = thisYearMonth.adjustInto(temporal);
980
* temporal = temporal.with(thisYearMonth);
981
* </pre>
982
* <p>
983
* This instance is immutable and unaffected by this method call.
984
*
985
* @param temporal the target object to be adjusted, not null
986
* @return the adjusted object, not null
987
* @throws DateTimeException if unable to make the adjustment
988
* @throws ArithmeticException if numeric overflow occurs
989
*/
990
@Override
991
public Temporal adjustInto(Temporal temporal) {
992
if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
993
throw new DateTimeException("Adjustment only supported on ISO date-time");
994
}
995
return temporal.with(PROLEPTIC_MONTH, getProlepticMonth());
996
}
997
998
/**
999
* Calculates the amount of time until another year-month in terms of the specified unit.
1000
* <p>
1001
* This calculates the amount of time between two {@code YearMonth}
1002
* objects in terms of a single {@code TemporalUnit}.
1003
* The start and end points are {@code this} and the specified year-month.
1004
* The result will be negative if the end is before the start.
1005
* The {@code Temporal} passed to this method is converted to a
1006
* {@code YearMonth} using {@link #from(TemporalAccessor)}.
1007
* For example, the amount in years between two year-months can be calculated
1008
* using {@code startYearMonth.until(endYearMonth, YEARS)}.
1009
* <p>
1010
* The calculation returns a whole number, representing the number of
1011
* complete units between the two year-months.
1012
* For example, the amount in decades between 2012-06 and 2032-05
1013
* will only be one decade as it is one month short of two decades.
1014
* <p>
1015
* There are two equivalent ways of using this method.
1016
* The first is to invoke this method.
1017
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
1018
* <pre>
1019
* // these two lines are equivalent
1020
* amount = start.until(end, MONTHS);
1021
* amount = MONTHS.between(start, end);
1022
* </pre>
1023
* The choice should be made based on which makes the code more readable.
1024
* <p>
1025
* The calculation is implemented in this method for {@link ChronoUnit}.
1026
* The units {@code MONTHS}, {@code YEARS}, {@code DECADES},
1027
* {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
1028
* Other {@code ChronoUnit} values will throw an exception.
1029
* <p>
1030
* If the unit is not a {@code ChronoUnit}, then the result of this method
1031
* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
1032
* passing {@code this} as the first argument and the converted input temporal
1033
* as the second argument.
1034
* <p>
1035
* This instance is immutable and unaffected by this method call.
1036
*
1037
* @param endExclusive the end date, exclusive, which is converted to a {@code YearMonth}, not null
1038
* @param unit the unit to measure the amount in, not null
1039
* @return the amount of time between this year-month and the end year-month
1040
* @throws DateTimeException if the amount cannot be calculated, or the end
1041
* temporal cannot be converted to a {@code YearMonth}
1042
* @throws UnsupportedTemporalTypeException if the unit is not supported
1043
* @throws ArithmeticException if numeric overflow occurs
1044
*/
1045
@Override
1046
public long until(Temporal endExclusive, TemporalUnit unit) {
1047
YearMonth end = YearMonth.from(endExclusive);
1048
if (unit instanceof ChronoUnit chronoUnit) {
1049
long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow
1050
switch (chronoUnit) {
1051
case MONTHS: return monthsUntil;
1052
case YEARS: return monthsUntil / 12;
1053
case DECADES: return monthsUntil / 120;
1054
case CENTURIES: return monthsUntil / 1200;
1055
case MILLENNIA: return monthsUntil / 12000;
1056
case ERAS: return end.getLong(ERA) - getLong(ERA);
1057
}
1058
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
1059
}
1060
return unit.between(this, end);
1061
}
1062
1063
/**
1064
* Formats this year-month using the specified formatter.
1065
* <p>
1066
* This year-month will be passed to the formatter to produce a string.
1067
*
1068
* @param formatter the formatter to use, not null
1069
* @return the formatted year-month string, not null
1070
* @throws DateTimeException if an error occurs during printing
1071
*/
1072
public String format(DateTimeFormatter formatter) {
1073
Objects.requireNonNull(formatter, "formatter");
1074
return formatter.format(this);
1075
}
1076
1077
//-----------------------------------------------------------------------
1078
/**
1079
* Combines this year-month with a day-of-month to create a {@code LocalDate}.
1080
* <p>
1081
* This returns a {@code LocalDate} formed from this year-month and the specified day-of-month.
1082
* <p>
1083
* The day-of-month value must be valid for the year-month.
1084
* <p>
1085
* This method can be used as part of a chain to produce a date:
1086
* <pre>
1087
* LocalDate date = year.atMonth(month).atDay(day);
1088
* </pre>
1089
*
1090
* @param dayOfMonth the day-of-month to use, from 1 to 31
1091
* @return the date formed from this year-month and the specified day, not null
1092
* @throws DateTimeException if the day is invalid for the year-month
1093
* @see #isValidDay(int)
1094
*/
1095
public LocalDate atDay(int dayOfMonth) {
1096
return LocalDate.of(year, month, dayOfMonth);
1097
}
1098
1099
/**
1100
* Returns a {@code LocalDate} at the end of the month.
1101
* <p>
1102
* This returns a {@code LocalDate} based on this year-month.
1103
* The day-of-month is set to the last valid day of the month, taking
1104
* into account leap years.
1105
* <p>
1106
* This method can be used as part of a chain to produce a date:
1107
* <pre>
1108
* LocalDate date = year.atMonth(month).atEndOfMonth();
1109
* </pre>
1110
*
1111
* @return the last valid date of this year-month, not null
1112
*/
1113
public LocalDate atEndOfMonth() {
1114
return LocalDate.of(year, month, lengthOfMonth());
1115
}
1116
1117
//-----------------------------------------------------------------------
1118
/**
1119
* Compares this year-month to another year-month.
1120
* <p>
1121
* The comparison is based first on the value of the year, then on the value of the month.
1122
* It is "consistent with equals", as defined by {@link Comparable}.
1123
*
1124
* @param other the other year-month to compare to, not null
1125
* @return the comparator value, negative if less, positive if greater
1126
*/
1127
@Override
1128
public int compareTo(YearMonth other) {
1129
int cmp = (year - other.year);
1130
if (cmp == 0) {
1131
cmp = (month - other.month);
1132
}
1133
return cmp;
1134
}
1135
1136
/**
1137
* Checks if this year-month is after the specified year-month.
1138
*
1139
* @param other the other year-month to compare to, not null
1140
* @return true if this is after the specified year-month
1141
*/
1142
public boolean isAfter(YearMonth other) {
1143
return compareTo(other) > 0;
1144
}
1145
1146
/**
1147
* Checks if this year-month is before the specified year-month.
1148
*
1149
* @param other the other year-month to compare to, not null
1150
* @return true if this point is before the specified year-month
1151
*/
1152
public boolean isBefore(YearMonth other) {
1153
return compareTo(other) < 0;
1154
}
1155
1156
//-----------------------------------------------------------------------
1157
/**
1158
* Checks if this year-month is equal to another year-month.
1159
* <p>
1160
* The comparison is based on the time-line position of the year-months.
1161
*
1162
* @param obj the object to check, null returns false
1163
* @return true if this is equal to the other year-month
1164
*/
1165
@Override
1166
public boolean equals(Object obj) {
1167
if (this == obj) {
1168
return true;
1169
}
1170
return (obj instanceof YearMonth other)
1171
&& year == other.year
1172
&& month == other.month;
1173
}
1174
1175
/**
1176
* A hash code for this year-month.
1177
*
1178
* @return a suitable hash code
1179
*/
1180
@Override
1181
public int hashCode() {
1182
return year ^ (month << 27);
1183
}
1184
1185
//-----------------------------------------------------------------------
1186
/**
1187
* Outputs this year-month as a {@code String}, such as {@code 2007-12}.
1188
* <p>
1189
* The output will be in the format {@code uuuu-MM}:
1190
*
1191
* @return a string representation of this year-month, not null
1192
*/
1193
@Override
1194
public String toString() {
1195
int absYear = Math.abs(year);
1196
StringBuilder buf = new StringBuilder(9);
1197
if (absYear < 1000) {
1198
if (year < 0) {
1199
buf.append(year - 10000).deleteCharAt(1);
1200
} else {
1201
buf.append(year + 10000).deleteCharAt(0);
1202
}
1203
} else {
1204
buf.append(year);
1205
}
1206
return buf.append(month < 10 ? "-0" : "-")
1207
.append(month)
1208
.toString();
1209
}
1210
1211
//-----------------------------------------------------------------------
1212
/**
1213
* Writes the object using a
1214
* <a href="{@docRoot}/serialized-form.html#java.time.Ser">dedicated serialized form</a>.
1215
* @serialData
1216
* <pre>
1217
* out.writeByte(12); // identifies a YearMonth
1218
* out.writeInt(year);
1219
* out.writeByte(month);
1220
* </pre>
1221
*
1222
* @return the instance of {@code Ser}, not null
1223
*/
1224
@java.io.Serial
1225
private Object writeReplace() {
1226
return new Ser(Ser.YEAR_MONTH_TYPE, this);
1227
}
1228
1229
/**
1230
* Defend against malicious streams.
1231
*
1232
* @param s the stream to read
1233
* @throws InvalidObjectException always
1234
*/
1235
@java.io.Serial
1236
private void readObject(ObjectInputStream s) throws InvalidObjectException {
1237
throw new InvalidObjectException("Deserialization via serialization delegate");
1238
}
1239
1240
void writeExternal(DataOutput out) throws IOException {
1241
out.writeInt(year);
1242
out.writeByte(month);
1243
}
1244
1245
static YearMonth readExternal(DataInput in) throws IOException {
1246
int year = in.readInt();
1247
byte month = in.readByte();
1248
return YearMonth.of(year, month);
1249
}
1250
1251
}
1252
1253