0
# Year and YearMonth Operations
1
2
Functionality for working with Year and YearMonth temporal objects including arithmetic operations, period calculations, and temporal object creation through operator overloading.
3
4
## Capabilities
5
6
### Year Operations
7
8
Year represents a year in the ISO-8601 calendar system.
9
10
```groovy { .api }
11
/**
12
* Returns a Year that is the specified number of years after this year.
13
*/
14
Year plus(Year self, long years)
15
16
/**
17
* Returns a Year that is the specified number of years before this year.
18
*/
19
Year minus(Year self, long years)
20
21
/**
22
* Returns the next Year after this year.
23
*/
24
Year next(Year self)
25
26
/**
27
* Returns the previous Year before this year.
28
*/
29
Year previous(Year self)
30
31
/**
32
* Returns a Period between the first day of this year and the first day of the provided Year.
33
*/
34
Period rightShift(Year self, Year year)
35
36
/**
37
* Returns a YearMonth of this year and the provided Month.
38
*/
39
YearMonth leftShift(Year self, Month month)
40
41
/**
42
* Returns a LocalDate of this year on the given MonthDay.
43
*/
44
LocalDate leftShift(Year self, MonthDay monthDay)
45
46
/**
47
* Returns the era of the year (0 for BC, 1 for AD).
48
*/
49
int getEra(Year self)
50
51
/**
52
* Returns the year value of the era.
53
*/
54
int getYearOfEra(Year self)
55
```
56
57
**Usage Examples:**
58
59
```groovy
60
import java.time.*
61
62
def year2024 = Year.of(2024)
63
64
// Arithmetic operations
65
def nextYear = year2024 + 1 // Year 2025
66
def fiveYearsAgo = year2024 - 5 // Year 2019
67
def decade = year2024 + 10 // Year 2034
68
69
// Navigation
70
def following = year2024.next() // Year 2025
71
def preceding = year2024.previous() // Year 2023
72
73
// Period calculation
74
def period = year2024 >> Year.of(2030) // Period of 6 years
75
76
// Creating other temporal objects
77
def january2024 = year2024 << Month.JANUARY // YearMonth: 2024-01
78
def christmas = year2024 << MonthDay.of(12, 25) // LocalDate: 2024-12-25
79
def newYear = year2024 << MonthDay.of(1, 1) // LocalDate: 2024-01-01
80
81
// Era information
82
def era = year2024.era // 1 (AD/CE)
83
def yearOfEra = year2024.yearOfEra // 2024
84
85
// Practical examples
86
def isLeapYear = year2024.isLeap() // true (2024 is a leap year)
87
def daysInYear = year2024.length() // 366 (leap year)
88
89
// Working with leap years
90
def leapYears = (2020..2030).findAll { Year.of(it).isLeap() }
91
println "Leap years between 2020-2030: ${leapYears}" // [2020, 2024, 2028]
92
```
93
94
### YearMonth Operations
95
96
YearMonth represents a year-month combination in the ISO-8601 calendar system.
97
98
```groovy { .api }
99
/**
100
* Returns a YearMonth that is the specified number of months after this year-month.
101
*/
102
YearMonth plus(YearMonth self, long months)
103
104
/**
105
* Returns a YearMonth that is the specified number of months before this year-month.
106
*/
107
YearMonth minus(YearMonth self, long months)
108
109
/**
110
* Returns the next YearMonth after this year-month.
111
*/
112
YearMonth next(YearMonth self)
113
114
/**
115
* Returns the previous YearMonth before this year-month.
116
*/
117
YearMonth previous(YearMonth self)
118
119
/**
120
* Returns a LocalDate of this year-month and the given day of the month.
121
*/
122
LocalDate leftShift(YearMonth self, int dayOfMonth)
123
124
/**
125
* Returns a Period between the first day of this year-month and the given YearMonth.
126
*/
127
Period rightShift(YearMonth self, YearMonth other)
128
```
129
130
**Usage Examples:**
131
132
```groovy
133
import java.time.*
134
135
def dec2024 = YearMonth.of(2024, 12)
136
137
// Arithmetic operations
138
def nextMonth = dec2024 + 1 // YearMonth: 2025-01
139
def sixMonthsAgo = dec2024 - 6 // YearMonth: 2024-06
140
def twoYearsLater = dec2024 + 24 // YearMonth: 2026-12
141
142
// Navigation
143
def following = dec2024.next() // YearMonth: 2025-01
144
def preceding = dec2024.previous() // YearMonth: 2024-11
145
146
// Creating LocalDate with specific day
147
def christmas = dec2024 << 25 // LocalDate: 2024-12-25
148
def newYearsEve = dec2024 << 31 // LocalDate: 2024-12-31
149
def firstOfMonth = dec2024 << 1 // LocalDate: 2024-12-01
150
151
// Period calculation
152
def period = dec2024 >> YearMonth.of(2025, 6) // Period of 6 months
153
154
// Practical examples
155
def monthLength = dec2024.lengthOfMonth() // 31 days
156
def yearLength = dec2024.lengthOfYear() // 366 days (2024 is leap year)
157
158
// Generate date ranges for the month
159
def allDaysInMonth = (1..monthLength).collect { dec2024 << it }
160
println "All days in December 2024: ${allDaysInMonth.size()} days"
161
162
// Financial quarters
163
def getQuarter = { YearMonth yearMonth ->
164
def month = yearMonth.monthValue
165
return Math.ceil(month / 3.0) as int
166
}
167
168
def quarter = getQuarter(dec2024) // 4 (Q4)
169
println "December 2024 is in Q${quarter}"
170
171
// Month-end processing
172
def isMonthEnd = { LocalDate date ->
173
def yearMonth = YearMonth.from(date)
174
return date.dayOfMonth == yearMonth.lengthOfMonth()
175
}
176
177
def endOfDec = dec2024 << 31
178
println "Is ${endOfDec} month-end? ${isMonthEnd(endOfDec)}" // true
179
```
180
181
### MonthDay Operations
182
183
Enhanced functionality for MonthDay temporal objects.
184
185
```groovy { .api }
186
/**
187
* Returns a LocalDate of this month-day and the provided year.
188
*/
189
LocalDate leftShift(MonthDay self, int year)
190
191
/**
192
* Returns a LocalDate of this month-day and the provided Year.
193
*/
194
LocalDate leftShift(MonthDay self, Year year)
195
```
196
197
**Usage Examples:**
198
199
```groovy
200
import java.time.*
201
202
def christmas = MonthDay.of(12, 25)
203
def leapDay = MonthDay.of(2, 29)
204
205
// Creating LocalDate for specific years
206
def christmas2024 = christmas << 2024 // LocalDate: 2024-12-25
207
def christmas2025 = christmas << Year.of(2025) // LocalDate: 2025-12-25
208
209
// Working with leap day
210
def leapDay2024 = leapDay << Year.of(2024) // LocalDate: 2024-02-29
211
// Note: leapDay << 2023 would throw an exception (2023 is not a leap year)
212
213
// Holiday calculations
214
def holidays = [
215
'New Year': MonthDay.of(1, 1),
216
'Valentine\'s Day': MonthDay.of(2, 14),
217
'Christmas': MonthDay.of(12, 25)
218
]
219
220
def year = Year.of(2024)
221
holidays.each { name, monthDay ->
222
def date = monthDay << year
223
println "${name} in ${year.value}: ${date} (${date.dayOfWeek})"
224
}
225
226
// Anniversary tracking
227
def anniversary = MonthDay.of(6, 15)
228
def thisYear = anniversary << Year.now()
229
def nextYear = anniversary << Year.now().plusYears(1)
230
231
println "This year's anniversary: ${thisYear}"
232
println "Next year's anniversary: ${nextYear}"
233
234
// Seasonal events
235
def seasons = [
236
'Spring Equinox': MonthDay.of(3, 20),
237
'Summer Solstice': MonthDay.of(6, 21),
238
'Fall Equinox': MonthDay.of(9, 22),
239
'Winter Solstice': MonthDay.of(12, 21)
240
]
241
242
def currentYear = Year.now()
243
seasons.each { event, monthDay ->
244
def date = monthDay << currentYear
245
def daysUntil = LocalDate.now().until(date, ChronoUnit.DAYS)
246
println "${event}: ${date} (${daysUntil} days away)"
247
}
248
```
249
250
### Integration with Other Temporal Types
251
252
How Year and YearMonth operations integrate with the broader datetime system.
253
254
**Usage Examples:**
255
256
```groovy
257
import java.time.*
258
import java.time.temporal.ChronoUnit
259
260
// Financial year calculations
261
def calculateFiscalYear = { LocalDate date ->
262
// Assuming fiscal year starts in April
263
def year = date.year
264
def fiscalYear = (date.monthValue >= 4) ? year : year - 1
265
return Year.of(fiscalYear)
266
}
267
268
def today = LocalDate.now()
269
def fiscalYear = calculateFiscalYear(today)
270
def fiscalStart = fiscalYear << MonthDay.of(4, 1)
271
def fiscalEnd = (fiscalYear + 1) << MonthDay.of(3, 31)
272
273
println "Current fiscal year: ${fiscalYear.value}"
274
println "Fiscal year period: ${fiscalStart} to ${fiscalEnd}"
275
276
// Age calculations
277
def calculateAge = { LocalDate birthDate, LocalDate asOfDate ->
278
def birthYear = Year.from(birthDate)
279
def currentYear = Year.from(asOfDate)
280
def yearsDiff = currentYear.value - birthYear.value
281
282
// Adjust if birthday hasn't occurred this year
283
def birthMonthDay = MonthDay.from(birthDate)
284
def currentMonthDay = MonthDay.from(asOfDate)
285
286
if (currentMonthDay.isBefore(birthMonthDay)) {
287
yearsDiff--
288
}
289
290
return yearsDiff
291
}
292
293
def birthDate = LocalDate.of(1990, 6, 15)
294
def age = calculateAge(birthDate, LocalDate.now())
295
println "Age: ${age} years"
296
297
// Project timeline management
298
def projectStart = YearMonth.of(2024, 3)
299
def projectDuration = 18 // months
300
301
def milestones = [:]
302
(0..projectDuration).step(3) { monthOffset ->
303
def milestone = projectStart + monthOffset
304
def quarter = "Q${Math.ceil(milestone.monthValue / 3.0) as int}"
305
milestones["${milestone.year} ${quarter}"] = milestone
306
}
307
308
println "Project milestones:"
309
milestones.each { quarter, yearMonth ->
310
println "${quarter}: ${yearMonth}"
311
}
312
313
// Seasonal business analysis
314
def analyzeSeason = { YearMonth yearMonth ->
315
def month = yearMonth.month
316
switch (month) {
317
case [Month.DECEMBER, Month.JANUARY, Month.FEBRUARY]:
318
return [season: 'Winter', category: 'Holiday/Indoor']
319
case [Month.MARCH, Month.APRIL, Month.MAY]:
320
return [season: 'Spring', category: 'Renewal/Growth']
321
case [Month.JUNE, Month.JULY, Month.AUGUST]:
322
return [season: 'Summer', category: 'Vacation/Outdoor']
323
case [Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER]:
324
return [season: 'Fall', category: 'Back-to-School/Harvest']
325
}
326
}
327
328
def currentMonth = YearMonth.now()
329
def analysis = analyzeSeason(currentMonth)
330
println "Current month ${currentMonth}: ${analysis.season} (${analysis.category})"
331
332
// Lease and contract management
333
def calculateLeaseEnd = { LocalDate startDate, int durationMonths ->
334
def startYearMonth = YearMonth.from(startDate)
335
def endYearMonth = startYearMonth + durationMonths
336
// Use last day of the end month
337
return endYearMonth << endYearMonth.lengthOfMonth()
338
}
339
340
def leaseStart = LocalDate.of(2024, 1, 15)
341
def leaseEnd = calculateLeaseEnd(leaseStart, 12) // 12-month lease
342
println "Lease period: ${leaseStart} to ${leaseEnd}"
343
344
// Birthday and anniversary tracking
345
def findNextOccurrence = { MonthDay event, LocalDate fromDate ->
346
def thisYear = event << Year.from(fromDate)
347
def nextYear = event << Year.from(fromDate).plusYears(1)
348
349
return thisYear.isAfter(fromDate) ? thisYear : nextYear
350
}
351
352
def birthday = MonthDay.of(8, 22)
353
def nextBirthday = findNextOccurrence(birthday, LocalDate.now())
354
def daysUntil = ChronoUnit.DAYS.between(LocalDate.now(), nextBirthday)
355
356
println "Next birthday: ${nextBirthday} (${daysUntil} days away)"
357
```