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

enum-extensions.mddocs/

Enum Extensions

Enhanced functionality for DayOfWeek and Month enums including arithmetic operations, utility methods, and integration with other temporal types through operator overloading and factory methods.

Capabilities

DayOfWeek Operations

Enhanced functionality for the DayOfWeek enum with arithmetic and utility methods.

/**
 * Returns the DayOfWeek that is the specified number of days after this day.
 */
DayOfWeek plus(DayOfWeek self, int days)

/**
 * Returns the DayOfWeek that is the specified number of days before this day.
 */
DayOfWeek minus(DayOfWeek self, int days)

/**
 * Returns true if this day of the week is a weekend day (Saturday or Sunday).
 */
boolean isWeekend(DayOfWeek self)

/**
 * Returns true if this day of the week is a weekday (Monday through Friday).
 */
boolean isWeekday(DayOfWeek self)

Usage Examples:

import java.time.*

def monday = DayOfWeek.MONDAY

// Arithmetic operations
def wednesday = monday + 2        // Add 2 days -> WEDNESDAY
def saturday = monday + 5         // Add 5 days -> SATURDAY  
def previousFriday = monday - 3   // Subtract 3 days -> FRIDAY

println "Monday + 2 days = ${wednesday}"
println "Monday + 5 days = ${saturday}"
println "Monday - 3 days = ${previousFriday}"

// Week wrapping
def sunday = DayOfWeek.SATURDAY + 1    // Wraps to SUNDAY
def friday = DayOfWeek.SUNDAY - 2      // Wraps to FRIDAY

println "Saturday + 1 = ${sunday}"
println "Sunday - 2 = ${friday}"

// Large numbers wrap around the week
def nextMonday = monday + 7        // 7 days later -> MONDAY
def sameDay = monday + 14          // 14 days later -> MONDAY

println "Monday + 7 days = ${nextMonday}"
println "Monday + 14 days = ${sameDay}"

// Weekend/weekday checking
def days = DayOfWeek.values()
days.each { day ->
    def type = day.isWeekend() ? 'weekend' : 'weekday'
    println "${day} is a ${type}"
}

// Practical usage
def today = LocalDate.now().dayOfWeek
if (today.isWeekday()) {
    println "Today (${today}) is a work day"
} else {
    println "Today (${today}) is a weekend"
}

// Find next business day
def nextBusinessDay = today
while (nextBusinessDay.isWeekend()) {
    nextBusinessDay = nextBusinessDay + 1
}
println "Next business day after ${today}: ${nextBusinessDay}"

Month Operations

Enhanced functionality for the Month enum with arithmetic operations and temporal object creation.

/**
 * Returns the Month that is the specified number of months after this month.
 */
Month plus(Month self, int months)

/**
 * Returns the Month that is the specified number of months before this month.
 */
Month minus(Month self, int months)

/**
 * Creates a MonthDay at the provided day of the month.
 */
MonthDay leftShift(Month self, int dayOfMonth)

/**
 * Creates a YearMonth with the provided Year.
 */
YearMonth leftShift(Month self, Year year)

Usage Examples:

import java.time.*

def january = Month.JANUARY

// Arithmetic operations
def march = january + 2          // Add 2 months -> MARCH
def november = january - 2       // Subtract 2 months -> NOVEMBER (wraps to previous year)
def april = january + 3          // Add 3 months -> APRIL

println "January + 2 months = ${march}"
println "January - 2 months = ${november}"
println "January + 3 months = ${april}"

// Year wrapping
def december = Month.JANUARY - 1     // Wraps to DECEMBER
def february = Month.DECEMBER + 2    // Wraps to FEBRUARY

println "January - 1 month = ${december}"
println "December + 2 months = ${february}"

// Large numbers wrap around
def sameMonth = january + 12         // 12 months later -> JANUARY
def nextJanuary = january + 13       // 13 months later -> FEBRUARY

println "January + 12 months = ${sameMonth}"
println "January + 13 months = ${nextJanuary}"

// Creating temporal objects using left shift operator
def newYearsEve = Month.DECEMBER << 31        // MonthDay: December 31st
def christmas = Month.DECEMBER << 25          // MonthDay: December 25th
def valentines = Month.FEBRUARY << 14         // MonthDay: February 14th

println "New Year's Eve: ${newYearsEve}"
println "Christmas: ${christmas}"
println "Valentine's Day: ${valentines}"

// Creating YearMonth objects
def currentYear = Year.now()
def januaryThisYear = Month.JANUARY << currentYear    // YearMonth: January of current year
def december2024 = Month.DECEMBER << Year.of(2024)    // YearMonth: December 2024

println "January this year: ${januaryThisYear}"
println "December 2024: ${december2024}"

// Practical usage - seasonal operations
def seasons = [
    'Spring': [Month.MARCH, Month.APRIL, Month.MAY],
    'Summer': [Month.JUNE, Month.JULY, Month.AUGUST],
    'Fall': [Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER],
    'Winter': [Month.DECEMBER, Month.JANUARY, Month.FEBRUARY]
]

def currentMonth = LocalDate.now().month
def currentSeason = seasons.find { season, months -> 
    months.contains(currentMonth) 
}?.key

println "Current month ${currentMonth} is in ${currentSeason}"

// Working with month lengths
def year2024 = Year.of(2024)
Month.values().each { month ->
    def monthLength = (month << year2024).lengthOfMonth()
    println "${month}: ${monthLength} days in 2024"
}

Integration with Temporal Objects

How enum extensions integrate with other temporal types for comprehensive date/time operations.

Usage Examples:

import java.time.*

// Using DayOfWeek with LocalDate operations
def findNextOccurrence = { LocalDate startDate, DayOfWeek targetDay ->
    def current = startDate
    while (current.dayOfWeek != targetDay) {
        current = current + 1
    }
    return current
}

def today = LocalDate.now()
def nextFriday = findNextOccurrence(today, DayOfWeek.FRIDAY)
def nextMonday = findNextOccurrence(today, DayOfWeek.MONDAY)

println "Next Friday: ${nextFriday}"
println "Next Monday: ${nextMonday}"

// Using Month with date creation
def createHolidays = { Year year ->
    return [
        'New Year': (Month.JANUARY << 1) << year,      // January 1st
        'Independence Day': (Month.JULY << 4) << year, // July 4th  
        'Christmas': (Month.DECEMBER << 25) << year     // December 25th
    ]
}

def holidays2024 = createHolidays(Year.of(2024))
holidays2024.each { name, date ->
    println "${name}: ${date} (${date.dayOfWeek})"
}

// Business day calculations
def isBusinessDay = { LocalDate date ->
    return date.dayOfWeek.isWeekday()
}

def addBusinessDays = { LocalDate startDate, int businessDays ->
    def current = startDate
    def added = 0
    
    while (added < businessDays) {
        current = current + 1
        if (isBusinessDay(current)) {
            added++
        }
    }
    return current
}

def startDate = LocalDate.of(2024, 12, 20)  // Friday
def fiveDaysLater = addBusinessDays(startDate, 5)

println "5 business days after ${startDate}: ${fiveDaysLater}"

// Monthly reporting periods
def getQuarterMonths = { int quarter ->
    def baseMonth = Month.JANUARY + ((quarter - 1) * 3)
    return [
        baseMonth,
        baseMonth + 1,
        baseMonth + 2
    ]
}

(1..4).each { quarter ->
    def months = getQuarterMonths(quarter)
    println "Q${quarter}: ${months.join(', ')}"
}

// Seasonal date ranges
def getSeason = { Month month ->
    switch (month) {
        case [Month.DECEMBER, Month.JANUARY, Month.FEBRUARY]:
            return 'Winter'
        case [Month.MARCH, Month.APRIL, Month.MAY]:
            return 'Spring'
        case [Month.JUNE, Month.JULY, Month.AUGUST]:
            return 'Summer'
        case [Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER]:
            return 'Fall'
    }
}

def currentMonth = LocalDate.now().month
def season = getSeason(currentMonth)
println "Current season for ${currentMonth}: ${season}"

// Weekend vs weekday analysis
def analyzeWeek = { LocalDate startOfWeek ->
    def days = (0..6).collect { startOfWeek + it }
    def weekdays = days.findAll { it.dayOfWeek.isWeekday() }
    def weekends = days.findAll { it.dayOfWeek.isWeekend() }
    
    return [
        weekdays: weekdays,
        weekends: weekends,
        totalDays: days.size(),
        workingDays: weekdays.size()
    ]
}

def monday = LocalDate.now().with(DayOfWeek.MONDAY)  // Start of current week
def weekAnalysis = analyzeWeek(monday)

println "Week starting ${monday}:"
println "Working days: ${weekAnalysis.workingDays} (${weekAnalysis.weekdays.join(', ')})"
println "Weekend days: ${weekAnalysis.weekends.size()} (${weekAnalysis.weekends.join(', ')})"

Enum Arithmetic Edge Cases

Understanding the behavior of enum arithmetic with edge cases and boundary conditions.

Usage Examples:

import java.time.*

// DayOfWeek edge cases
def sunday = DayOfWeek.SUNDAY

// Negative arithmetic
def saturday = sunday - 1        // SATURDAY
def friday = sunday - 2          // FRIDAY
def monday = sunday - (-1)       // Same as sunday + 1 -> MONDAY

// Large numbers
def stillSunday = sunday + 7     // Wraps around -> SUNDAY  
def alsoSunday = sunday + 14     // Multiple weeks -> SUNDAY
def backToSunday = sunday - 7    // Negative wrap -> SUNDAY

println "Sunday - 1 = ${saturday}"
println "Sunday + 7 = ${stillSunday}"
println "Sunday - 7 = ${backToSunday}"

// Month edge cases
def december = Month.DECEMBER

// Crossing year boundaries
def january = december + 1       // Wraps to JANUARY
def november = december - 1      // NOVEMBER
def february = december + 2      // FEBRUARY (next year conceptually)

// Large arithmetic
def sameDecember = december + 12  // Full year -> DECEMBER
def march = december + 3          // MARCH (next year)
def september = december - 3      // SEPTEMBER (same year)

println "December + 1 = ${january}"
println "December + 12 = ${sameDecember}"
println "December - 3 = ${september}"

// Zero arithmetic (identity)
def unchangedDay = DayOfWeek.WEDNESDAY + 0    // WEDNESDAY
def unchangedMonth = Month.JUNE + 0           // JUNE

println "Wednesday + 0 = ${unchangedDay}"
println "June + 0 = ${unchangedMonth}"

// Modular arithmetic demonstration
def demonstrateModular = { DayOfWeek day, List<Integer> offsets ->
    offsets.each { offset ->
        def result = day + offset
        println "${day} + ${offset} = ${result} (offset mod 7 = ${offset % 7})"
    }
}

println "DayOfWeek modular arithmetic:"
demonstrateModular(DayOfWeek.MONDAY, [0, 1, 7, 8, 14, 15, -1, -7, -8])

// Month modular arithmetic
def demonstrateMonthModular = { Month month, List<Integer> offsets ->
    offsets.each { offset ->
        def result = month + offset  
        println "${month} + ${offset} = ${result} (offset mod 12 = ${offset % 12})"
    }
}

println "\nMonth modular arithmetic:"
demonstrateMonthModular(Month.JANUARY, [0, 1, 12, 13, 24, 25, -1, -12, -13])

Practical Applications

Real-world scenarios demonstrating the utility of enum extensions.

Usage Examples:

import java.time.*

// Payroll system - find pay dates (every other Friday)
def calculatePayDates = { LocalDate startDate, int numberOfPays ->
    def payDates = []
    def current = startDate
    
    // Find first Friday on or after start date
    while (current.dayOfWeek != DayOfWeek.FRIDAY) {
        current = current + 1
    }
    
    numberOfPays.times {
        payDates << current
        current = current + 14  // Every two weeks
    }
    
    return payDates
}

def payDates = calculatePayDates(LocalDate.of(2024, 1, 1), 6)
println "Pay dates for first half of 2024:"
payDates.each { date ->
    println "${date} (${date.dayOfWeek})"
}

// Restaurant schedule - closed on Mondays, special menu on weekends
def getRestaurantStatus = { LocalDate date ->
    def dayOfWeek = date.dayOfWeek
    
    if (dayOfWeek == DayOfWeek.MONDAY) {
        return 'Closed'
    } else if (dayOfWeek.isWeekend()) {
        return 'Special Weekend Menu'
    } else {
        return 'Regular Menu'
    }
}

def thisWeek = (0..6).collect { LocalDate.now().with(DayOfWeek.MONDAY) + it }
println "Restaurant schedule this week:"
thisWeek.each { date ->
    println "${date} (${date.dayOfWeek}): ${getRestaurantStatus(date)}"
}

// Seasonal product availability
def getProductAvailability = { Month month ->
    def season = null
    switch (month) {
        case [Month.DECEMBER, Month.JANUARY, Month.FEBRUARY]:
            season = 'Winter'
            break
        case [Month.MARCH, Month.APRIL, Month.MAY]:
            season = 'Spring'
            break
        case [Month.JUNE, Month.JULY, Month.AUGUST]:
            season = 'Summer'
            break
        case [Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER]:
            season = 'Fall'
            break
    }
    
    def products = [
        'Winter': ['Hot chocolate', 'Soup', 'Winter coats'],
        'Spring': ['Rain gear', 'Gardening supplies', 'Light jackets'],
        'Summer': ['Sunscreen', 'Swimming gear', 'Ice cream'],
        'Fall': ['Pumpkins', 'Warm sweaters', 'Back-to-school supplies']
    ]
    
    return [season: season, products: products[season]]
}

Month.values().each { month ->
    def availability = getProductAvailability(month)
    println "${month} (${availability.season}): ${availability.products.join(', ')}"
}

// Meeting scheduler - avoid Mondays and Fridays
def findBestMeetingDay = { LocalDate weekStart ->
    def preferredDays = [DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY]
    def monday = weekStart.with(DayOfWeek.MONDAY)
    
    def availableDays = preferredDays.collect { dayOfWeek ->
        monday.with(dayOfWeek)
    }
    
    return availableDays.find { date ->
        // Additional logic could check calendar conflicts, etc.
        true  // For demo, all preferred days are available
    }
}

def nextWeek = LocalDate.now().plusWeeks(1)
def bestDay = findBestMeetingDay(nextWeek)
println "Best day for meeting next week: ${bestDay} (${bestDay.dayOfWeek})"

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