CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-codehaus-groovy--groovy-datetime

Groovy extensions for working with Java 8+ date/time types, providing convenient methods for temporal operations and transformations

Pending
Overview
Eval results
Files

temporal-iteration.mddocs/

Temporal Iteration

Functionality for iterating over temporal ranges with support for custom units, step sizes, and calculating periods or durations between temporal objects.

Capabilities

Temporal Iteration Methods

Core iteration functionality that works with all Temporal subtypes.

/**
 * Iterates from this to the target Temporal, inclusive, incrementing by one default unit each iteration.
 * Default units: DAYS for dates, MONTHS for YearMonth, YEARS for Year, SECONDS for others.
 */
void upto(Temporal from, Temporal to, Closure closure)

/**
 * Iterates from this to the target Temporal, inclusive, incrementing by one specified unit each iteration.
 */
void upto(Temporal from, Temporal to, TemporalUnit unit, Closure closure)

/**
 * Iterates from this to the target Temporal, inclusive, decrementing by one default unit each iteration.
 */
void downto(Temporal from, Temporal to, Closure closure)

/**
 * Iterates from this to the target Temporal, inclusive, decrementing by one specified unit each iteration.
 */
void downto(Temporal from, Temporal to, TemporalUnit unit, Closure closure)

/**
 * Returns a TemporalAmount (Duration or Period) between this and another Temporal.
 * Returns Period for dates, Duration for times.
 */
TemporalAmount rightShift(Temporal self, Temporal other)

TemporalAccessor Operations

Generic field access operations for all temporal objects that implement TemporalAccessor.

/**
 * Supports the subscript operator for accessing temporal fields.
 * Equivalent to calling getLong(TemporalField).
 */
long getAt(TemporalAccessor self, TemporalField field)

TemporalAmount Operations

Generic unit access operations for temporal amounts (Duration and Period).

/**
 * Supports the subscript operator for accessing temporal units.
 * Equivalent to calling get(TemporalUnit).
 */
long getAt(TemporalAmount self, TemporalUnit unit)

Usage Examples:

import java.time.*
import java.time.temporal.ChronoUnit
import java.time.temporal.ChronoField

// Date iteration with default unit (days)
def start = LocalDate.of(2024, 1, 1)
def end = start + 5
start.upto(end) { date ->
    println "${date} is ${date.dayOfWeek}"
}

// Date iteration with custom unit
start.upto(end, ChronoUnit.DAYS) { date ->
    println "Processing: ${date}"
}

// Time iteration (default unit is seconds)
def startTime = LocalTime.of(10, 0)
def endTime = startTime + 5  // 5 seconds later
startTime.upto(endTime) { time ->
    println time
}

// Year iteration (default unit is years)
def startYear = Year.of(2020)
def endYear = Year.of(2024)
startYear.upto(endYear) { year ->
    println "Year: ${year.value}"
}

// Downto iteration
end.downto(start) { date ->
    println "Counting down: ${date}"  
}

// Period calculation using right shift operator
def period = start >> end  // Returns Period
println "Period: ${period.days} days"

// Duration calculation
def duration = startTime >> endTime  // Returns Duration  
println "Duration: ${duration.seconds} seconds"

// TemporalAccessor field access using subscript operator
def now = LocalDateTime.now()
def hourOfDay = now[ChronoField.HOUR_OF_DAY]     // Get hour field
def dayOfYear = now[ChronoField.DAY_OF_YEAR]     // Get day of year
def month = now[ChronoField.MONTH_OF_YEAR]       // Get month

println "Current time: ${now}"
println "Hour of day: ${hourOfDay}"
println "Day of year: ${dayOfYear}"
println "Month: ${month}"

// TemporalAmount unit access using subscript operator
def period = Period.of(2, 3, 15)  // 2 years, 3 months, 15 days
def years = period[ChronoUnit.YEARS]     // Get years component
def months = period[ChronoUnit.MONTHS]   // Get months component
def days = period[ChronoUnit.DAYS]       // Get days component

println "Period: ${period}"
println "Years: ${years}"
println "Months: ${months}"
println "Days: ${days}"

def duration2 = Duration.ofHours(5).plusMinutes(30)
def hours = duration2[ChronoUnit.HOURS]      // Get hours component
def minutes = duration2[ChronoUnit.MINUTES]  // Get total minutes

println "Duration: ${duration2}"
println "Total hours: ${hours}"
println "Total minutes: ${minutes}"

Date Range Iteration

Specialized iteration methods for date-based temporal types.

/**
 * Returns a LocalDate one day after this date.
 */
LocalDate next(LocalDate self)

/**
 * Returns a LocalDate one day before this date.
 */
LocalDate previous(LocalDate self)

/**
 * Returns a Period between this date and another date.
 */
Period rightShift(LocalDate self, LocalDate other)

Usage Examples:

import java.time.*

def today = LocalDate.now()
def dates = []

// Collect dates using next() method
def current = today
5.times {
    dates << current
    current = current.next()
}

// Create date ranges for iteration
def startDate = LocalDate.of(2024, 1, 1)
def endDate = LocalDate.of(2024, 1, 7) 

// Standard Groovy range operator works with dates
(startDate..endDate).each { date ->
    println "${date}: ${date.dayOfWeek}"
}

// Calculate period between dates
def period = startDate >> endDate
println "Difference: ${period.days} days"

Year and Month Iteration

Iteration support for year and month-based temporal types.

/**
 * Returns a Year one year after this year.
 */
Year next(Year self)

/**
 * Returns a Year one year before this year.
 */
Year previous(Year self)

/**
 * Returns a Period between the first day of this year and the first day of the target year.
 */
Period rightShift(Year self, Year other)

/**
 * Returns a YearMonth one month after this year-month.
 */
YearMonth next(YearMonth self)

/**
 * Returns a YearMonth one month before this year-month.
 */
YearMonth previous(YearMonth self)

/**
 * Returns a Period between the first day of this year-month and the first day of the target year-month.
 */
Period rightShift(YearMonth self, YearMonth other)

Usage Examples:

import java.time.*

// Year iteration
def startYear = Year.of(2020)
def endYear = Year.of(2024)

startYear.upto(endYear) { year ->
    println "Processing year: ${year.value}"
    println "Leap year: ${year.isLeap()}"
}

// YearMonth iteration
def startMonth = YearMonth.of(2024, 1)  
def endMonth = YearMonth.of(2024, 6)

startMonth.upto(endMonth) { yearMonth ->
    println "${yearMonth.month} ${yearMonth.year}: ${yearMonth.lengthOfMonth()} days"
}

// Calculate periods
def yearPeriod = startYear >> endYear
def monthPeriod = startMonth >> endMonth
println "Years between: ${yearPeriod.years}"
println "Months between: ${monthPeriod.months}"

Custom Unit Iteration

Advanced iteration with custom temporal units and step sizes.

Usage Examples:

import java.time.*
import java.time.temporal.ChronoUnit

def start = LocalDateTime.of(2024, 1, 1, 0, 0)
def end = start.plusDays(2)

// Iterate by hours
start.upto(end, ChronoUnit.HOURS) { dateTime ->
    println dateTime.format('yyyy-MM-dd HH:mm')
}

// Iterate by 6-hour increments (not directly supported, but can be achieved)
def current = start
while (current <= end) {
    println current.format('yyyy-MM-dd HH:mm')
    current = current.plus(6, ChronoUnit.HOURS)
}

// Week-based iteration
def monday = LocalDate.of(2024, 1, 1)  // Assume this is a Monday
def endOfMonth = LocalDate.of(2024, 1, 31)

monday.upto(endOfMonth, ChronoUnit.WEEKS) { date ->
    println "Week starting: ${date}"
}

Range Operators and Integration

Integration with Groovy's range operators for natural iteration syntax.

Usage Examples:

import java.time.*

def start = LocalDate.of(2024, 1, 1)
def end = start + 10

// Using Groovy range operator (works because of next/previous methods)
(start..end).each { date ->
    if (date.dayOfWeek == DayOfWeek.SUNDAY) {
        println "Sunday: ${date}"
    }
}

// Using step with ranges (for every other day)
(start..end).step(2) { date ->
    println "Every other day: ${date}"
}

// Reverse ranges
(end..start).each { date ->
    println "Counting down: ${date}"
}

Error Handling and Constraints

Important behavior and limitations for temporal iteration.

Exceptions Thrown:

  • GroovyRuntimeException - If the start value is later than the end value for upto()
  • GroovyRuntimeException - If the start value is earlier than the end value for downto()
  • GroovyRuntimeException - If the temporal types don't match
  • GroovyRuntimeException - If temporal type doesn't support the specified unit

Usage Examples:

import java.time.*

def start = LocalDate.of(2024, 1, 5)
def end = LocalDate.of(2024, 1, 1)  // Earlier than start

try {
    // This will throw GroovyRuntimeException
    start.upto(end) { date ->
        println date
    }
} catch (GroovyRuntimeException e) {
    println "Cannot iterate backwards with upto(): ${e.message}"
}

// Use downto() instead
start.downto(end) { date ->
    println "Going backwards: ${date}"
}

// Type mismatch will also cause errors
def date = LocalDate.now()
def time = LocalTime.now()

try {
    // This will throw GroovyRuntimeException
    date.upto(time) { /* won't work */ }
} catch (GroovyRuntimeException e) {
    println "Type mismatch: ${e.message}"
}

Install with Tessl CLI

npx tessl i tessl/maven-org-codehaus-groovy--groovy-datetime

docs

date-time-operations.md

duration-period-operations.md

enum-extensions.md

index.md

legacy-conversion.md

parsing-factory-methods.md

temporal-iteration.md

year-month-operations.md

zone-offset-operations.md

tile.json