0
# Time and Date Operations
1
2
Time arithmetic, date manipulation, and duration calculations through category-based extensions to Java's Date and temporal classes. These utilities provide intuitive and powerful date/time operations with natural language syntax.
3
4
## Capabilities
5
6
### Time Category
7
8
Category class that adds time arithmetic methods to Date and Number classes.
9
10
```java { .api }
11
class TimeCategory {
12
/**
13
* Adds a duration to a date.
14
*/
15
static Date plus(Date date, BaseDuration duration);
16
17
/**
18
* Subtracts a duration from a date.
19
*/
20
static Date minus(Date date, BaseDuration duration);
21
22
/**
23
* Calculates the duration between two dates.
24
*/
25
static BaseDuration minus(Date lhs, Date rhs);
26
27
/**
28
* Creates a duration from a number of days.
29
*/
30
static DatumDependentDuration getDays(Number self);
31
32
/**
33
* Creates a duration from a number of hours.
34
*/
35
static BaseDuration getHours(Number self);
36
37
/**
38
* Creates a duration from a number of minutes.
39
*/
40
static BaseDuration getMinutes(Number self);
41
42
/**
43
* Creates a duration from a number of seconds.
44
*/
45
static BaseDuration getSeconds(Number self);
46
47
/**
48
* Creates a duration from a number of milliseconds.
49
*/
50
static BaseDuration getMilliseconds(Number self);
51
52
/**
53
* Creates a duration from a number of weeks.
54
*/
55
static DatumDependentDuration getWeeks(Number self);
56
57
/**
58
* Creates a duration from a number of months.
59
*/
60
static DatumDependentDuration getMonths(Number self);
61
62
/**
63
* Creates a duration from a number of years.
64
*/
65
static DatumDependentDuration getYears(Number self);
66
67
/**
68
* Multiplies a duration by a number.
69
*/
70
static BaseDuration multiply(BaseDuration duration, Number factor);
71
72
/**
73
* Divides a duration by a number.
74
*/
75
static BaseDuration div(BaseDuration duration, Number divisor);
76
77
/**
78
* Negates a duration.
79
*/
80
static BaseDuration negative(BaseDuration duration);
81
82
/**
83
* Gets the absolute value of a duration.
84
*/
85
static BaseDuration abs(BaseDuration duration);
86
}
87
```
88
89
### Duration Base Classes
90
91
Abstract base classes for representing time durations.
92
93
```java { .api }
94
abstract class BaseDuration implements Comparable<BaseDuration> {
95
/**
96
* Gets the from date for this duration.
97
*/
98
Date getFrom();
99
100
/**
101
* Gets the to date for this duration.
102
*/
103
Date getTo();
104
105
/**
106
* Gets the duration in milliseconds.
107
*/
108
long toMilliseconds();
109
110
/**
111
* Converts to a string representation.
112
*/
113
String toString();
114
115
/**
116
* Compares this duration with another.
117
*/
118
int compareTo(BaseDuration other);
119
120
/**
121
* Adds this duration to a date.
122
*/
123
Date plus(Date date);
124
125
/**
126
* Subtracts this duration from a date.
127
*/
128
Date minus(Date date);
129
130
/**
131
* Adds another duration to this one.
132
*/
133
BaseDuration plus(BaseDuration other);
134
135
/**
136
* Subtracts another duration from this one.
137
*/
138
BaseDuration minus(BaseDuration other);
139
140
/**
141
* Multiplies this duration by a factor.
142
*/
143
BaseDuration multiply(Number factor);
144
145
/**
146
* Divides this duration by a divisor.
147
*/
148
BaseDuration div(Number divisor);
149
150
/**
151
* Gets the negative of this duration.
152
*/
153
BaseDuration negative();
154
155
/**
156
* Gets the absolute value of this duration.
157
*/
158
BaseDuration abs();
159
}
160
```
161
162
### Time Duration
163
164
Represents a fixed duration of time (hours, minutes, seconds, milliseconds).
165
166
```java { .api }
167
class TimeDuration extends BaseDuration {
168
/**
169
* Creates a TimeDuration with the specified components.
170
*/
171
TimeDuration(int days, int hours, int minutes, int seconds, int millis);
172
173
/**
174
* Creates a TimeDuration from milliseconds.
175
*/
176
TimeDuration(long millis);
177
178
/**
179
* Gets the number of days.
180
*/
181
int getDays();
182
183
/**
184
* Gets the number of hours (0-23).
185
*/
186
int getHours();
187
188
/**
189
* Gets the number of minutes (0-59).
190
*/
191
int getMinutes();
192
193
/**
194
* Gets the number of seconds (0-59).
195
*/
196
int getSeconds();
197
198
/**
199
* Gets the number of milliseconds (0-999).
200
*/
201
int getMillis();
202
203
/**
204
* Converts to total milliseconds.
205
*/
206
long toMilliseconds();
207
208
/**
209
* Converts to total seconds.
210
*/
211
long toSeconds();
212
213
/**
214
* Converts to total minutes.
215
*/
216
long toMinutes();
217
218
/**
219
* Converts to total hours.
220
*/
221
long toHours();
222
223
/**
224
* Converts to total days.
225
*/
226
long toDays();
227
228
/**
229
* Creates a string representation.
230
*/
231
String toString();
232
233
/**
234
* Adds this duration to a Calendar.
235
*/
236
void addToCalendar(Calendar calendar);
237
238
/**
239
* Subtracts this duration from a Calendar.
240
*/
241
void subtractFromCalendar(Calendar calendar);
242
}
243
```
244
245
### Datum Dependent Duration
246
247
Represents durations that depend on calendar context (months, years).
248
249
```java { .api }
250
class DatumDependentDuration extends BaseDuration {
251
/**
252
* Creates a DatumDependentDuration with the specified components.
253
*/
254
DatumDependentDuration(int years, int months, int days, int hours, int minutes, int seconds, int millis);
255
256
/**
257
* Gets the number of years.
258
*/
259
int getYears();
260
261
/**
262
* Gets the number of months.
263
*/
264
int getMonths();
265
266
/**
267
* Gets the number of days.
268
*/
269
int getDays();
270
271
/**
272
* Gets the number of hours.
273
*/
274
int getHours();
275
276
/**
277
* Gets the number of minutes.
278
*/
279
int getMinutes();
280
281
/**
282
* Gets the number of seconds.
283
*/
284
int getSeconds();
285
286
/**
287
* Gets the number of milliseconds.
288
*/
289
int getMillis();
290
291
/**
292
* Converts to milliseconds relative to a specific date.
293
*/
294
long toMilliseconds(Date relativeTo);
295
296
/**
297
* Creates a string representation.
298
*/
299
String toString();
300
301
/**
302
* Adds this duration to a Calendar.
303
*/
304
void addToCalendar(Calendar calendar);
305
306
/**
307
* Subtracts this duration from a Calendar.
308
*/
309
void subtractFromCalendar(Calendar calendar);
310
}
311
```
312
313
### Duration Factory Methods
314
315
Utility methods for creating common durations.
316
317
```java { .api }
318
class Duration {
319
/**
320
* Creates a duration from milliseconds.
321
*/
322
static TimeDuration ofMilliseconds(long millis);
323
324
/**
325
* Creates a duration from seconds.
326
*/
327
static TimeDuration ofSeconds(long seconds);
328
329
/**
330
* Creates a duration from minutes.
331
*/
332
static TimeDuration ofMinutes(long minutes);
333
334
/**
335
* Creates a duration from hours.
336
*/
337
static TimeDuration ofHours(long hours);
338
339
/**
340
* Creates a duration from days.
341
*/
342
static TimeDuration ofDays(long days);
343
344
/**
345
* Creates a duration from weeks.
346
*/
347
static TimeDuration ofWeeks(long weeks);
348
349
/**
350
* Creates a datum dependent duration from months.
351
*/
352
static DatumDependentDuration ofMonths(int months);
353
354
/**
355
* Creates a datum dependent duration from years.
356
*/
357
static DatumDependentDuration ofYears(int years);
358
359
/**
360
* Parses a duration from a string.
361
*/
362
static BaseDuration parse(String durationString);
363
}
364
```
365
366
## Usage Examples
367
368
### Basic Time Arithmetic
369
370
```java
371
import groovy.time.TimeCategory;
372
import java.util.Date;
373
import java.util.Calendar;
374
375
// Use TimeCategory for natural time arithmetic
376
Date now = new Date();
377
378
// Using TimeCategory.use() for safe category application
379
TimeCategory.use(new Closure<Void>(null) {
380
public Void doCall() {
381
// Add time periods
382
Date tomorrow = now.plus(1.getDays());
383
Date nextWeek = now.plus(1.getWeeks());
384
Date nextMonth = now.plus(1.getMonths());
385
Date nextYear = now.plus(1.getYears());
386
387
// Add multiple time units
388
Date future = now.plus(2.getHours()).plus(30.getMinutes());
389
390
// Subtract time periods
391
Date yesterday = now.minus(1.getDays());
392
Date lastWeek = now.minus(7.getDays());
393
394
// Calculate differences
395
BaseDuration diff = future.minus(now);
396
397
System.out.println("Now: " + now);
398
System.out.println("Tomorrow: " + tomorrow);
399
System.out.println("Future: " + future);
400
System.out.println("Difference: " + diff);
401
402
return null;
403
}
404
});
405
```
406
407
### Working with Duration Objects
408
409
```java
410
import groovy.time.TimeDuration;
411
import groovy.time.DatumDependentDuration;
412
import groovy.time.Duration;
413
414
// Create specific durations
415
TimeDuration twoHoursThirtyMinutes = new TimeDuration(0, 2, 30, 0, 0);
416
TimeDuration fiveMinutes = Duration.ofMinutes(5);
417
DatumDependentDuration threeMonths = Duration.ofMonths(3);
418
419
// Duration arithmetic
420
TimeDuration combined = (TimeDuration) twoHoursThirtyMinutes.plus(fiveMinutes);
421
TimeDuration doubled = (TimeDuration) fiveMinutes.multiply(2);
422
TimeDuration half = (TimeDuration) twoHoursThirtyMinutes.div(2);
423
424
// Apply durations to dates
425
Date startDate = new Date();
426
Date endDate = combined.plus(startDate);
427
428
System.out.println("Start: " + startDate);
429
System.out.println("Duration: " + combined);
430
System.out.println("End: " + endDate);
431
432
// Convert durations
433
long totalMinutes = combined.toMinutes();
434
long totalSeconds = combined.toSeconds();
435
long totalMillis = combined.toMilliseconds();
436
437
System.out.println("Total minutes: " + totalMinutes);
438
System.out.println("Total seconds: " + totalSeconds);
439
System.out.println("Total milliseconds: " + totalMillis);
440
```
441
442
### Complex Date Calculations
443
444
```java
445
import groovy.time.TimeCategory;
446
import java.util.Date;
447
import java.util.Calendar;
448
import java.text.SimpleDateFormat;
449
450
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
451
452
// Calculate business days and complex periods
453
TimeCategory.use(new Closure<Void>(null) {
454
public Void doCall() {
455
Date projectStart = new Date();
456
457
// Project timeline calculations
458
Date milestone1 = projectStart.plus(2.getWeeks()).plus(3.getDays());
459
Date milestone2 = milestone1.plus(1.getMonths()).plus(1.getWeeks());
460
Date projectEnd = projectStart.plus(6.getMonths());
461
462
// Calculate working days (excluding weekends)
463
BaseDuration projectDuration = projectEnd.minus(projectStart);
464
465
System.out.println("Project Start: " + formatter.format(projectStart));
466
System.out.println("Milestone 1: " + formatter.format(milestone1));
467
System.out.println("Milestone 2: " + formatter.format(milestone2));
468
System.out.println("Project End: " + formatter.format(projectEnd));
469
System.out.println("Total Duration: " + projectDuration);
470
471
// Calculate age from birthdate
472
Calendar birthCal = Calendar.getInstance();
473
birthCal.set(1990, Calendar.MARCH, 15);
474
Date birthDate = birthCal.getTime();
475
476
BaseDuration age = new Date().minus(birthDate);
477
long ageInDays = age.toDays();
478
long ageInYears = ageInDays / 365;
479
480
System.out.println("Birth Date: " + formatter.format(birthDate));
481
System.out.println("Age in days: " + ageInDays);
482
System.out.println("Age in years: " + ageInYears);
483
484
return null;
485
}
486
});
487
```
488
489
### Duration Comparisons and Sorting
490
491
```java
492
import groovy.time.TimeDuration;
493
import groovy.time.Duration;
494
import java.util.List;
495
import java.util.ArrayList;
496
import java.util.Collections;
497
498
// Create various durations
499
List<TimeDuration> durations = new ArrayList<>();
500
durations.add(Duration.ofHours(2));
501
durations.add(Duration.ofMinutes(90));
502
durations.add(Duration.ofSeconds(7200));
503
durations.add(Duration.ofDays(1));
504
durations.add(new TimeDuration(0, 1, 30, 0, 0));
505
506
// Sort durations
507
Collections.sort(durations);
508
509
System.out.println("Sorted durations:");
510
for (TimeDuration duration : durations) {
511
System.out.println(duration + " (" + duration.toMinutes() + " minutes)");
512
}
513
514
// Find maximum and minimum durations
515
TimeDuration maxDuration = Collections.max(durations);
516
TimeDuration minDuration = Collections.min(durations);
517
518
System.out.println("Maximum duration: " + maxDuration);
519
System.out.println("Minimum duration: " + minDuration);
520
521
// Duration arithmetic
522
TimeDuration totalDuration = new TimeDuration(0, 0, 0, 0, 0);
523
for (TimeDuration duration : durations) {
524
totalDuration = (TimeDuration) totalDuration.plus(duration);
525
}
526
527
System.out.println("Total duration: " + totalDuration);
528
System.out.println("Average duration: " + totalDuration.div(durations.size()));
529
```
530
531
### Calendar-Based Operations
532
533
```java
534
import groovy.time.TimeCategory;
535
import groovy.time.DatumDependentDuration;
536
import java.util.Calendar;
537
import java.util.Date;
538
539
// Working with calendar-dependent durations
540
Calendar calendar = Calendar.getInstance();
541
calendar.set(2023, Calendar.JANUARY, 31);
542
Date endOfJanuary = calendar.getTime();
543
544
TimeCategory.use(new Closure<Void>(null) {
545
public Void doCall() {
546
// Adding months can have different results depending on the date
547
Date oneMonthLater = endOfJanuary.plus(1.getMonths());
548
Date twoMonthsLater = endOfJanuary.plus(2.getMonths());
549
550
// February has fewer days, so this will be February 28 (or 29)
551
System.out.println("End of January: " + endOfJanuary);
552
System.out.println("One month later: " + oneMonthLater);
553
System.out.println("Two months later: " + twoMonthsLater);
554
555
// Working with leap years
556
calendar.set(2024, Calendar.FEBRUARY, 29); // Leap year
557
Date leapDay = calendar.getTime();
558
Date nextYear = leapDay.plus(1.getYears());
559
560
System.out.println("Leap day 2024: " + leapDay);
561
System.out.println("Same day next year: " + nextYear); // Will be Feb 28, 2025
562
563
return null;
564
}
565
});
566
```
567
568
### Time Zone and Calendar Manipulation
569
570
```java
571
import groovy.time.TimeCategory;
572
import groovy.time.TimeDuration;
573
import java.util.Calendar;
574
import java.util.TimeZone;
575
import java.text.SimpleDateFormat;
576
577
// Working with different time zones
578
SimpleDateFormat utcFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
579
utcFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
580
581
SimpleDateFormat localFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
582
583
Calendar utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
584
Date utcNow = utcCalendar.getTime();
585
586
TimeCategory.use(new Closure<Void>(null) {
587
public Void doCall() {
588
// Calculate meeting times across time zones
589
Date meetingTimeUTC = utcNow.plus(2.getHours());
590
591
// Convert to different time zones for display
592
System.out.println("Meeting time UTC: " + utcFormatter.format(meetingTimeUTC));
593
System.out.println("Meeting time local: " + localFormatter.format(meetingTimeUTC));
594
595
// Calculate duration until meeting
596
BaseDuration timeUntilMeeting = meetingTimeUTC.minus(utcNow);
597
System.out.println("Time until meeting: " + timeUntilMeeting);
598
599
// Schedule recurring meetings
600
List<Date> recurringMeetings = new ArrayList<>();
601
Date currentMeeting = meetingTimeUTC;
602
603
for (int i = 0; i < 5; i++) {
604
recurringMeetings.add(currentMeeting);
605
currentMeeting = currentMeeting.plus(1.getWeeks());
606
}
607
608
System.out.println("Recurring meetings:");
609
for (Date meeting : recurringMeetings) {
610
System.out.println(" " + utcFormatter.format(meeting));
611
}
612
613
return null;
614
}
615
});
616
```