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