Groovy's date and time features build upon Java's. For Java versions through to Java 6, this means working with the following key classes:
| Class | Description |
|---|---|
| Date | Represents a discrete point in time |
| Calendar | This is the parent class for calendars and has some useful constants and a static factory for creating calendars. Calendars know about fields like month, day, year and time. |
| DateFormat | Used for parsing and generating string versions of dates and times |
The date and calendar classes belong to the java.util package which Groovy automatically imports, so you can use them straight away without having to worry about imports.
To these classes, Groovy adds a few enhancements plus a category class for writing pretty time and date DSLs:
| Class | Description |
|---|---|
| TimeCategory | Allows you to write human friendly date manipulation expressions |
Here is a simple example of using Date:
which will produce output like this:
Fri Sep 26 19:23:30 EST 2008
Though we don't normally recommend it (see below), there is a child class of Calendar called GregorianCalendar which you can use directly as follows:
def christmas = new GregorianCalendar(2008, Calendar.DECEMBER, 25)
println christmas.time
which will produce output like this:
Thu Dec 25 00:00:00 EST 2008
You can also combine this with static imports as follows:
import static java.util.Calendar.* def newyears = new GregorianCalendar(2009, JANUARY, 1) println newyears.time
which will produce output like this:
Thu Jan 01 00:00:00 EST 2009
But the preferred approach to creating calendars involves calling the getInstance static factory method (shown below using the property access syntax, i.e. instance). This means that the specific details of the calendar system we are using (gregorian for most of us) doesn't clutter up our code. The example below creates a calendar and illustrates how you would set the time zone using short and long time zone values:
newyears = Calendar.instance newyears.set 2009, JANUARY, 1 newyears.timeZone = TimeZone.getTimeZone("America/Los_Angeles") newyears.timeZone = TimeZone.getTimeZone("UTC")
Calendars can be converted to dates using the getTime method (perhaps it should have been called getDate). And dates can be converted to a long milliseconds value using getTime. The returned value represents the time elapsed in milliseconds since January 1, 1970 00:00:00 GMT. Examples of these methods are shown below:
now = Calendar.instance println 'now is a ' + now.class.name date = now.time println 'date is a ' + date.class.name + ' with value ' + date millis = date.time println 'millis is a ' + millis.class.name + ' with value ' + millis
which will produce output like this:
now is a java.util.GregorianCalendar date is a java.util.Date with value Sat Sep 27 09:36:47 EST 2008 millis is a java.lang.Long with value 1222472207348
Working back the other way is just as easy. Dates have a constructor which takes a long millisecond value and calendars have a setTime method which takes a date:
date = new Date(millis)
now.time = date
Groovy also allows you to perform simple arithmetic with dates as illustrated here:
def newYearsEve = newyears.time - 1
println newYearsEve
def boxingDay = christmas.time + 1
println boxingDay
// or normal Java arithmetic to convert milliseconds to days
def daysBetween = (newYearsEve.time - boxingDay.time) / (24 * 60 * 60 * 1000)
println daysBetween
which will produce output like this:
Wed Dec 31 00:00:00 EST 2008 Fri Dec 26 00:00:00 EST 2008 5
You can also work with get and set operations for calendars or index operations on dates as illustrated here:
def nowCal = Calendar.instance y = nowCal.get(YEAR) Date nowDate = nowCal.time m = nowDate[MONTH] + 1 d = nowDate[DATE] println "Today is $d $m $y" nowCal.set DATE, 1 nowCal.set MONTH, FEBRUARY println "Changed to $nowCal.time"
which will produce output like this:
Today is 26 9 2008 Changed to Fri Feb 01 23:05:20 EST 2008
This mechanism also lets you find out other information about calendars (uses Groovy 1.6 multiple/tuple assignment syntax):
cal = Calendar.instance
cal.set 1988, APRIL, 4, 0, 0, 0
date = cal.time
def (doy, woy, y) = [DAY_OF_YEAR, WEEK_OF_YEAR, YEAR].collect{ date[it] }
println "$date is day $doy and week $woy of year $y"
which will produce output like this:
Mon Apr 04 00:00:00 EST 1988 is day 95 and week 15 of year 1988
You can also work with Groovy ranges:
def holidays = boxingDay..newYearsEve
println holidays.size()
println today in holidays
println holidays.collect{ it.toString()[0] }
which will produce output like this:
6 false [F, S, S, M, T, W]
You can print dates using DateFormat and SimpleDateFormat:
import java.text.DateFormat
def plainFormatter = DateFormat.instance
println plainFormatter.format(today)
which will produce output like this:
26/09/08 22:07
And combine with locales if needed:
import static java.text.DateFormat.* import static java.util.Locale.* [ITALY, FRANCE, GERMAN].each { loc -> println getDateInstance(FULL, loc).format(newyears.time) }
which will produce output like this:
giovedì 1 gennaio 2009 jeudi 1 janvier 2009 Donnerstag, 1. Januar 2009
This example uses SimpleDataFormat in combination with some additional calendar methods for adjusting dates:
import java.text.SimpleDateFormat printCal = {cal -> new SimpleDateFormat().format(cal.time)} cal = Calendar.instance cal.set 2000, JANUARY, 1, 00, 01, 0 assert printCal(cal) == '1/01/00 00:01' // roll minute back by 2 but don't adjust other fields cal.roll MINUTE, -2 assert printCal(cal) == '1/01/00 00:59' // adjust hour back 1 and adjust other fields if needed cal.add HOUR, -1 assert printCal(cal) == '31/12/99 23:59'
You can input dates using DateFormat or SimpleDateFormat:
Date d1 = getDateTimeInstance(MEDIUM, LONG).parse("25/12/2008 15:33:33") println d1 Date d2 = new SimpleDateFormat("yyyy-MMM-dd").parse("2008-DEC-25") println d2
which will produce output like this:
Thu Dec 25 15:33:33 EST 2008 Thu Dec 25 00:00:00 EST 2008
Groovy also has a Time Category class which gives you DSL style syntax for manipulating dates. Here is an example:
import org.codehaus.groovy.runtime.TimeCategory now = new Date() println now use(TimeCategory) { footballPractice = now + 1.week - 4.days + 2.hours - 3.seconds } println footballPractice
which will produce output like this:
Sat Sep 27 10:00:12 EST 2008 Tue Sep 30 12:00:09 EST 2008
With Groovy 1.6 and above you can also use the mixin notation:
Integer.metaClass.mixin TimeCategory
Date.metaClass.mixin TimeCategory
footballPractice = 1.week.from.now - 4.days + 2.hours - 3.seconds
println footballPractice
We have already know that we can get the current time using a date or calendar. If we need the current time in milliseconds we can get it from the time property. But, you can also access the current time in milliseconds directly:
println System.currentTimeMillis()
which will produce output like this:
1222480762098
This method is convenient if we want to time how long some code might take to execute, e.g.:
// ranges normally unmodifiable, so make a list copy def reversedNumbers = (10000..1).toList() // check size and first few elements println reversedNumbers.size() println reversedNumbers[0..5] // now perform the operation we want to time def before = System.currentTimeMillis() reversedNumbers.sort() def after = System.currentTimeMillis() // check first few elements println reversedNumbers[0..5] println "Sorting took ${after-before} ms"
which will produce output like this:
[10000, 9999, 9998, 9997, 9996, 9995] 10000 [1, 2, 3, 4, 5, 6] Sorting took 16 ms
If you need higher precision than milliseconds, and you have a recent version of Java, you can use:
println System.nanoTime()
which will produce output like this:
828923218382504
If you modifiy the above timing example to use nanotime, your output from running the example would finish with something like:
Sorting took 12255748 ns
Note that nanoTime implementations on some platforms may have limitations. You should check out how it works on your system before relying on its accuracy. On multiprocessor machines, you may find it fixes issues but raises other issues compared with currentTimeMillis. You may also find the call itself has different resource implications compared to currentTimeMillis.
You can also do simple scheduling with Java's Timer classes.
cal = Calendar.instance cal.roll MINUTE, 1 def timer = new Timer(true) def task = { println 'Background Task Done' } timer.schedule task as TimerTask, cal.time
which will produce output like this (about one minute after executing the script):
Background Task Done
Copyright (c) 2008 Paul King. All rights reserved.