Groovy extensions for working with Java 8+ date/time types, providing convenient methods for temporal operations and transformations
—
Bidirectional conversion methods between legacy java.util.Date/Calendar/TimeZone types and modern java.time API types, enabling smooth migration and interoperability between old and new date/time systems.
Converting java.util.Calendar objects to modern java.time types.
/**
* Converts the Calendar to a corresponding LocalDate.
*/
LocalDate toLocalDate(Calendar self)
/**
* Converts the Calendar to a corresponding LocalTime.
*/
LocalTime toLocalTime(Calendar self)
/**
* Converts the Calendar to a corresponding LocalDateTime.
*/
LocalDateTime toLocalDateTime(Calendar self)
/**
* Converts the Calendar to a corresponding ZonedDateTime.
*/
ZonedDateTime toZonedDateTime(Calendar self)
/**
* Converts the Calendar to a corresponding OffsetDateTime.
*/
OffsetDateTime toOffsetDateTime(Calendar self)
/**
* Converts the Calendar to a corresponding OffsetTime.
*/
OffsetTime toOffsetTime(Calendar self)
/**
* Converts the Calendar to a corresponding Year.
*/
Year toYear(Calendar self)
/**
* Converts the Calendar to a corresponding Month.
*/
Month toMonth(Calendar self)
/**
* Converts the Calendar to a corresponding YearMonth.
*/
YearMonth toYearMonth(Calendar self)
/**
* Converts the Calendar to a corresponding MonthDay.
*/
MonthDay toMonthDay(Calendar self)
/**
* Converts the Calendar to a corresponding DayOfWeek.
*/
DayOfWeek toDayOfWeek(Calendar self)
/**
* Returns the ZoneId of the Calendar's timezone.
*/
ZoneId getZoneId(Calendar self)
/**
* Returns the ZoneOffset of the Calendar's timezone.
*/
ZoneOffset getZoneOffset(Calendar self)
/**
* Converts the Calendar to an Instant.
*/
Instant toInstant(Calendar self)Usage Examples:
import java.time.*
import java.util.*
// Create a Calendar for testing
def calendar = Calendar.getInstance()
calendar.set(2024, Calendar.DECEMBER, 25, 14, 30, 45)
calendar.set(Calendar.MILLISECOND, 123)
// Basic temporal conversions
def localDate = calendar.toLocalDate() // 2024-12-25
def localTime = calendar.toLocalTime() // 14:30:45.123
def localDateTime = calendar.toLocalDateTime() // 2024-12-25T14:30:45.123
println "LocalDate: ${localDate}"
println "LocalTime: ${localTime}"
println "LocalDateTime: ${localDateTime}"
// Timezone-aware conversions
def zonedDateTime = calendar.toZonedDateTime() // Includes timezone
def offsetDateTime = calendar.toOffsetDateTime() // Fixed offset
def offsetTime = calendar.toOffsetTime() // Time with offset
println "ZonedDateTime: ${zonedDateTime}"
println "OffsetDateTime: ${offsetDateTime}"
// Component extractions
def year = calendar.toYear() // Year 2024
def month = calendar.toMonth() // Month DECEMBER
def yearMonth = calendar.toYearMonth() // 2024-12
def monthDay = calendar.toMonthDay() // --12-25
def dayOfWeek = calendar.toDayOfWeek() // Day of week
println "Year: ${year}, Month: ${month}, YearMonth: ${yearMonth}"
println "MonthDay: ${monthDay}, DayOfWeek: ${dayOfWeek}"
// Timezone information
def zoneId = calendar.zoneId // System default or calendar's zone
def zoneOffset = calendar.zoneOffset // Offset from UTC
println "ZoneId: ${zoneId}, ZoneOffset: ${zoneOffset}"
// Instant conversion
def instant = calendar.toInstant() // Point in time
println "Instant: ${instant}"Converting java.util.Date objects to modern java.time types.
/**
* Converts the Date to a corresponding LocalDate.
*/
LocalDate toLocalDate(Date self)
/**
* Converts the Date to a corresponding LocalTime.
*/
LocalTime toLocalTime(Date self)
/**
* Converts the Date to a corresponding LocalDateTime.
*/
LocalDateTime toLocalDateTime(Date self)
/**
* Converts the Date to a corresponding ZonedDateTime.
*/
ZonedDateTime toZonedDateTime(Date self)
/**
* Converts the Date to a corresponding OffsetDateTime.
*/
OffsetDateTime toOffsetDateTime(Date self)
/**
* Converts the Date to a corresponding OffsetTime.
*/
OffsetTime toOffsetTime(Date self)
/**
* Converts the Date to a corresponding Year.
*/
Year toYear(Date self)
/**
* Converts the Date to a corresponding Month.
*/
Month toMonth(Date self)
/**
* Converts the Date to a corresponding YearMonth.
*/
YearMonth toYearMonth(Date self)
/**
* Converts the Date to a corresponding MonthDay.
*/
MonthDay toMonthDay(Date self)
/**
* Converts the Date to a corresponding DayOfWeek.
*/
DayOfWeek toDayOfWeek(Date self)
/**
* Returns the ZoneId associated with the Date (typically system default).
*/
ZoneId getZoneId(Date self)
/**
* Returns the ZoneOffset associated with the Date (typically system default).
*/
ZoneOffset getZoneOffset(Date self)Usage Examples:
import java.time.*
import java.util.*
// Create a Date for testing
def date = new Date(124, 11, 25, 14, 30, 45) // Note: Year is years since 1900
// Basic temporal conversions
def localDate = date.toLocalDate() // Extract date portion
def localTime = date.toLocalTime() // Extract time portion
def localDateTime = date.toLocalDateTime() // Date and time
println "From Date - LocalDate: ${localDate}, LocalTime: ${localTime}"
println "LocalDateTime: ${localDateTime}"
// Timezone-aware conversions (using system default timezone)
def zonedDateTime = date.toZonedDateTime()
def offsetDateTime = date.toOffsetDateTime()
def offsetTime = date.toOffsetTime()
println "ZonedDateTime: ${zonedDateTime}"
println "OffsetDateTime: ${offsetDateTime}"
// Component extractions
def year = date.toYear()
def month = date.toMonth()
def yearMonth = date.toYearMonth()
def monthDay = date.toMonthDay()
def dayOfWeek = date.toDayOfWeek()
println "Components - Year: ${year}, Month: ${month}"
println "YearMonth: ${yearMonth}, MonthDay: ${monthDay}, DayOfWeek: ${dayOfWeek}"
// Timezone information (based on system default)
def zoneId = date.zoneId
def zoneOffset = date.zoneOffset
println "ZoneId: ${zoneId}, ZoneOffset: ${zoneOffset}"
// Convert to Instant (already available in Date)
def instant = date.toInstant()
println "Instant: ${instant}"Converting modern java.time types back to legacy java.util.Date/Calendar types.
/**
* Converts LocalDate to java.util.Date (time portion cleared).
*/
Date toDate(LocalDate self)
/**
* Converts LocalTime to java.util.Date (using today's date).
*/
Date toDate(LocalTime self)
/**
* Converts LocalDateTime to java.util.Date.
*/
Date toDate(LocalDateTime self)
/**
* Converts Instant to java.util.Date.
*/
Date toDate(Instant self)
/**
* Converts ZonedDateTime to java.util.Date.
*/
Date toDate(ZonedDateTime self)
/**
* Converts OffsetDateTime to java.util.Date.
*/
Date toDate(OffsetDateTime self)
/**
* Converts OffsetTime to java.util.Date.
*/
Date toDate(OffsetTime self)
/**
* Converts LocalDate to java.util.Calendar (time portion cleared).
*/
Calendar toCalendar(LocalDate self)
/**
* Converts LocalTime to java.util.Calendar (using today's date).
*/
Calendar toCalendar(LocalTime self)
/**
* Converts LocalDateTime to java.util.Calendar.
*/
Calendar toCalendar(LocalDateTime self)
/**
* Converts Instant to java.util.Calendar.
*/
Calendar toCalendar(Instant self)
/**
* Converts ZonedDateTime to java.util.Calendar.
*/
Calendar toCalendar(ZonedDateTime self)
/**
* Converts OffsetDateTime to java.util.Calendar.
*/
Calendar toCalendar(OffsetDateTime self)
/**
* Converts OffsetTime to java.util.Calendar.
*/
Calendar toCalendar(OffsetTime self)Usage Examples:
import java.time.*
import java.util.*
// Convert LocalDate to legacy types
def localDate = LocalDate.of(2024, 12, 25)
def dateFromLocalDate = localDate.toDate() // Date with time at start of day
def calendarFromLocalDate = localDate.toCalendar() // Calendar with time cleared
println "LocalDate to Date: ${dateFromLocalDate}"
println "LocalDate to Calendar: ${calendarFromLocalDate.time}"
// Convert LocalTime to legacy types (uses today's date)
def localTime = LocalTime.of(14, 30, 45)
def dateFromLocalTime = localTime.toDate() // Today's date with specified time
def calendarFromLocalTime = localTime.toCalendar() // Today's date with specified time
println "LocalTime to Date: ${dateFromLocalTime}"
// Convert LocalDateTime to legacy types
def localDateTime = LocalDateTime.of(2024, 12, 25, 14, 30, 45)
def dateFromDateTime = localDateTime.toDate()
def calendarFromDateTime = localDateTime.toCalendar()
println "LocalDateTime to Date: ${dateFromDateTime}"
println "Calendar year: ${calendarFromDateTime.get(Calendar.YEAR)}"
// Convert timezone-aware types
def zonedDateTime = ZonedDateTime.of(2024, 12, 25, 14, 30, 45, 0, ZoneId.of('America/New_York'))
def dateFromZoned = zonedDateTime.toDate() // Adjusted to system timezone
def calendarFromZoned = zonedDateTime.toCalendar() // Preserves original timezone
println "ZonedDateTime to Date: ${dateFromZoned}"
println "Calendar timezone: ${calendarFromZoned.timeZone.id}"
// Convert Instant to legacy types
def instant = Instant.now()
def dateFromInstant = instant.toDate()
def calendarFromInstant = instant.toCalendar() // GMT timezone
println "Instant to Date: ${dateFromInstant}"
println "Instant to Calendar: ${calendarFromInstant.time}"Converting between java.util.TimeZone and java.time timezone types.
/**
* Converts TimeZone to ZoneOffset using current time.
*/
ZoneOffset toZoneOffset(TimeZone self)
/**
* Converts TimeZone to ZoneOffset at the specified instant.
*/
ZoneOffset toZoneOffset(TimeZone self, Instant instant)
/**
* Converts ZoneId to java.util.TimeZone.
*/
TimeZone toTimeZone(ZoneId self)
/**
* Converts ZoneOffset to java.util.TimeZone.
*/
TimeZone toTimeZone(ZoneOffset self)Usage Examples:
import java.time.*
import java.util.*
// TimeZone to ZoneOffset conversion
def estTimeZone = TimeZone.getTimeZone('America/New_York')
def currentOffset = estTimeZone.toZoneOffset() // Current offset
def summerOffset = estTimeZone.toZoneOffset(Instant.parse('2024-07-01T00:00:00Z')) // Summer offset
def winterOffset = estTimeZone.toZoneOffset(Instant.parse('2024-01-01T00:00:00Z')) // Winter offset
println "EST Current offset: ${currentOffset}"
println "EST Summer offset: ${summerOffset}" // Likely -04:00 (EDT)
println "EST Winter offset: ${winterOffset}" // Likely -05:00 (EST)
// ZoneId to TimeZone conversion
def zoneId = ZoneId.of('Europe/London')
def timeZone = zoneId.toTimeZone()
println "ZoneId to TimeZone: ${timeZone.id}"
// ZoneOffset to TimeZone conversion
def offset = ZoneOffset.ofHours(5)
def offsetTimeZone = offset.toTimeZone() // GMT+05:00
println "ZoneOffset to TimeZone: ${offsetTimeZone.id}"
// Complex timezone handling
def utcZone = ZoneId.of('UTC')
def utcTimeZone = utcZone.toTimeZone()
def utcOffset = utcTimeZone.toZoneOffset()
println "UTC roundtrip: ${utcZone} -> ${utcTimeZone.id} -> ${utcOffset}"Demonstrating bidirectional conversion between legacy and modern types.
Usage Examples:
import java.time.*
import java.util.*
// Date -> LocalDateTime -> Date roundtrip
def originalDate = new Date()
def localDateTime = originalDate.toLocalDateTime()
def convertedBackDate = localDateTime.toDate()
println "Date roundtrip: ${originalDate} -> ${localDateTime} -> ${convertedBackDate}"
println "Equal: ${originalDate.time == convertedBackDate.time}" // May differ by milliseconds
// Calendar -> ZonedDateTime -> Calendar roundtrip
def originalCalendar = Calendar.getInstance()
originalCalendar.set(2024, Calendar.DECEMBER, 25, 14, 30, 45)
originalCalendar.set(Calendar.MILLISECOND, 0) // Clear milliseconds for cleaner comparison
def zonedDateTime = originalCalendar.toZonedDateTime()
def convertedBackCalendar = zonedDateTime.toCalendar()
println "Calendar roundtrip preserves values:"
println "Original year: ${originalCalendar.get(Calendar.YEAR)}, converted: ${convertedBackCalendar.get(Calendar.YEAR)}"
println "Original month: ${originalCalendar.get(Calendar.MONTH)}, converted: ${convertedBackCalendar.get(Calendar.MONTH)}"
println "Original day: ${originalCalendar.get(Calendar.DAY_OF_MONTH)}, converted: ${convertedBackCalendar.get(Calendar.DAY_OF_MONTH)}"
// TimeZone handling in conversions
def specificTimeZone = TimeZone.getTimeZone('Asia/Tokyo')
def japanCalendar = Calendar.getInstance(specificTimeZone)
japanCalendar.set(2024, Calendar.DECEMBER, 25, 14, 30, 45)
def japanZoned = japanCalendar.toZonedDateTime()
def backToCalendar = japanZoned.toCalendar()
println "Timezone preserved: ${japanCalendar.timeZone.id} -> ${japanZoned.zone} -> ${backToCalendar.timeZone.id}"Practical approaches for migrating from legacy to modern date/time APIs.
Usage Examples:
import java.time.*
import java.util.*
// Legacy code simulation
class LegacyDateService {
Date createAppointment(Date date, int durationMinutes) {
def calendar = Calendar.getInstance()
calendar.time = date
calendar.add(Calendar.MINUTE, durationMinutes)
return calendar.time
}
boolean isWorkingDay(Date date) {
def calendar = Calendar.getInstance()
calendar.time = date
def dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)
return dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY
}
}
// Modern equivalent using conversions
class ModernDateService {
Date createAppointment(Date legacyDate, int durationMinutes) {
// Convert to modern API, do work, convert back
def localDateTime = legacyDate.toLocalDateTime()
def endDateTime = localDateTime.plusMinutes(durationMinutes)
return endDateTime.toDate()
}
boolean isWorkingDay(Date legacyDate) {
// Convert to modern API for easier day-of-week checking
def dayOfWeek = legacyDate.toDayOfWeek()
return dayOfWeek.isWeekday() // Uses modern extension method
}
}
// Wrapper for gradual migration
class DateWrapper {
private final LocalDateTime dateTime
DateWrapper(Date legacyDate) {
this.dateTime = legacyDate.toLocalDateTime()
}
DateWrapper(LocalDateTime modernDateTime) {
this.dateTime = modernDateTime
}
// Provide both legacy and modern access
Date toLegacyDate() { dateTime.toDate() }
LocalDateTime toModernDateTime() { dateTime }
// Modern functionality
DateWrapper plusDays(int days) {
new DateWrapper(dateTime.plusDays(days))
}
String format(String pattern) {
dateTime.format(pattern)
}
}
// Usage examples
def legacyService = new LegacyDateService()
def modernService = new ModernDateService()
def testDate = new Date()
def appointment1 = legacyService.createAppointment(testDate, 60)
def appointment2 = modernService.createAppointment(testDate, 60)
println "Legacy result: ${appointment1}"
println "Modern result: ${appointment2}"
println "Results equal: ${appointment1.time == appointment2.time}"
// Wrapper usage
def wrapper = new DateWrapper(testDate)
def futureWrapper = wrapper.plusDays(7)
def formatted = futureWrapper.format('yyyy-MM-dd HH:mm:ss')
println "Wrapped date + 7 days: ${formatted}"
println "Back to legacy: ${futureWrapper.toLegacyDate()}"Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-datetime