Monday, April 2, 2012

When Dates go wild

It's really easy to get the dates wrong if you don't have a central place for date/time functions in your application, especially if you have a multi-tiered application where you can have different dates in the database server, application server, client side, etc (Let alone situations when your database or application is clustered on different servers).

It is a good practice to have a central place/strategy to provide current date when one is required, but there is no simple answer to where this central place should be. Whatever you come up with, you need to make sure that no one goes around it and do their own new Date(). It is really easy to avoid such a thing with a custom Checkstyle check, as you can see here:

import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class CentralPlaceForDateConstruction extends Check
{
private final static Set<String> PROHIBITED_CLASS_NAMES =
new HashSet<String>(Arrays.asList(
"Date", "GregorianCalendar",
"DateTime", "BaseDateTime", "MutableDateTime", "DateMidnight"));

public int[] getDefaultTokens()
{
return new int[]{TokenTypes.EXPR};
}

public void visitToken(DetailAST ast)
{
if (ast.getChildCount() == 1 && ast.branchContains(TokenTypes.LITERAL_NEW))
{
DetailAST newKeyworkAST = ast.findFirstToken(TokenTypes.LITERAL_NEW);
if (newKeyworkAST == null)
return;
DetailAST createdClassAST = newKeyworkAST.findFirstToken(TokenTypes.IDENT);
if (createdClassAST == null)
return;
if (PROHIBITED_CLASS_NAMES.contains(createdClassAST.getText()))
{
if (createdClassAST.getNextSibling().getType() != TokenTypes.ARRAY_DECLARATOR)
log(createdClassAST.getLineNo(),
"Use the central place for Date creation.");
}
}
}
}


Please see here for more information on developing a custom check, and probably here if you want to integrate your work with Maven.

Don't forget to use a suppression filter to ignore this for the central date/time manipulation classes.

P.S. I stumbled upon this on JodaTime's homepage: The 'J' in 'Joda' is pronounced the same as the 'J' in 'Java'. The project is not capable of wielding a light saber and is thus pronounced differently.