Wednesday, September 29, 2021

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 a 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 the existing API and how new API solves those problems.


1. It's not intuitive

Look at the following example, where 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.

Btw, If you are new to the Java world then I also recommend you go through The Complete Java MasterClass on Udemy to learn Java in a better and more structured way. This is one of the best and up-to-date courses to learn Java online.




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 the TimeZone object for New York, 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 mistake, the time zone string is wrong here. The 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 gotcha is "Asia/Hong_Kong", so be careful while using those timezones in Java.



3. Calendars are Tricky and Errorprone

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);

The right way of using Calendar object with date and timezone is as following :

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

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

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

Java Date and Calendar vs Date and Time API

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


4. Formatting Dates is Hard

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 like 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 utilities 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 the 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 applications 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 the team.

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



5. Mutable

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

Person 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 a 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 the 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 is also important to know the shortcomings of Java's old Date and Calendar API to appreciate and acclaim the greatness of Java 8's new Date and Time API.

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


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