Dangerous can be dating in java , joda and sonar to the rescue!

Don’t use java built-in classes, use jodatime and enforce this rule with sonar !

Don’t use java built-in classes

How many bugs in 5 lines of code ?

Date date = new Date(2007, 12, 13, 16, 40);
TimeZone zone = TimeZone.getInstance("Europe/Bruxelles");
Calendar cal = new GregorianCalendar(date, zone);
DateFormat fm = new SimpleDateFormat("HH:mm Z");
String str = fm.format(cal);

Just 6 bugs !

int year = 2007 - 1900;
int month = 12 - 1;
Date date = new Date(year, month, 13, 16, 40);
TimeZone zone = TimeZone.getInstance("Europe/Brussels");
Calendar cal = new GregorianCalendar(zone);
cal.setTime(date);
DateFormat fm = new SimpleDateFormat("HH:mm Z");
fm.setTimeZone(zone);
Date calDate = cal.getTime();
String str = fm.format(calDate);

If you want deeper explanations see this [presentation]

java.util.Date issues

  • From JDK1.0
  • Uses two digit years (from 1900)
  • January is 0, December is 11
  • Should have been immutable
  • Most methods deprecated in JDK1.1
  • Uses milliseconds from 1970 representation

java.util.Calendar issues

  • From JDK1.1
  • Uses subclasses for different calendar systems
  • January is 0, December is 11
  • Should have been immutable
  • Uses dual representation internally
    • value for each field
    • milliseconds from 1970 representation
  • Odd performance and bugs

java.util.DateFormat issues

  • Pattern based date formatting
  • “dd MMM yyyy”
  • Requires Date object
  • Not thread-safe : see rule findbugs : Multithreaded correctness – Call to static DateFormat
  • Not especially fast
  • Sun RFE to make thread-safe ignored

SQL – java.util.sql.Date, Time, Timestamp issues

Subclass java.util.Date

  • Date extends Date (!)
  • Time extends Date (!)
  • Override superclass to block methods (throws Exception)
  • Timestamp adds nanoseconds
  • equals() broken
  • All the problems of java.util.Date and more
  • timezone problem new Time(long)

Avoid millis manipulation and let’s use Jodatime !

when playing with java.util.Date you end up doing calculation in millis

int days = 40;
Date now = new Date();
long nowMillis = now.getTime();
Timestamp nowTimestamp = new Timestamp(nowMillis);
long future = 3600 * 24 * days * 1000;
Timestamp expiryTimestamp = new Timestamp(nowMillis + future);
System.out.println("nowTimestamp " + nowTimestamp);
System.out.println("expiryTimestamp " + expiryTimestamp);

this last code sample contains a bug… int vs long for days !

see this explaination the expiryTimestamp is before the nowTimestamp for “large days count”

nowTimestamp 	2011-02-04 12:45:40.381
expiryTimestamp 2011-01-25 19:42:53.085

now let’s write the same code with joda time

DateTime nowTimestamp2 = new DateTime();
System.out.println("nowTimestamp    " + nowTimestamp2);
System.out.println("expiryTimestamp " + nowTimestamp2.plusDays(days));

it’s more readable… and most important it return the correct value 😉

nowTimestamp 	2011-02-04T12:45:40.443+01:00
expiryTimestamp 2011-03-16T12:45:40.443+01:00

Sonar to the rescue

sonar can detect these issues :

  • Multithreaded correctness – Call to static Calendar
  • Multithreaded correctness – Call to static DateFormat

to fix them with jodatime let’s use the DateTimeFormat.

fmt=DateTimeFormat.forPattern("MMMM, yyyy");
DateTime datetime = fmt.parseDateTime(duedate);

this one is threadsafe and can be static and final field. or use the toString

datetime.toString("dd:MM:yy");

but the step further is to banish jdk date from your code base !
To do so, let’s define sonar architectural constraint like

  • Arch : avoid java.util.GregorianCalendar
  • Arch : avoid java.util.Date
  • Arch : avoid java.text.SimpleDateFormat
  • Arch : avoid java.sql.Timestamp
  • Arch : avoid java.sql.Date

to banish jdk dates from your model, you may implement hibernate usertype, jaxb adapter,…

,

  1. #1 by prabhakaran on April 14, 2012 - 11:45 am

    Great work dude. The presentation is not found in your web page.

  2. #4 by Phil on October 12, 2017 - 2:25 pm

    Has anyone benchmarked the difference in performance between using the EqualsBuilder and writing equals with short-cut operators? Is the EqualsBuilder’s code simple enough for inlining and would this actually result in short-cuts being generated? I know, I know… I could go try it for myself. I’m being lazy. But still, is it worth thinking about? Equals and comparisons (both of which have builders) are pretty fundamental to a lot of programs and are often used in loops of various forms.

  3. #5 by mestachs on May 29, 2018 - 5:34 pm

    Another great piece on how time is hard to deal with : https://zachholman.com/talk/utc-is-enough-for-everyone-right

  1. Sonar Rules ! « Don't Make the Same Mistake Twice
  2. Through the eyes of sonar: Immutable Objects. « Don't Make the Same Mistake Twice
  3. Through the eyes of sonar: recap. | Don't Make the Same Mistake Twice

Leave a comment