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