Groovy extensions for working with Java 8+ date/time types, providing convenient methods for temporal operations and transformations
—
Mathematical operations on Duration and Period objects with full operator overloading support for arithmetic, comparison, and type checking operations.
Duration represents a time-based amount of time (hours, minutes, seconds, nanoseconds).
/**
* Returns a Duration that is the specified number of seconds longer than this duration.
*/
Duration plus(Duration self, long seconds)
/**
* Returns a Duration that is the specified number of seconds shorter than this duration.
*/
Duration minus(Duration self, long seconds)
/**
* Returns a Duration that is one second longer than this duration.
*/
Duration next(Duration self)
/**
* Returns a Duration that is one second shorter than this duration.
*/
Duration previous(Duration self)
/**
* Supports the unary minus operator; equivalent to Duration.negated().
*/
Duration negative(Duration self)
/**
* Supports the unary plus operator; returns the absolute value of the duration.
*/
Duration positive(Duration self)
/**
* Supports the multiplication operator; equivalent to Duration.multipliedBy().
*/
Duration multiply(Duration self, long scalar)
/**
* Supports the division operator; equivalent to Duration.dividedBy().
*/
Duration div(Duration self, long scalar)
/**
* Returns true if this duration is positive, excluding zero.
*/
boolean isPositive(Duration self)
/**
* Returns true if this duration is zero or positive.
*/
boolean isNonnegative(Duration self)
/**
* Returns true if this duration is zero or negative.
*/
boolean isNonpositive(Duration self)Usage Examples:
import java.time.*
def duration = Duration.ofMinutes(30)
// Arithmetic operations using operators
def longer = duration + 120 // Add 120 seconds (2 minutes)
def shorter = duration - 300 // Subtract 300 seconds (5 minutes)
def doubled = duration * 2 // 60 minutes
def halved = duration / 2 // 15 minutes
// Unary operators
def negated = -duration // Negative 30 minutes
def absolute = +duration // Absolute value (same as positive duration)
// Navigation
def nextSecond = duration.next() // One second longer
def prevSecond = duration.previous() // One second shorter
// Type checking
println duration.isPositive() // true (30 minutes > 0)
println duration.isNonnegative() // true (30 minutes >= 0)
def zeroDuration = Duration.ZERO
println zeroDuration.isNonnegative() // true (0 >= 0)
println zeroDuration.isPositive() // false (0 not > 0)
def negativeDuration = Duration.ofMinutes(-10)
println negativeDuration.isNonpositive() // true (-10 minutes <= 0)
// Chaining operations
def result = Duration.ofHours(1)
.plus(1800) // Add 30 minutes
.multiply(2) // Double it
.div(3) // Divide by 3
println "Result: ${result.toHours()} hours, ${result.toMinutesPart()} minutes"Period represents a date-based amount of time (years, months, days).
/**
* Returns a Period that is the specified number of days longer than this period.
*/
Period plus(Period self, long days)
/**
* Returns a Period that is the specified number of days shorter than this period.
*/
Period minus(Period self, long days)
/**
* Returns a Period that is one day longer than this period.
*/
Period next(Period self)
/**
* Returns a Period that is one day shorter than this period.
*/
Period previous(Period self)
/**
* Supports the unary minus operator; equivalent to Period.negated().
*/
Period negative(Period self)
/**
* Supports the unary plus operator; returns a Period with all absolute values.
*/
Period positive(Period self)
/**
* Supports the multiplication operator; equivalent to Period.multipliedBy().
*/
Period multiply(Period self, int scalar)
/**
* Returns true if this period is positive, excluding zero.
*/
boolean isPositive(ChronoPeriod self)
/**
* Returns true if this period is zero or positive.
*/
boolean isNonnegative(ChronoPeriod self)
/**
* Returns true if this period is zero or negative.
*/
boolean isNonpositive(ChronoPeriod self)Usage Examples:
import java.time.*
def period = Period.of(1, 6, 15) // 1 year, 6 months, 15 days
// Arithmetic operations
def longerPeriod = period + 10 // Add 10 days
def shorterPeriod = period - 5 // Subtract 5 days
def doubled = period * 2 // 2 years, 12 months, 30 days
// Unary operators
def negated = -period // -1 year, -6 months, -15 days
def absolute = +period // All positive values
// Navigation
def nextDay = period.next() // Add one day
def prevDay = period.previous() // Subtract one day
// Type checking
println period.isPositive() // true (has positive components)
println period.isNonnegative() // true (no negative components)
def mixedPeriod = Period.of(1, -2, 3) // 1 year, -2 months, 3 days
println mixedPeriod.isPositive() // false (has negative component)
def negativePeriod = Period.of(-1, -1, -1)
println negativePeriod.isNonpositive() // true (all components <= 0)
// Working with normalized periods
def normalized = Period.of(0, 14, 0).normalized() // Becomes 1 year, 2 months
println "Normalized: ${normalized.years} years, ${normalized.months} months"Generic access to temporal amounts using the subscript operator.
/**
* Supports the subscript operator for accessing TemporalUnit values.
*/
long getAt(TemporalAmount self, TemporalUnit unit)Usage Examples:
import java.time.*
import java.time.temporal.ChronoUnit
def duration = Duration.ofHours(2).plusMinutes(30).plusSeconds(45)
def period = Period.of(2, 3, 10)
// Access duration components using subscript operator
def hours = duration[ChronoUnit.HOURS] // 2
def minutes = duration[ChronoUnit.MINUTES] // 150 (total minutes)
def seconds = duration[ChronoUnit.SECONDS] // 9045 (total seconds)
// Access period components using subscript operator
def years = period[ChronoUnit.YEARS] // 2
def months = period[ChronoUnit.MONTHS] // 3
def days = period[ChronoUnit.DAYS] // 10
println "Duration: ${hours}h ${minutes}m ${seconds}s"
println "Period: ${years}y ${months}m ${days}d"Advanced usage patterns for duration arithmetic and manipulation.
Usage Examples:
import java.time.*
import java.time.temporal.ChronoUnit
// Complex duration calculations
def workingHours = Duration.ofHours(8)
def breakTime = Duration.ofMinutes(30)
def overtime = Duration.ofHours(2)
def totalWorkTime = workingHours + (breakTime.toSeconds() / 60) + overtime.toSeconds()
def weeklyWork = workingHours * 5 // 5 working days
// Duration comparisons and chains
def shortBreak = Duration.ofMinutes(15)
def longBreak = Duration.ofMinutes(30)
if (shortBreak < longBreak) {
println "Short break is indeed shorter"
}
// Create durations from different units
def fromHours = Duration.ofHours(1)
def fromMinutes = Duration.ofMinutes(60)
def fromSeconds = Duration.ofSeconds(3600)
println "All equal: ${fromHours == fromMinutes && fromMinutes == fromSeconds}"
// Duration arithmetic with temporal objects
def now = Instant.now()
def later = now + Duration.ofMinutes(30).toSeconds() // Add duration as seconds
def earlier = now - (Duration.ofHours(1).toSeconds()) // Subtract duration as secondsAdvanced usage patterns for period arithmetic and date manipulation.
Usage Examples:
import java.time.*
// Complex period calculations
def age = Period.between(LocalDate.of(1990, 5, 15), LocalDate.now())
def retirement = Period.of(65, 0, 0) - age // Years until retirement
println "Age: ${age.years} years, ${age.months} months, ${age.days} days"
println "Years to retirement: ${retirement.years}"
// Period manipulation with dates
def startDate = LocalDate.of(2024, 1, 1)
def projectDuration = Period.of(0, 6, 15) // 6 months, 15 days
def milestones = []
def currentDate = startDate
3.times { i ->
milestones << currentDate
currentDate = currentDate + projectDuration // Add period to date
}
milestones.each { milestone ->
println "Milestone ${milestones.indexOf(milestone) + 1}: ${milestone}"
}
// Working with different period types
def yearPeriod = Period.ofYears(2)
def monthPeriod = Period.ofMonths(24) // Equivalent to 2 years
def dayPeriod = Period.ofDays(730) // Approximately 2 years
// Note: These are not automatically equivalent due to variable month/year lengths
println "Year period: ${yearPeriod}"
println "Month period: ${monthPeriod}"
println "Day period: ${dayPeriod}"
// Normalize to convert months to years where possible
def normalizedMonth = monthPeriod.normalized()
println "Normalized month period: ${normalizedMonth}" // 2 years, 0 monthsHow Duration and Period objects integrate with temporal types for arithmetic operations.
Usage Examples:
import java.time.*
// Using periods with dates
def startDate = LocalDate.of(2024, 1, 1)
def period = Period.of(1, 6, 10) // 1 year, 6 months, 10 days
def futureDate = startDate + period // Uses plus(Period) method
def pastDate = startDate - period // Uses minus(Period) method
// Using durations with time-based objects
def startTime = LocalTime.of(9, 0)
def duration = Duration.ofHours(2).plusMinutes(30)
def endTime = startTime + duration.toSeconds() // Add as seconds
def earlierTime = startTime - duration.toSeconds()
// Complex temporal arithmetic
def meeting = LocalDateTime.of(2024, 12, 25, 14, 0)
def preparation = Duration.ofMinutes(30)
def followUp = Period.ofDays(3)
def prepStart = meeting - preparation.toSeconds()
def followUpDate = meeting.toLocalDate() + followUp
println "Prep starts: ${prepStart}"
println "Follow-up date: ${followUpDate}"Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-datetime