Monday, April 3, 2017

5 Reasons Why Java's old Date and Calendar API was Bad

If you have been programming in Java for a couple of years then you may know that how bad was Java's Date and Calendar API was, I mean the java.util.Date and java.utill.Calendar was badly designed. Though Java has corrected it's mistake by introducing a brand new, shiny Date and Time API, not many Java developers are using it yet. In a bit to motivate you to use new Date and Time API from Java 8, I am going to list down a couple of reasons why Java's Date and Calendar class has been criticized so much in the past.  These points are also important to know from the Interview point of view because as an experienced Java programmer, it is expected from you to know the shortcomings of existing API and how new API solves those problems.


1) It's not intuitive
Look at the following example, here a user simply wants to create a Date object for 25th December 2017, 8.30 at night, do you think this is the right way to represent that date in Java?

Date date = new Date(2017, 12, 25, 20, 30);

Well, even though it is looking alright, it is not correct. The above code contains two bugs, which is not at all intuitive. If you are using the java.util.Date class then you must know that year starts from 1900 and month starts from zero i.e. January is the zeroth month, not the first.

Here is the right way to declare same date in Java:

int year = 2017 - 1900;
int month = 12 - 1;
Date date = new Date(year, month, 25, 20, 30);

You must remember that January is 0, December is 11 and Date use years from 1900.



2) Timezones
Prior to JDK 8, Java uses String to represent TimeZone, a very bad idea. Ideally, they should have defined a constant or Enum instead of allowing the user to pass String. Since String lacks compiler checks, it opens a door for spelling mistakes and silly human errors. Java's naming convention with timezones also doesn't help. Look at the following example, here I am trying to get TimeZone object for NewYork, doesn't it look all right?

TimeZone zone = TimeZone.getInstance("America/NewYork");

Unfortunately, it's not correct. It contains a silly but hard to find a mistake, the time zone string is wrong here. Correct timezone String is "America/New_York" as shown in the following example

TimeZone zone = TimeZone.getInstance("America/New_York");

Had they have used Enum, these would have been flagged by the compiler or your IDE as soon as you typed. Another example of this kind of gotcah is "Asia/Hong_Kong", so be careful while using those timezones in Java.



3) Calendars
The Calendar class is also not very user-friendly or intuitive in Java. You just cannot apply common sense or predictive knowledge. For example in the following code, we are trying to create a Calendar object for a date in a particular timezone, It will not show any compile time error but it will not work as you expect.

Calendar cal = new GregorianCalendar(date, zone);

Right way of using Calandar object with date and timezone is as following :

Calendar cal = new GregorianCalendar(zone);
cal.setTime(date);

So, if you haven't used Calendar API from a long time, there is no chance you can get it right after that.

Here is another example of how intuitive new Date and Time API has as compared to old Date and Calendar API:

Java Date and Calendar vs Date and Time API

If you are interested on more examples of old and new Date and Time API like this, I suggest exploring a good Java 8 book e.g. Java SE 8 for Impatient by Cay S. Horstmann. One of my favorite author, who explains the details which matter most.


4) Formatting Dates
Formatting dates are one of the most common tasks while using Dates in Java. Given multi-threading is the core strength of Java, one should expect that their core classes e.g. String, Integer or Date should work seamlessly in concurrent applications. Java designers made a good job with String and Integer but did a really poor job with Date, formatting date was very tricky in Java. One of the most useful utility to format dates, SimpleDateFormat was not thread-safe.

DateFormat fm = new SimpleDateFormat("HH:mm Z");
String str = fm.format(cal);

This example contains a couple of bugs, first, you have to set Timezone for DateFormat class and second, you cannot pass a Calendar object to format method, you can only pass a java.util.Date object, hence you need to first convert Calendar to Date in Java and then pass it to the format() method as shown below:

Here is the right way of using Calendar class with SimpleDateFormat in Java.

DateFormat fm = new SimpleDateFormat("HH:mm Z");
fm.setTimeZone(zone);
Date calDate = cal.getTime();
String str = fm.format(calDate);

You must remember that Calendar cannot be formatted in Java and DateFormat class is not thread-safe so it cannot be used in multi-threaded Java application without proper synchronization. This issue has been addressed in Java 8 by making DateFormatter immutable and thread-safe. If you want to learn more, you can also read Java 8 in Action by Roul-Gabrial Urma and team.

5 Reasons Why Java's old Date and Caledar API was Bad



5) Mutable
This is IMHO biggest mistake Java designers has made in the JDK. Unlike String or Integer, Date is mutable. It's possible for you to pass a client to get reference of Date and change it without owner of that Date class knowing, as shown in below example

Persons p = new Person();

Date birthDay = p.getBirthDay();
birthDay.setTime();

Now that person will have a different birth date, so bad. That's why whenever you have to return Date from your class, you must return a new Date object or clone, you should never return the original Date object, it breaks the Encapsulation of class.


If these reasons were not enough, the SQL Date/Time/Timestamp also extends the java.util.Date class and violates the Liskov Substitution Principle, which means if a method expects the java.util.Date object then you cannot pass the java.sql.Date, java.sql.Time, or java.sql.Timestamp class, even though they are a subclass of java.util.Date, hence you need to convert util date to SQL date and vice-versa while passing around your application's DAO layer and Business layer.


That's all on why Java's Date, Calendar, and Time classes suck before Java 8. It's important to learn from experience and that's what Java designers have done that. For you, a Java developer also its important to know shortcomings of Java's old Date and Calendar API to appreciate and acclaim greatness of Java 8's new Date and Time API.

If you want to learn new features of Java 8 and new Date and Time API, I suggest reading Java SE 8 for Impatient by Cay S. Horstmann, one of the best books to learn Java 8 quickly. 

Further Reading
Java Fundamentals, Part 1 and 2
Core Java For the Impatient - Covers Java SE 8
Java Fundamentals: The Java Language


1 comment :

Anonymous said...

Not to forget the memory consumption of Calender. It's more then 400 bytes just for representing one instance of a date.

Post a Comment