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/MonthDay.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.DAY_OF_MONTH;
65
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
66
67
import java.io.DataInput;
68
import java.io.DataOutput;
69
import java.io.IOException;
70
import java.io.InvalidObjectException;
71
import java.io.ObjectInputStream;
72
import java.io.Serializable;
73
import java.time.chrono.Chronology;
74
import java.time.chrono.IsoChronology;
75
import java.time.format.DateTimeFormatter;
76
import java.time.format.DateTimeFormatterBuilder;
77
import java.time.format.DateTimeParseException;
78
import java.time.temporal.ChronoField;
79
import java.time.temporal.Temporal;
80
import java.time.temporal.TemporalAccessor;
81
import java.time.temporal.TemporalAdjuster;
82
import java.time.temporal.TemporalField;
83
import java.time.temporal.TemporalQueries;
84
import java.time.temporal.TemporalQuery;
85
import java.time.temporal.UnsupportedTemporalTypeException;
86
import java.time.temporal.ValueRange;
87
import java.util.Objects;
88
89
/**
90
* A month-day in the ISO-8601 calendar system, such as {@code --12-03}.
91
* <p>
92
* {@code MonthDay} is an immutable date-time object that represents the combination
93
* of a month and day-of-month. Any field that can be derived from a month and day,
94
* such as quarter-of-year, can be obtained.
95
* <p>
96
* This class does not store or represent a year, time or time-zone.
97
* For example, the value "December 3rd" can be stored in a {@code MonthDay}.
98
* <p>
99
* Since a {@code MonthDay} does not possess a year, the leap day of
100
* February 29th is considered valid.
101
* <p>
102
* This class implements {@link TemporalAccessor} rather than {@link Temporal}.
103
* This is because it is not possible to define whether February 29th is valid or not
104
* without external information, preventing the implementation of plus/minus.
105
* Related to this, {@code MonthDay} only provides access to query and set the fields
106
* {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH}.
107
* <p>
108
* The ISO-8601 calendar system is the modern civil calendar system used today
109
* in most of the world. It is equivalent to the proleptic Gregorian calendar
110
* system, in which today's rules for leap years are applied for all time.
111
* For most applications written today, the ISO-8601 rules are entirely suitable.
112
* However, any application that makes use of historical dates, and requires them
113
* to be accurate will find the ISO-8601 approach unsuitable.
114
*
115
* <p>
116
* This is a <a href="{@docRoot}/java/lang/doc-files/ValueBased.html">value-based</a>
117
* class; use of identity-sensitive operations (including reference equality
118
* ({@code ==}), identity hash code, or synchronization) on instances of
119
* {@code MonthDay} may have unpredictable results and should be avoided.
120
* The {@code equals} method should be used for comparisons.
121
*
122
* @implSpec
123
* This class is immutable and thread-safe.
124
*
125
* @since 1.8
126
*/
127
public final class MonthDay
128
implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable {
129
130
/**
131
* Serialization version.
132
*/
133
private static final long serialVersionUID = -939150713474957432L;
134
/**
135
* Parser.
136
*/
137
private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
138
.appendLiteral("--")
139
.appendValue(MONTH_OF_YEAR, 2)
140
.appendLiteral('-')
141
.appendValue(DAY_OF_MONTH, 2)
142
.toFormatter();
143
144
/**
145
* The month-of-year, not null.
146
*/
147
private final int month;
148
/**
149
* The day-of-month.
150
*/
151
private final int day;
152
153
//-----------------------------------------------------------------------
154
/**
155
* Obtains the current month-day from the system clock in the default time-zone.
156
* <p>
157
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
158
* time-zone to obtain the current month-day.
159
* <p>
160
* Using this method will prevent the ability to use an alternate clock for testing
161
* because the clock is hard-coded.
162
*
163
* @return the current month-day using the system clock and default time-zone, not null
164
*/
165
public static MonthDay now() {
166
return now(Clock.systemDefaultZone());
167
}
168
169
/**
170
* Obtains the current month-day from the system clock in the specified time-zone.
171
* <p>
172
* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current month-day.
173
* Specifying the time-zone avoids dependence on the default time-zone.
174
* <p>
175
* Using this method will prevent the ability to use an alternate clock for testing
176
* because the clock is hard-coded.
177
*
178
* @param zone the zone ID to use, not null
179
* @return the current month-day using the system clock, not null
180
*/
181
public static MonthDay now(ZoneId zone) {
182
return now(Clock.system(zone));
183
}
184
185
/**
186
* Obtains the current month-day from the specified clock.
187
* <p>
188
* This will query the specified clock to obtain the current month-day.
189
* Using this method allows the use of an alternate clock for testing.
190
* The alternate clock may be introduced using {@link Clock dependency injection}.
191
*
192
* @param clock the clock to use, not null
193
* @return the current month-day, not null
194
*/
195
public static MonthDay now(Clock clock) {
196
final LocalDate now = LocalDate.now(clock); // called once
197
return MonthDay.of(now.getMonth(), now.getDayOfMonth());
198
}
199
200
//-----------------------------------------------------------------------
201
/**
202
* Obtains an instance of {@code MonthDay}.
203
* <p>
204
* The day-of-month must be valid for the month within a leap year.
205
* Hence, for February, day 29 is valid.
206
* <p>
207
* For example, passing in April and day 31 will throw an exception, as
208
* there can never be April 31st in any year. By contrast, passing in
209
* February 29th is permitted, as that month-day can sometimes be valid.
210
*
211
* @param month the month-of-year to represent, not null
212
* @param dayOfMonth the day-of-month to represent, from 1 to 31
213
* @return the month-day, not null
214
* @throws DateTimeException if the value of any field is out of range,
215
* or if the day-of-month is invalid for the month
216
*/
217
public static MonthDay of(Month month, int dayOfMonth) {
218
Objects.requireNonNull(month, "month");
219
DAY_OF_MONTH.checkValidValue(dayOfMonth);
220
if (dayOfMonth > month.maxLength()) {
221
throw new DateTimeException("Illegal value for DayOfMonth field, value " + dayOfMonth +
222
" is not valid for month " + month.name());
223
}
224
return new MonthDay(month.getValue(), dayOfMonth);
225
}
226
227
/**
228
* Obtains an instance of {@code MonthDay}.
229
* <p>
230
* The day-of-month must be valid for the month within a leap year.
231
* Hence, for month 2 (February), day 29 is valid.
232
* <p>
233
* For example, passing in month 4 (April) and day 31 will throw an exception, as
234
* there can never be April 31st in any year. By contrast, passing in
235
* February 29th is permitted, as that month-day can sometimes be valid.
236
*
237
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
238
* @param dayOfMonth the day-of-month to represent, from 1 to 31
239
* @return the month-day, not null
240
* @throws DateTimeException if the value of any field is out of range,
241
* or if the day-of-month is invalid for the month
242
*/
243
public static MonthDay of(int month, int dayOfMonth) {
244
return of(Month.of(month), dayOfMonth);
245
}
246
247
//-----------------------------------------------------------------------
248
/**
249
* Obtains an instance of {@code MonthDay} from a temporal object.
250
* <p>
251
* This obtains a month-day based on the specified temporal.
252
* A {@code TemporalAccessor} represents an arbitrary set of date and time information,
253
* which this factory converts to an instance of {@code MonthDay}.
254
* <p>
255
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
256
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
257
* The extraction is only permitted if the temporal object has an ISO
258
* chronology, or can be converted to a {@code LocalDate}.
259
* <p>
260
* This method matches the signature of the functional interface {@link TemporalQuery}
261
* allowing it to be used as a query via method reference, {@code MonthDay::from}.
262
*
263
* @param temporal the temporal object to convert, not null
264
* @return the month-day, not null
265
* @throws DateTimeException if unable to convert to a {@code MonthDay}
266
*/
267
public static MonthDay from(TemporalAccessor temporal) {
268
if (temporal instanceof MonthDay) {
269
return (MonthDay) temporal;
270
}
271
try {
272
if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
273
temporal = LocalDate.from(temporal);
274
}
275
return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
276
} catch (DateTimeException ex) {
277
throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " +
278
temporal + " of type " + temporal.getClass().getName(), ex);
279
}
280
}
281
282
//-----------------------------------------------------------------------
283
/**
284
* Obtains an instance of {@code MonthDay} from a text string such as {@code --12-03}.
285
* <p>
286
* The string must represent a valid month-day.
287
* The format is {@code --MM-dd}.
288
*
289
* @param text the text to parse such as "--12-03", not null
290
* @return the parsed month-day, not null
291
* @throws DateTimeParseException if the text cannot be parsed
292
*/
293
public static MonthDay parse(CharSequence text) {
294
return parse(text, PARSER);
295
}
296
297
/**
298
* Obtains an instance of {@code MonthDay} from a text string using a specific formatter.
299
* <p>
300
* The text is parsed using the formatter, returning a month-day.
301
*
302
* @param text the text to parse, not null
303
* @param formatter the formatter to use, not null
304
* @return the parsed month-day, not null
305
* @throws DateTimeParseException if the text cannot be parsed
306
*/
307
public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) {
308
Objects.requireNonNull(formatter, "formatter");
309
return formatter.parse(text, MonthDay::from);
310
}
311
312
//-----------------------------------------------------------------------
313
/**
314
* Constructor, previously validated.
315
*
316
* @param month the month-of-year to represent, validated from 1 to 12
317
* @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31
318
*/
319
private MonthDay(int month, int dayOfMonth) {
320
this.month = month;
321
this.day = dayOfMonth;
322
}
323
324
//-----------------------------------------------------------------------
325
/**
326
* Checks if the specified field is supported.
327
* <p>
328
* This checks if this month-day can be queried for the specified field.
329
* If false, then calling the {@link #range(TemporalField) range} and
330
* {@link #get(TemporalField) get} methods will throw an exception.
331
* <p>
332
* If the field is a {@link ChronoField} then the query is implemented here.
333
* The supported fields are:
334
* <ul>
335
* <li>{@code MONTH_OF_YEAR}
336
* <li>{@code YEAR}
337
* </ul>
338
* All other {@code ChronoField} instances will return false.
339
* <p>
340
* If the field is not a {@code ChronoField}, then the result of this method
341
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
342
* passing {@code this} as the argument.
343
* Whether the field is supported is determined by the field.
344
*
345
* @param field the field to check, null returns false
346
* @return true if the field is supported on this month-day, false if not
347
*/
348
@Override
349
public boolean isSupported(TemporalField field) {
350
if (field instanceof ChronoField) {
351
return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
352
}
353
return field != null && field.isSupportedBy(this);
354
}
355
356
/**
357
* Gets the range of valid values for the specified field.
358
* <p>
359
* The range object expresses the minimum and maximum valid values for a field.
360
* This month-day is used to enhance the accuracy of the returned range.
361
* If it is not possible to return the range, because the field is not supported
362
* or for some other reason, an exception is thrown.
363
* <p>
364
* If the field is a {@link ChronoField} then the query is implemented here.
365
* The {@link #isSupported(TemporalField) supported fields} will return
366
* appropriate range instances.
367
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
368
* <p>
369
* If the field is not a {@code ChronoField}, then the result of this method
370
* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
371
* passing {@code this} as the argument.
372
* Whether the range can be obtained is determined by the field.
373
*
374
* @param field the field to query the range for, not null
375
* @return the range of valid values for the field, not null
376
* @throws DateTimeException if the range for the field cannot be obtained
377
* @throws UnsupportedTemporalTypeException if the field is not supported
378
*/
379
@Override
380
public ValueRange range(TemporalField field) {
381
if (field == MONTH_OF_YEAR) {
382
return field.range();
383
} else if (field == DAY_OF_MONTH) {
384
return ValueRange.of(1, getMonth().minLength(), getMonth().maxLength());
385
}
386
return TemporalAccessor.super.range(field);
387
}
388
389
/**
390
* Gets the value of the specified field from this month-day as an {@code int}.
391
* <p>
392
* This queries this month-day for the value of the specified field.
393
* The returned value will always be within the valid range of values for the field.
394
* If it is not possible to return the value, because the field is not supported
395
* or for some other reason, an exception is thrown.
396
* <p>
397
* If the field is a {@link ChronoField} then the query is implemented here.
398
* The {@link #isSupported(TemporalField) supported fields} will return valid
399
* values based on this month-day.
400
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
401
* <p>
402
* If the field is not a {@code ChronoField}, then the result of this method
403
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
404
* passing {@code this} as the argument. Whether the value can be obtained,
405
* and what the value represents, is determined by the field.
406
*
407
* @param field the field to get, not null
408
* @return the value for the field
409
* @throws DateTimeException if a value for the field cannot be obtained or
410
* the value is outside the range of valid values for the field
411
* @throws UnsupportedTemporalTypeException if the field is not supported or
412
* the range of values exceeds an {@code int}
413
* @throws ArithmeticException if numeric overflow occurs
414
*/
415
@Override // override for Javadoc
416
public int get(TemporalField field) {
417
return range(field).checkValidIntValue(getLong(field), field);
418
}
419
420
/**
421
* Gets the value of the specified field from this month-day as a {@code long}.
422
* <p>
423
* This queries this month-day for the value of the specified field.
424
* If it is not possible to return the value, because the field is not supported
425
* or for some other reason, an exception is thrown.
426
* <p>
427
* If the field is a {@link ChronoField} then the query is implemented here.
428
* The {@link #isSupported(TemporalField) supported fields} will return valid
429
* values based on this month-day.
430
* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
431
* <p>
432
* If the field is not a {@code ChronoField}, then the result of this method
433
* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
434
* passing {@code this} as the argument. Whether the value can be obtained,
435
* and what the value represents, is determined by the field.
436
*
437
* @param field the field to get, not null
438
* @return the value for the field
439
* @throws DateTimeException if a value for the field cannot be obtained
440
* @throws UnsupportedTemporalTypeException if the field is not supported
441
* @throws ArithmeticException if numeric overflow occurs
442
*/
443
@Override
444
public long getLong(TemporalField field) {
445
if (field instanceof ChronoField) {
446
switch ((ChronoField) field) {
447
// alignedDOW and alignedWOM not supported because they cannot be set in with()
448
case DAY_OF_MONTH: return day;
449
case MONTH_OF_YEAR: return month;
450
}
451
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
452
}
453
return field.getFrom(this);
454
}
455
456
//-----------------------------------------------------------------------
457
/**
458
* Gets the month-of-year field from 1 to 12.
459
* <p>
460
* This method returns the month as an {@code int} from 1 to 12.
461
* Application code is frequently clearer if the enum {@link Month}
462
* is used by calling {@link #getMonth()}.
463
*
464
* @return the month-of-year, from 1 to 12
465
* @see #getMonth()
466
*/
467
public int getMonthValue() {
468
return month;
469
}
470
471
/**
472
* Gets the month-of-year field using the {@code Month} enum.
473
* <p>
474
* This method returns the enum {@link Month} for the month.
475
* This avoids confusion as to what {@code int} values mean.
476
* If you need access to the primitive {@code int} value then the enum
477
* provides the {@link Month#getValue() int value}.
478
*
479
* @return the month-of-year, not null
480
* @see #getMonthValue()
481
*/
482
public Month getMonth() {
483
return Month.of(month);
484
}
485
486
/**
487
* Gets the day-of-month field.
488
* <p>
489
* This method returns the primitive {@code int} value for the day-of-month.
490
*
491
* @return the day-of-month, from 1 to 31
492
*/
493
public int getDayOfMonth() {
494
return day;
495
}
496
497
//-----------------------------------------------------------------------
498
/**
499
* Checks if the year is valid for this month-day.
500
* <p>
501
* This method checks whether this month and day and the input year form
502
* a valid date. This can only return false for February 29th.
503
*
504
* @param year the year to validate
505
* @return true if the year is valid for this month-day
506
* @see Year#isValidMonthDay(MonthDay)
507
*/
508
public boolean isValidYear(int year) {
509
return (day == 29 && month == 2 && Year.isLeap(year) == false) == false;
510
}
511
512
//-----------------------------------------------------------------------
513
/**
514
* Returns a copy of this {@code MonthDay} with the month-of-year altered.
515
* <p>
516
* This returns a month-day with the specified month.
517
* If the day-of-month is invalid for the specified month, the day will
518
* be adjusted to the last valid day-of-month.
519
* <p>
520
* This instance is immutable and unaffected by this method call.
521
*
522
* @param month the month-of-year to set in the returned month-day, from 1 (January) to 12 (December)
523
* @return a {@code MonthDay} based on this month-day with the requested month, not null
524
* @throws DateTimeException if the month-of-year value is invalid
525
*/
526
public MonthDay withMonth(int month) {
527
return with(Month.of(month));
528
}
529
530
/**
531
* Returns a copy of this {@code MonthDay} with the month-of-year altered.
532
* <p>
533
* This returns a month-day with the specified month.
534
* If the day-of-month is invalid for the specified month, the day will
535
* be adjusted to the last valid day-of-month.
536
* <p>
537
* This instance is immutable and unaffected by this method call.
538
*
539
* @param month the month-of-year to set in the returned month-day, not null
540
* @return a {@code MonthDay} based on this month-day with the requested month, not null
541
*/
542
public MonthDay with(Month month) {
543
Objects.requireNonNull(month, "month");
544
if (month.getValue() == this.month) {
545
return this;
546
}
547
int day = Math.min(this.day, month.maxLength());
548
return new MonthDay(month.getValue(), day);
549
}
550
551
/**
552
* Returns a copy of this {@code MonthDay} with the day-of-month altered.
553
* <p>
554
* This returns a month-day with the specified day-of-month.
555
* If the day-of-month is invalid for the month, an exception is thrown.
556
* <p>
557
* This instance is immutable and unaffected by this method call.
558
*
559
* @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31
560
* @return a {@code MonthDay} based on this month-day with the requested day, not null
561
* @throws DateTimeException if the day-of-month value is invalid,
562
* or if the day-of-month is invalid for the month
563
*/
564
public MonthDay withDayOfMonth(int dayOfMonth) {
565
if (dayOfMonth == this.day) {
566
return this;
567
}
568
return of(month, dayOfMonth);
569
}
570
571
//-----------------------------------------------------------------------
572
/**
573
* Queries this month-day using the specified query.
574
* <p>
575
* This queries this month-day using the specified query strategy object.
576
* The {@code TemporalQuery} object defines the logic to be used to
577
* obtain the result. Read the documentation of the query to understand
578
* what the result of this method will be.
579
* <p>
580
* The result of this method is obtained by invoking the
581
* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
582
* specified query passing {@code this} as the argument.
583
*
584
* @param <R> the type of the result
585
* @param query the query to invoke, not null
586
* @return the query result, null may be returned (defined by the query)
587
* @throws DateTimeException if unable to query (defined by the query)
588
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
589
*/
590
@SuppressWarnings("unchecked")
591
@Override
592
public <R> R query(TemporalQuery<R> query) {
593
if (query == TemporalQueries.chronology()) {
594
return (R) IsoChronology.INSTANCE;
595
}
596
return TemporalAccessor.super.query(query);
597
}
598
599
/**
600
* Adjusts the specified temporal object to have this month-day.
601
* <p>
602
* This returns a temporal object of the same observable type as the input
603
* with the month and day-of-month changed to be the same as this.
604
* <p>
605
* The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
606
* twice, passing {@link ChronoField#MONTH_OF_YEAR} and
607
* {@link ChronoField#DAY_OF_MONTH} as the fields.
608
* If the specified temporal object does not use the ISO calendar system then
609
* a {@code DateTimeException} is thrown.
610
* <p>
611
* In most cases, it is clearer to reverse the calling pattern by using
612
* {@link Temporal#with(TemporalAdjuster)}:
613
* <pre>
614
* // these two lines are equivalent, but the second approach is recommended
615
* temporal = thisMonthDay.adjustInto(temporal);
616
* temporal = temporal.with(thisMonthDay);
617
* </pre>
618
* <p>
619
* This instance is immutable and unaffected by this method call.
620
*
621
* @param temporal the target object to be adjusted, not null
622
* @return the adjusted object, not null
623
* @throws DateTimeException if unable to make the adjustment
624
* @throws ArithmeticException if numeric overflow occurs
625
*/
626
@Override
627
public Temporal adjustInto(Temporal temporal) {
628
if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
629
throw new DateTimeException("Adjustment only supported on ISO date-time");
630
}
631
temporal = temporal.with(MONTH_OF_YEAR, month);
632
return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
633
}
634
635
/**
636
* Formats this month-day using the specified formatter.
637
* <p>
638
* This month-day will be passed to the formatter to produce a string.
639
*
640
* @param formatter the formatter to use, not null
641
* @return the formatted month-day string, not null
642
* @throws DateTimeException if an error occurs during printing
643
*/
644
public String format(DateTimeFormatter formatter) {
645
Objects.requireNonNull(formatter, "formatter");
646
return formatter.format(this);
647
}
648
649
//-----------------------------------------------------------------------
650
/**
651
* Combines this month-day with a year to create a {@code LocalDate}.
652
* <p>
653
* This returns a {@code LocalDate} formed from this month-day and the specified year.
654
* <p>
655
* A month-day of February 29th will be adjusted to February 28th in the resulting
656
* date if the year is not a leap year.
657
* <p>
658
* This instance is immutable and unaffected by this method call.
659
*
660
* @param year the year to use, from MIN_YEAR to MAX_YEAR
661
* @return the local date formed from this month-day and the specified year, not null
662
* @throws DateTimeException if the year is outside the valid range of years
663
*/
664
public LocalDate atYear(int year) {
665
return LocalDate.of(year, month, isValidYear(year) ? day : 28);
666
}
667
668
//-----------------------------------------------------------------------
669
/**
670
* Compares this month-day to another month-day.
671
* <p>
672
* The comparison is based first on value of the month, then on the value of the day.
673
* It is "consistent with equals", as defined by {@link Comparable}.
674
*
675
* @param other the other month-day to compare to, not null
676
* @return the comparator value, negative if less, positive if greater
677
*/
678
@Override
679
public int compareTo(MonthDay other) {
680
int cmp = (month - other.month);
681
if (cmp == 0) {
682
cmp = (day - other.day);
683
}
684
return cmp;
685
}
686
687
/**
688
* Checks if this month-day is after the specified month-day.
689
*
690
* @param other the other month-day to compare to, not null
691
* @return true if this is after the specified month-day
692
*/
693
public boolean isAfter(MonthDay other) {
694
return compareTo(other) > 0;
695
}
696
697
/**
698
* Checks if this month-day is before the specified month-day.
699
*
700
* @param other the other month-day to compare to, not null
701
* @return true if this point is before the specified month-day
702
*/
703
public boolean isBefore(MonthDay other) {
704
return compareTo(other) < 0;
705
}
706
707
//-----------------------------------------------------------------------
708
/**
709
* Checks if this month-day is equal to another month-day.
710
* <p>
711
* The comparison is based on the time-line position of the month-day within a year.
712
*
713
* @param obj the object to check, null returns false
714
* @return true if this is equal to the other month-day
715
*/
716
@Override
717
public boolean equals(Object obj) {
718
if (this == obj) {
719
return true;
720
}
721
if (obj instanceof MonthDay) {
722
MonthDay other = (MonthDay) obj;
723
return month == other.month && day == other.day;
724
}
725
return false;
726
}
727
728
/**
729
* A hash code for this month-day.
730
*
731
* @return a suitable hash code
732
*/
733
@Override
734
public int hashCode() {
735
return (month << 6) + day;
736
}
737
738
//-----------------------------------------------------------------------
739
/**
740
* Outputs this month-day as a {@code String}, such as {@code --12-03}.
741
* <p>
742
* The output will be in the format {@code --MM-dd}:
743
*
744
* @return a string representation of this month-day, not null
745
*/
746
@Override
747
public String toString() {
748
return new StringBuilder(10).append("--")
749
.append(month < 10 ? "0" : "").append(month)
750
.append(day < 10 ? "-0" : "-").append(day)
751
.toString();
752
}
753
754
//-----------------------------------------------------------------------
755
/**
756
* Writes the object using a
757
* <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
758
* @serialData
759
* <pre>
760
* out.writeByte(13); // identifies a MonthDay
761
* out.writeByte(month);
762
* out.writeByte(day);
763
* </pre>
764
*
765
* @return the instance of {@code Ser}, not null
766
*/
767
private Object writeReplace() {
768
return new Ser(Ser.MONTH_DAY_TYPE, this);
769
}
770
771
/**
772
* Defend against malicious streams.
773
*
774
* @param s the stream to read
775
* @throws InvalidObjectException always
776
*/
777
private void readObject(ObjectInputStream s) throws InvalidObjectException {
778
throw new InvalidObjectException("Deserialization via serialization delegate");
779
}
780
781
void writeExternal(DataOutput out) throws IOException {
782
out.writeByte(month);
783
out.writeByte(day);
784
}
785
786
static MonthDay readExternal(DataInput in) throws IOException {
787
byte month = in.readByte();
788
byte day = in.readByte();
789
return MonthDay.of(month, day);
790
}
791
792
}
793
794