Wednesday, 19 December 2012

When you need to do some serious work with dates

In the Java course, which will hopefully be available on VirtualPairProgrammers.com at around the end of March, we do some basic date manipulation using the GregorianCalendar class. I explain that the Date class within java has problems, which is why many of the methods are depreciated. I don't go into detail about what is wrong with it, but there's a great post about that here:

http://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api

GregorianCalendar is acceptable for basic date usage although it's not completely intuitive and doesn't really cut the mustard if you need to do some serious date manipulation.

Something we do within the course is work out a date in the future by adding a fixed number of days to today's date - we want to create a variable called DueDate and set it's value to, say, 14 days after today. So if today is the 4th March, then DueDate should be equal to 18th March.

Programatically the code to do this, using the GregorianCalendar class looks like this:

public void CalculateDueDate() {
GregorianCalendar gc = new GregorianCalendar();
gc.add(Calendar.DAY_OF_MONTH, 14);
Date dueDate = gc.getTime();
System.out.println(dueDate);
}


This code is reasonably straight forward - we create a new instance of the GregorianCalendar class (which by default will have an initial value of the date and time when it is instantiated) and then call it's add method to move it's value on by 14 days.

What's odd about this code, at least to me, is the use of DAY_OF_MONTH to specify that it is 14 days we want to day (days as opposed to months or years). It's odd because DAY_OF_MONTH has a specific meaning - and yet we could use this code to validly add 41 days, even though no month has more than 41. Interestingly DAY_OF_WEEK will also work in it's place, as will DAY_OF_YEAR. Now these three field values are definitely NOT the same, but the GregorianCalendar class is "clever enough" to know how to perform an add correctly, when any one of these fields is provided as the first parameter.

This leaves most programmers feeling a little uncomfortable - surely it would make more sense for the add function to take a value of calendar.DAY - but this field doesn't exist. There are fields for year, month, hour, minute and second, so this missing DAY field really doesn't feel comfortable.

Now this isn't the only reason to dump the GregorianCalendar class in favour of a nicer alternative - in fact most people would say I have gone off on a tangent, and some of the bigger issues include the lack of methods like .getMonth(). But this is a good enough one for me to say it's worth spending some time looking at JodaTime.

Now JodaTime isn't the only alternative set of date and time classes available for Java but I believe it's one of the most popular - and for good reason. The documentation for JodaTime library which can be found at http://joda-time.sourceforge.net/index.html is simply first class. If you want to see what I mean, take a look at their chronology pages. The detail they go into about the Gregorian and Julian calendars, their combination into GregorianJulian and the ISO8601 format is fascinating.

So before we can use JodaTime we need to install it - the process is straightforward - download one of the distribution files, unzip the contents, and then add the joda-time-version.jar file as an external file to you project's build path.

Using JodaTime our example above becomes:
public void CalculateDueDate() {
DateTime dt = new DateTime();
DateTime dueDate = dt.plusDays(14);
System.out.println(dueDate);
}


The .plusDays function is really nice - it's completely clear what it does, and straight forward to use.

I'll finish this blog post with one exceptionally nice feature of Joda time -the ease in formatting dates for output. In the UK it's normal to display dates in the format day/month/year. To amend my code to do that, I can specify a format in the .toString method of the DateTime class. All I need to do is amend my final line to:

System.out.println(dueDate.toString("dd/MM/yyyy"));


There's lots more to the JodaTime class but I hope you'll see that it really is an easy to use, reliable, time and date management library. Just play with it for half an hour and you'll wonder how you ever managed without it!