I have looked at some highly useful methods available in Groovy GDK [1]'s extensions to the Java JDK [2] in blog posts such as Groovy JDK (GDK): File.deleteDir() [3], Groovy JDK (GDK): Text File to String [4], Groovy JDK (GDK): More File Fun [5], Groovy JDK (GDK): String Support [6], and Groovy JDK (GDK): Number Support [7]. In this post, I look at some of the endearing features of Groovy's GDK extensions to the Java JDK java.util.Date [8] and java.util.Calendar [9] classes.
Java's current standard support for dates and times is generally disliked [10] in the Java development community. Many of us look forward to JSR-310 [11] and/or already use Joda Time [12] to get around the shortcomings of Java's treatment of dates and times. Groovy makes working with dates and times a little easier when third-party frameworks are not available or cannot be used.
The Groovy GDK [13] extension of Date [14] provides several new and highly useful methods as shown in the screen snapshot of its documentation [15].
Some of these useful mehtods that I will highlight in this post are clearTime() [17], format(String) [18], getDateString() [19], getTimeString(), parse(String, String) [20], parseToStringDate(String) [21], toCalendar() [22], toTimestamp() [23], and updated(Map) [24]. Many of the other methods listed in the API support Groovy operator overloading [25] and are not highlighted in this post.
Date.clearTime() and Calendar.clearTime()
There are times when one wishes to represent a date only and the time portion of a Date or Calendar is not important (which is exactly why JSR 310 [11] is bringing date-only constructs such as LocalDate [26] to JDK 8). In such cases, Groovy's extension to Date and Calendar make it easy to "clear" the time component. The next code listing demonstrates use of Date.clearTime() followed by a screen snapshot showing that code executed. Note that the clearTime() method [17] mutates the object it acts upon.
/**
* Demonstrates Groovy's GDK Date.clearTime() method. Note that the clearTime()
* method acts upon the Date object upon which it is called, mutating its value
* in addition to returning a reference to that changed object.
*/
def demoClearTime()
{
printTitle("Groovy GDK Date.clearTime()")
def now = new Date()
println "Now: ${now}"
def timelessNow = now.clearTime()
println "Now sans Time: ${timelessNow}"
println "Mutated Time: ${now}"
}
Calendar's clearTime() works similarly as shown in the next code snippet and its accompanying screen snapshot of its execution.
/**
* Demonstrates Groovy's GDK Calendar.clearTime() method. Note that the
* clearTime() method acts upon the Calendar object upon which it is called,
* mutating its value in addition to returning a reference to that changed object.
*/
def demoCalendarClearTime()
{
printTitle("Groovy GDK Calendar.clearTime()")
def now = Calendar.getInstance()
println "Now: ${now}"
now.clearTime()
println "Now is Timeless: ${now}"
}
Date.format and Calendar.format
It is common in Java development to need to display a Date or Calendar in a specific user-friendly format and this is typically accomplished using instances of SimpleDateFormat [29]. Groovy simplifies this process of applying a format to a Date or String with the respective methods Date.format(String) [18] and Calendar.format(String) [30]. Code listings demonstrating each are shown next with each code listing followed by a screen snapshot displaying the executed code.
/**
* Demonstrate how much more easily a formatted String representation of a Date
* can be acquired in Groovy using GDK Date.format(String). No need for an
* explicit instance of SimpleDateFormat or any other DateFormat implementation
* here!
*/
def demoFormat()
{
printTitle("Groovy GDK Date.format(String)")
def now = new Date()
println "Now: ${now}"
def dateString = now.format("yyyy-MMM-dd HH:mm:ss a")
println "Formatted Now: ${dateString}"
}
/**
* Demonstrate how much more easily a formatted String representation of a
* Calendar can be acquired in Groovy using GDK Calendar.format(String). No need
* for an explicit instance of SimpleDateFormat or any other DateFormat
* implementation here!
*/
def demoCalendarFormat()
{
printTitle("Groovy GDK Calendar.format(String)")
def now = Calendar.getInstance()
println "Now: ${now}"
def calendarString = now.format("yyyy-MMM-dd HH:mm:ss a")
println "Formatted Now: ${calendarString}"
}
Date.getDateString(), Date.getTimeString(), and Date.getDateTimeString()
The format methods shown previously allow customized representation of a Date or Calendar and the clearTime methods shown previously allow the time element to be removed from an instance of a Date or Calendar. Groovy provides some convenience methods on Date for displaying a user-friendly date only, time only, or date and time without specifying a format or clearing the time component. These methods print dates and times in the predefined format specified by DateFormat.SHORT [33] (for date portions) and DateFormat.MEDIUM [34] (for time portions). Code listings of each of these methods are shown next and are each followed by screen snapshots of that code being executed.
/**
* Demonstrates Groovy's GDK Date.getDateString() method. Note that this
* method doesn't change the underlying date, but simply presents only the date
* portion (no time portion is presented) using the JDK's DateFormat.SHORT
* constant (which defines the locale-specific "short style pattern" for
* formatting a Date).
*/
def demoGetDateString()
{
printTitle("Groovy GDK Date.getDateString()")
def now = new Date()
println "Now: ${now}"
println "Date Only: ${now.getDateString()}"
println "Now Unchanged: ${now}"
}
/**
* Demonstrates Groovy's GDK Date.getTimeString() method. Note that this
* method doesn't change the underlying date, but simply presents only the time
* portion (no date portion is presented) using the JDK's DateFormat.MEDIUM
* constant (which defines the locale-specific "medium style pattern" for
* formatting a Date).
*/
def demoGetTimeString()
{
printTitle("Groovy GDK Date.getTimeString()")
def now = new Date()
println "Now: ${now}"
println "Time Only: ${now.getTimeString()}"
println "Now Unchanged: ${now}"
}
/**
* Demonstrates Groovy's GDK Date.getDateTimeString() method. Note that this
* method doesn't change the underlying date, but simply presents the date and
* time portions as a String. The date is presented with locale-specific format
* as defined by DateFormat.SHORT and the time is presented with locale-specific
* format as defined by DateFormat.MEDIUM.
*/
def demoGetDateTimeString()
{
printTitle("Groovy GDK Date.getDateTimeString()")
def now = new Date()
println "Now: ${now}"
println "Date/Time String: ${now.getDateTimeString()}"
println "Now Unchanged: ${now}"
}
Date.parse(String, String)
The GDK Date class provides a method Date.parse(String, String) [20] that is a "convenience method" that "acts as a wrapper for SimpleDateFormat [29]." A code snippet and corresponding screen snapshot of the code's output follow and demonstrate this method's usefulness.
/**
* Demonstrate Groovy GDK's Date.parse(String, String) method which parses a
* String (second parameter) based on its provided format (first parameter).
*/
def demoParse()
{
printTitle("Groovy GDK Date.parse(String, String)")
def nowString = "2012-Nov-26 11:45:23 PM"
println "Now String: ${nowString}"
def now = Date.parse("yyyy-MMM-dd hh:mm:ss a", nowString)
println "Now from String: ${now}"
}
Date.parseToStringDate(String)
The GDK Date.parseToStringDate(String) [21] method can be used to obtain an instance of Date from a String matching the exact format put out by the Date.toString() method. In other words, this method can be useful for converting back to a Date from a String that was generated from a Date's toString() method.
Use of this method is demonstrated with the following code snippet and screen snapshot of the corresponding output.
/**
* Demonstrate Groovy GDK's Date.parseToStringDate(String) method which parses
* a String generated by a Date.toString() call, but assuming U.S. locale to
* do this.
*/
def demoParseToStringDate()
{
printTitle("Groovy GDK Date.parseToStringDate(String)")
def now = new Date()
println "Now: ${now}"
def nowString = now.toString()
def nowAgain = Date.parseToStringDate(nowString)
println "From toString: ${nowAgain}"
}
There is one potentially significant downside to the GDK Date.parseToStringDate(String) method. As its documentation states, it relies on "US-locale-constants only."
Date.toCalendar() and Date.toTimestamp()
It is often useful to convert a java.util.Date [8] to a java.util.Calendar [9] or java.sql.Timestamp [40]. Groovy makes these common conversions particularly easy with the GDK Date-provided methods Date.toCalendar [22] and Date.toTimestamp() [23]. These are demonstrated in the following code snippets with their output displayed in corresponding screen snapshots.
/**
* Demonstrates how easy it is to get a Calendar instance from a Date instance
* using Groovy's GDK Date.toCalendar() method.
*/
def demoToCalendar()
{
printTitle("Groovy GDK Date.toCalendar()")
def now = new Date()
println "Now: ${now}"
def calendarNow = now.toCalendar()
println "Now: ${calendarNow} [${calendarNow.class}]"
}
/**
* Demonstrates how easy it is to get a Timestamp instance from a Date instance
* using Groovy's GDK Date.toTimestamp() method.
*/
def demoToTimestamp()
{
printTitle("Groovy GDK Date.toTimestamp()")
def now = new Date()
println "Now: ${now}"
def timestampNow = now.toTimestamp()
println "Now: ${timestampNow} [${timestampNow.class}]"
}
Date.updated(Map) [and Calendar.updated(Map)]
The final convenience method provided by the GDK Date that I'm going to discuss in this post is Date.updated(Map) [24], which its documentation describes as "Support creating a new Date having similar properties to an existing Date (which remains unaltered) but with some fields updated according to a Map of changes." In other words, this method allows one to start with a certain Date instance and acquire another Date instance with the same properties other than changes specified in the provided Map.
The next code listing acquires a new Date instance from an existing Date instance with a few fields updated using the Date.updated(Map) method. The code listing is followed by a screen snapshot of its execution.
/**
* Demonstrate Groovy GDK's Date.updated(Map) with adaptation of the example
* provided for that method in that method's Javadoc-based GDK documentation.
* Note that the original Date upon which updated is invoked is NOT mutated and
* the updates are on the returned instance of Date only.
*/
def demoUpdated()
{
printTitle("Groovy GDK Date.updated(Map)")
def now = new Date()
def nextYear = now[YEAR] + 1
def nextDate = now[DATE] + 1
def prevMonth = now[MONTH] - 1
def oneYearFromNow = now.updated(year: nextYear, date: nextDate, month: prevMonth)
println "Now: ${now}"
println "1 Year from Now: ${oneYearFromNow}"
}
The demonstration shows that the original Date instance does remain unaltered and that a copy with specified fields changed is provided. There is also an equivalent for the GDK Calendar called Calendar.updated(Map) [44].
Conclusion
One of the things I like about Groovy is the GDK extensions to SDK classes. In this post, I looked at how the GDK Date extension [14] of the JDK's Date [8] provides many useful convenience methods that lead to more concise and more readable code.
Original posting available at http://marxsoftware.blogspot.com/ [45] (Inspired by Actual Events)
Links:
[1] http://groovy.codehaus.org/groovy-jdk/
[2] http://www.oracle.com/technetwork/java/javase/7u-relnotes-515228.html
[3] http://marxsoftware.blogspot.com/2009/09/groovy-jdk-gdk-filedeletedir.html
[4] http://marxsoftware.blogspot.com/2009/09/groovy-jdk-gdk-text-file-to-string.html
[5] http://marxsoftware.blogspot.com/2009/09/groovy-jdk-gdk-more-file-fun.html
[6] http://marxsoftware.blogspot.com/2009/09/groovy-jdk-gdk-string-support.html
[7] http://marxsoftware.blogspot.com/2009/09/groovy-jdk-gdk-number-support.html
[8] http://docs.oracle.com/javase/7/docs/api/java/util/Date.html
[9] http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
[10] http://marxsoftware.blogspot.com/2012/03/how-badly-do-we-want-new-java-datetime.html
[11] http://sourceforge.net/apps/mediawiki/threeten/index.php?title=ThreeTen
[12] http://joda-time.sourceforge.net/
[13] http://groovy.codehaus.org/GDK Extensions to Object
[14] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html
[15] http://marxsoftware.blogspot.com/2011/02/groovy-javadoc-based-api-documentation.html
[16] http://3.bp.blogspot.com/-GmRU2AHF9wk/UL2aDCnbezI/AAAAAAAADyo/1oBObS56ECA/s1600/groovyGdkDateApiGroovyDoc.png
[17] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#clearTime()
[18] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#format(java.lang.String)
[19] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#getDateString()
[20] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#parse(java.lang.String, java.lang.String)
[21] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#parseToStringDate(java.lang.String)
[22] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#toCalendar()
[23] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#toTimestamp()
[24] http://groovy.codehaus.org/groovy-jdk/java/util/Date.html#updated(java.util.Map)
[25] http://groovy.codehaus.org/Operator Overloading
[26] http://marxsoftware.blogspot.com/2012/10/javaone-2012-from-instants-to-eras.html
[27] http://2.bp.blogspot.com/-xRmJZOs5CIM/UMGOVwL_VSI/AAAAAAAADzE/AKCgih1MrQY/s1600/01_gdkDateClearTime.png
[28] http://3.bp.blogspot.com/--i46_R-yiyE/UMGOsw3IvLI/AAAAAAAADzQ/f5Feu3oHP1E/s1600/11_gdkCalendarClearTime-annotated.png
[29] http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
[30] http://groovy.codehaus.org/groovy-jdk/java/util/Calendar.html#format(java.lang.String)
[31] http://3.bp.blogspot.com/-VWwqRchnatg/UMGQf9MgI3I/AAAAAAAADzc/Ks37fZEDrGE/s1600/05_gdkDateFormat.png
[32] http://1.bp.blogspot.com/-pv7aSr1RUQU/UMGQleS4RHI/AAAAAAAADzo/MSCaL7eZxfI/s1600/12_gdkCalendarFormat-annotated.png
[33] http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#SHORT
[34] http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#MEDIUM
[35] http://3.bp.blogspot.com/-iC-lKe6O_-Y/UMGSohw9qNI/AAAAAAAADz0/Dt32q_a2-fQ/s1600/02_gdkDateGetDateString.png
[36] http://1.bp.blogspot.com/-7O1JJzHbAyM/UMGSyzCShXI/AAAAAAAAD0A/nwI-3GBcvhk/s1600/03_gdkDateGetTimeString.png
[37] http://2.bp.blogspot.com/-KFcgA4vPaJo/UMGS9_QXjTI/AAAAAAAAD0M/47NfwNSJaAI/s1600/04_gdkDateGetDateTimeString.png
[38] http://1.bp.blogspot.com/-xDxZP9Ik0Bk/UMgiBMbKSPI/AAAAAAAAD0s/nYPSqCfTRH4/s1600/06_gdkDateParse.png
[39] http://2.bp.blogspot.com/-2_imR-BgzDs/UMgjKVf6YsI/AAAAAAAAD08/w7vHJ7riTW8/s1600/07_gdkDateParseToStringDate.png
[40] http://docs.oracle.com/javase/7/docs/api/java/sql/Timestamp.html
[41] http://3.bp.blogspot.com/-mZKzi2zmG98/UMgk-yZloJI/AAAAAAAAD1I/taHQfGyq8uI/s1600/08_gdkDateToCalendar.png
[42] http://4.bp.blogspot.com/-YFsGRGLF3Jw/UMglHpXPR8I/AAAAAAAAD1U/vFL1P5veZsI/s1600/09_gdkDateToTimestamp.png
[43] http://3.bp.blogspot.com/-ak3lVwTTlYU/UMgmXFsgUyI/AAAAAAAAD1g/RuXUW1i1-A4/s1600/10_gdkDateUpdatedMap.png
[44] http://groovy.codehaus.org/groovy-jdk/java/util/Calendar.html#updated(java.util.Map)
[45] http://marxsoftware.blogspot.com/