DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Harnessing the Power of SIMD With Java Vector API
  • Optimizing Java Applications: Parallel Processing and Result Aggregation Techniques
  • How To Get Cell Data From an Excel Spreadsheet Using APIs in Java
  • Commonly Occurring Errors in Microsoft Graph Integrations and How To Troubleshoot Them (Part 4)

Trending

  • Automatic Code Transformation With OpenRewrite
  • AI, ML, and Data Science: Shaping the Future of Automation
  • Java Virtual Threads and Scaling
  • A Complete Guide to Modern AI Developer Tools
  1. DZone
  2. Coding
  3. Languages
  4. Groovy Additions to the Java 8 Date/Time API

Groovy Additions to the Java 8 Date/Time API

Groovy now has extension methods and overloaded operators for the Java 8 Date/Time API types. Let's see them in action and how they can make coding easier.

By 
Joe Wolf user avatar
Joe Wolf
·
May. 30, 18 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
22.0K Views

Join the DZone community and get the full member experience.

Join For Free

After suffering through java.util.Date and Calendar for many years, Java 8's Date/Time API was a welcome and groovy addition to Java SE in and of itself. Groovy's upcoming 2.5 and 3.0 releases, however, make it even groovier.

To follow along with the examples, you will need to download either Groovy 2.5-rc1 or Groovy 3.0-alpha-2 (or later releases in those 2.5 or 3.0 lines). Date/Time API-related features are not available in Groovy 2.6 as that version is intended to be a Groovy 3.0 backport for Java 7, which predates the Date/Time API.

Creating Date/Time Instances

Groovy's great operability with Java means that the on and now factory methods of the various java.timer types can certainly be used to create instances, but there are now some Groovy-specific alternatives.

Conversion from Legacy Types

Creating a new java.util.Date in Groovy is highly convenient as the java.util package is always imported; a developer simply needs to write new Date(). To encourage use of the Java 8 Date/Time types while accomodating this habit, Groovy provides a number of extension methods on java.util.Date and java.util.Calendar that convert these legacy instances to their modern equivalents.

def date = new Date().toLocalDate()
def time = new Date().toLocalTime()
def datetime = new Date().toLocalDateTime()

def offsetDateTime = new Date().toOffsetDateTime()
def offsetTime = new Date().toOffsetTime()
def zonedDateTime = new Date().toZonedDateTime()

def monthDay = new Date().toMonthDay()
def yearMonth = new Date().toYearMonth()
def year = new Date().toYear()


Creating Java 8 Date/Time instances through this approach may be convenient (if sticking with def, you may not even need to explicitly import java.time.*), but it does sacrifice some precision, as legacy types do not support nanoseconds.

It's also worth noting that the Java 8 Date/Time data types have toDate() and toCalendar() methods for converting to their java.util equivalents... but you would never deliberately want to use them, right?

Left-Shift Composition

Groovy overrides the << operator to allow the creation of broader date/time type instances through composition of narrower types. For example, you can create a LocalDateTime instance from a LocalDate and a LocalTime, or create an OffsetDateTime from a LocalDateTime and a ZoneOffset.

def year = Year.of(2018)
def yearMonth = Month.MAY << year

def localDate = yearMonth << 21
def localDateTime = LocalTime.now() << localDate

def offsetDateTime1 = localDateTime << ZoneOffset.ofHours(-5)
def offsetDateTime2 = localDate << OffsetTime.now()

def zonedDateTime = localDateTime << ZoneId.systemDefault()


The order of the operands does not matter.

Parsing Strings

One of the more common ways of generating date/time instances is by parsing a String. Groovy adds convenience parsemethods to the Java 8 Date/Time types that accept two String arguments: the value to parse and the format the of the value. These new methods spare you from explicitly creating a DateTimeFormatter instance.

def someDate = LocalDate.parse('2012/11/23', 'yyyy/MM/dd')


Veteran Groovy developers take note: the ordering of the String arguments on the venerable Date.parse() method is format-to-use first, value-to-parse second. The new parse methods have the arguments reversed for consistency with the Java 8 Date/Time API's parse methods, which take a DateTimeFormatter in the second argument.

Durations and Periods

The right shift operator >> is overloaded in Groovy for creating Period or Duration instances from Temporal types. The operator can be read as "through," as in "May 1st, 2018 through May 9th, 2018."

Period p = LocalDate.of(2018, Month.MAY, 1) >> LocalDate.of(2018, Month.MAY, 9)
assert p.days == 8

Duration d = LocalTime.of(0, 0, 0) >> LocalTime.of(0, 0, 59)
assert d.seconds == 59


Manipulating Values

Now that we have created date/time type instances, the next thing we may want to do with them is manipulate their values. Unlike java.util.Date and Calendar, date/time types are immutable. So even though it may look as if the instances' values are being changed, new instances are being created behind the scenes which bear the changed values.

Arithmetic Operations

The + and - operators can be used to add/subtract TemporalAmount (i.e. Duration and Period) or integer values. For integers, the default unit depends on the data type being manipulated:

Data Type Unit
LocalDate ChronoUnit.DAYS
YearMonth ChronoUnit.MONTHS
Year ChronoUnit.YEARS
all others ChronoUnit.SECONDS


As an example:

// Legacy API way
use (groovy.time.TimeCategory) {
    def twoDaysFromToday = new Date() + 2 // days by default, even without TimeCategory
    def monthAndTwoDaysFromToday = twoDaysFromToday + 1.month
    def threeSecondsAgo = new Date() - 3.seconds
}

// Date/Time API way
def twoDaysFromToday = LocalDate.now() + 2

def monthAndTwoDaysFromToday = twoDaysFromToday + Period.ofMonths(1)

def threeSecondsAgo = LocalDateTime.now() - 3


Period supports +, -, and * for multiplication. Duration supports +, -, *, and division with /.

def period = Period.ofMonths(2) * 2 
assert period.months == 4

def duration = Duration.ofSeconds(10) / 5
assert duration.seconds == 2


Incrementing and Decrementing

Given that the + and - operators work for the date/time types, it's no surprise that ++ and -- work as well.

Furthermore, because these operators exist and because the various date/time types implement Comparable, date/time types can be used within ranges. Consider the following code that counts the number of Mondays in 2018.

def firstDay2018 = LocalDate.of(2018, Month.JANUARY, 1)
def lastDay2018 = firstDay2018 + Period.ofYears(1) - 1  // add a year, subtract one day

def numberOfMondaysIn2018 = (firstDay2018..lastDay2018).collect { date -> date.dayOfWeek }
                                                       .findAll { dayOfWeek -> dayOfWeek == DayOfWeek.MONDAY }
                                                       .size()


Formatting Dates

After creating and manipulating date/time instances, the next natural thing to do is format them as Strings. Groovy provides some additional features for this purpose.

Overridden Format Methods

As with parse, Groovy adds another overridden format(String pattern) method that spares developers from having to explicitly construct a DateTimeFormatter instance.

// Legacy API way
new Date().format('MM/dd/yyyy')

// Date/Time API way
LocalDate.now().format('MM/dd/yyyy')


Alternatively, instead of passing a pattern as a String, you can call format(FormatStyle style), which is Locale-specific.

import java.time.format.FormatStyle

assert LocalTime.of(2,30).format(FormatStyle.SHORT) == '2:30 AM'


dateString, timeString, and dateTimeString

Groovy has added getDateString(), getTimeString(), and getDateTimeString() methods to the new date/time type akin to those long available for java.util.Date but with two important distinctions:

  1. The methods are not avaiable on types where they are not applicable (e.g. there is no getTimeString() method for LocalDate).
  2. The formatting performed by these methods is based on ISO DateTimeFormatter instances and is consequently not locale-specific. For example, new Date().dateString yields 5/23/18 on my en_US runtime, but LocalDateTime.now().dateString produces 2018-05-23.

Conclusion

Groovy now has extension methods and overloaded operators for the Java 8 Date/Time API types, similar to what is available for java.util.Date. There are even more features than what I've discussed here, so download a copy of 2.5 or 3.0 and check out the groovydocs and documentation.

API Groovy (programming language) Java (programming language) Data Types

Opinions expressed by DZone contributors are their own.

Related

  • Harnessing the Power of SIMD With Java Vector API
  • Optimizing Java Applications: Parallel Processing and Result Aggregation Techniques
  • How To Get Cell Data From an Excel Spreadsheet Using APIs in Java
  • Commonly Occurring Errors in Microsoft Graph Integrations and How To Troubleshoot Them (Part 4)

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: