1
2
3
4 package de.powerstat.validation.values;
5
6
7 import java.util.Objects;
8
9 import de.powerstat.validation.interfaces.IValueObject;
10
11
12
13
14
15
16
17
18
19
20 public final class MonthDay implements Comparable<MonthDay>, IValueObject
21 {
22
23
24
25 private static final String OVERFLOW = "Overflow";
26
27
28
29
30 private static final String UNDERFLOW = "Underflow";
31
32
33
34
35 private static final String DATE_SEP = "-";
36
37
38
39
40
41
42
43
44
45 private final Month month;
46
47
48
49
50 private final Day day;
51
52
53
54
55
56
57
58
59
60
61
62 private MonthDay(final Month month, final Day day)
63 {
64 super();
65 Objects.requireNonNull(month, "month");
66 Objects.requireNonNull(day, "day");
67 switch (month.intValue())
68 {
69 case 1:
70 case 3:
71 case 5:
72 case 7:
73 case 8:
74 case 10:
75 case 12:
76 break;
77
78 case 4:
79 case 6:
80 case 9:
81 case 11:
82 if (day.intValue() > 30)
83 {
84 throw new IndexOutOfBoundsException("Day number out of range for the month (31)!");
85 }
86 break;
87
88 case 2:
89 if (day.intValue() > 29)
90 {
91 throw new IndexOutOfBoundsException("Day number out of range for the month (30-31)!");
92 }
93 break;
94
95 default:
96 throw new IllegalStateException("Illegal month!");
97 }
98 this.month = month;
99 this.day = day;
100 }
101
102
103
104
105
106
107
108
109
110 public static MonthDay of(final Month month, final Day day)
111 {
112
113
114
115
116
117
118
119
120
121
122
123
124
125 return new MonthDay(month, day);
126 }
127
128
129
130
131
132
133
134
135 public static MonthDay of(final String value)
136 {
137 final String[] values = value.split(DATE_SEP);
138 if (values.length != 2)
139 {
140 throw new IllegalArgumentException("value not of required format");
141 }
142 return of(Month.of(values[0]), Day.of(values[1]));
143 }
144
145
146
147
148
149
150
151 public Month monthValue()
152 {
153 return this.month;
154 }
155
156
157
158
159
160
161
162 public Day dayValue()
163 {
164 return this.day;
165 }
166
167
168
169
170
171
172
173 @Override
174 public String stringValue()
175 {
176 return this.month.stringValue() + DATE_SEP + this.day.stringValue();
177 }
178
179
180
181
182
183
184
185
186 @Override
187 public int hashCode()
188 {
189 return Objects.hash(this.month, this.day);
190 }
191
192
193
194
195
196
197
198
199
200 @Override
201 public boolean equals(final Object obj)
202 {
203 if (this == obj)
204 {
205 return true;
206 }
207
208 if (!(obj instanceof MonthDay))
209 {
210 return false;
211 }
212 final MonthDay other = (MonthDay)obj;
213 boolean result = this.month.equals(other.month);
214 if (result)
215 {
216 result = this.day.equals(other.day);
217 }
218 return result;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232 @Override
233 public String toString()
234 {
235 final var builder = new StringBuilder(22);
236 builder.append("MonthDay[month=").append(this.month).append(", day=").append(this.day).append(']');
237 return builder.toString();
238 }
239
240
241
242
243
244
245
246
247
248 @Override
249 public int compareTo(final MonthDay obj)
250 {
251 Objects.requireNonNull(obj, "obj");
252 int result = this.month.compareTo(obj.month);
253 if (result == 0)
254 {
255 result = this.day.compareTo(obj.day);
256 }
257 return result;
258 }
259
260
261
262
263
264
265
266
267
268 public MonthDay add(final Months months)
269 {
270 final long newMonth = Math.toIntExact(Math.addExact(this.month.intValue(), months.longValue()));
271 if (newMonth > 12)
272 {
273
274
275
276 throw new ArithmeticException(MonthDay.OVERFLOW);
277 }
278 return MonthDay.of(Month.of(Math.toIntExact(newMonth)), this.day);
279 }
280
281
282
283
284
285
286
287
288
289 public MonthDay subtract(final Months months)
290 {
291 final long newMonth = Math.toIntExact(Math.subtractExact(this.month.intValue(), months.longValue()));
292 if (newMonth <= 0)
293 {
294
295
296
297 throw new ArithmeticException(MonthDay.UNDERFLOW);
298 }
299 return MonthDay.of(Month.of(Math.toIntExact(newMonth)), this.day);
300 }
301
302
303
304
305
306
307
308
309 public MonthDay incrementMonth()
310 {
311 final int newMonth = Math.incrementExact(this.month.intValue());
312 if (newMonth == 13)
313 {
314
315
316
317 throw new ArithmeticException(MonthDay.OVERFLOW);
318 }
319 return MonthDay.of(Month.of(newMonth), this.day);
320 }
321
322
323
324
325
326
327
328
329 public MonthDay decrementMonth()
330 {
331 final int newMonth = Math.decrementExact(this.month.intValue());
332 if (newMonth == 0)
333 {
334
335
336
337 throw new ArithmeticException(MonthDay.UNDERFLOW);
338 }
339 return MonthDay.of(Month.of(newMonth), this.day);
340 }
341
342
343
344
345
346
347
348 }