Deep Dive: Why avoid java.util.Date and Calendar Classes


If you have spend a good amount of time programming in Java (old enough that you have worked with Java 7 or below), you must have realized how inefficient and poorly designed the java.util.Date and java.util.Calander classes are. Just try to look for any questions related to java.util.Date class on Stackoverflow almost all the answers say "Avoid using the Date class". In this article we will try to cover why these classes should be avoided and what is the best way to handle Date-Time.



What are the problem with java.util.Date Class?

Short answer:

Open the source code of java.util.Date class and you would see almost all the constructors & methods of this class is deprecated.

Long answer:

The java.util.Date class in itself is not deprecated, when the earlier versions for Java were released it seems like not much attention was given to details and complexities involved with Date/Time especially internationalization and developer-friendliness of these classes.

This class was first released in Java 1 and soon in Java 1.1 most of its methods and constructors were deprecated,

List of depreciated constructors in Date class in Java 1.1:
  • Date(int year, int month, int date)
  • Date(int year, int month, int date, int hrs, int min)
  • Date(int year, int month, int date, int hrs, int min, int sec)
  • Date(String s)
List of deprecated methods in Date class in Java 1.1:
  • int getDate()
  • int getDay()
  • int getHours()
  • int getMinutes()
  • int getMonth()
  • int getSeconds()
  • long getTime()
  • int getTimezoneOffset()
  • int getYear()
  • int hashCode()
  • static long parse(String s)
  • void setDate(int date)
  • void setHours(int hours)
  • void setMinutes(int minutes)
  • void setMonth(int month)
  • void setSeconds(int seconds)
  • void setTime(long time)
  • void setYear(int year)
  • String toGMTString()
  • String toLocaleString()
  • String toString()
  • static long UTC(int year, int month, int date, int hrs, int min, int sec)

Read More: https://docs.oracle.com/javase/7/docs/api/java/util/Date.html

If you will read the JavaDoc you will see that it is recommended to make use of Calander and DateFormat class methods instead.



Understanding Epoch time

It is really important to know how Date and Time is represented or calculated by most of the Operating Systems and Programming Languages.

Epoch Time: It is the number of seconds that have passed since 1st of January 1970 in UTC/GMT.

In Java if you want to get the epoch time you can make use of the System.currentTimeMillis() and convert it into seconds.

Example:
    public static void main(String... args) {

        Long timeInMilliSec = System.currentTimeMillis();
        Long epochTimeInSec = timeInMilliSec/1000;

        System.out.println("Epoch Time:" + epochTimeInSec);
    }
Output:

Epoch Time:1628935442



Creating Date object in Java using java.util.Date class:

As we have talked earlier, most of the Date class constructors are deprecated the two that you can make use of are,

  1. Date()
  2. Date(long date) //the epoch time in milliseconds

The java.util.Date class default constructor actually makes use of the System.currentTimeMillis()

Date now = new Date();

If you look at the implementation of the default constructor you will see it makes use of,


    /**
     * Allocates a {@code Date} object and initializes it so that
     * it represents the time at which it was allocated, measured to the
     * nearest millisecond.
     *
     * @see     java.lang.System#currentTimeMillis()
     */
    public Date() {
        this(System.currentTimeMillis());
    }

If you look at the JavaDoc the first line reads:

The class Date represents a specific instant in time, with millisecond precision.
Examples:
package org.code2care;

import java.util.Date;
import java.util.TimeZone;

public class JavaDateExamples {

    public static void main(String... args) {
        
        //Non Deprecated Constructors
        Date now = new Date();
        System.out.println("Time Now: "+ now);

        Date landingOnMoon = new Date(-14182980000L);
        System.out.println("Moon Landing: "+ landingOnMoon);
    }
}
Output:
Time Now: Sat Aug 14 05:24:24 CDT 2021
Moon Landing: Sun Jul 20 15:17:00 CDT 1969


❗️Problem No. 1: No support for TimeZones.

You must have noticed that the above working with Java Date class seems fine, but the problem arises when you are dealing with Time Zones, what if I want to show the time in say Europe/London time! You cannot make use of TimeZone.setDefault( TimeZone.getTimeZone("Europe/London")), this will cause huge blunders!



❗️Problem No. 2: Date class is mutable.

Example:
        Date now = new Date();
        System.out.println("Time Now: "+ now);
        now.setTime(-14182980000L);
        System.out.println("Time What: "+ now);
Output:
Time Now: Sat Aug 14 05:40:45 CDT 2021
Time What: Sun Jul 20 15:17:00 CDT 1969

As you can see the Date class is not immutable, this is a big design flaw, which is the reason one has to make use of cloning.

Example: Date with cloning:
        Date now = new Date();
        Date newDate = (Date) now.clone();
        System.out.println("Time Now: "+ now);
        newDate.setTime(-14182980000L);
        System.out.println("Time What: "+ newDate);
        System.out.println("Now: "+ now);
Output:
Time Now: Sat Aug 14 05:57:17 CDT 2021
Time What: Sun Jul 20 15:17:00 CDT 1969
Now: Sat Aug 14 05:57:17 CDT 2021


❗️Problem No. 3: Date class does not friendly to add/subtract Date-Time.

There are methods to compare if a date is before, after, or equal to another date, but to add/delete time, you would need to working with epoch times and milli-seconds. You will have to make use of the Calendar object.

Example:
        Date now = new Date();
        System.out.println("Time Now: "+ now);

        Long nowMilliSec = now.getTime();
        Date futureTime = new Date(nowMilliSec + 86400000); //add 1 day
        System.out.println("Time What: "+ futureTime);
Output:
Time Now: Sat Aug 14 06:20:21 CDT 2021
Time What: Sun Aug 15 06:20:21 CDT 2021


❗️Problem No. 4: Months are repesneted as 0-11

This is really confusing! A novice developer can make a lot of blunders if has not read the API documentation well. One would have to make sure to subtract the month by 1 while setting the month and add 1 to make it work as 1-12 standard month representation.

Example:
        Date now = new Date();
        System.out.println("Date-Time: "+ now);
        System.out.println("Month: " + now.getMonth());
Output:
Date-Time: Sat Aug 14 08:29:01 CDT 2021
Month: 7


❗️Problem No. 5: How to set custom date as String in java.util.Date?

There is a way! But Spoiler Alert it's deprecated and if you still tend to make use of it, make sure you know what you are doing, lets have some fun,

        Date someDate = new Date(2021,8, 21); // 8 = Sept
        //Look at the year printed 3921
        System.out.println(someDate.toString());

        //Look at the Year, Month and Date input
        Date someDate1 = new Date(2021,18, 32);
        System.out.println(someDate.toString());
        
        Date someDate2 = new Date(2021,2, 29,44,44,44);
        System.out.println(someDate2.toString());
java.util.Date Examples
Output:
Wed Sep 21 00:00:00 CDT 3921
Tue Aug 01 00:00:00 CDT 3922
Wed Mar 30 20:44:44 CDT 3921

Many things going on here!

  • In the 1st example the month input 8 implies September and not August.
  • Year is set as 2021 but printed out as 3921, that's because the year that you input is computed as 1900+ input year = 1900 + 2021 = 3921. If the date is before 1900. So if you want to use a year like 1890 you have to set the year as -10.
  • No Time was provided hence the 1st example output you see the time is set to Mid-night 00:00:00 in HH:mm:ss format.
  • In the second example - the month is set to numeric 18, no errors no warning and as you can see the output is +9 months to the date, and Date is set as 32 which is also added up correctly. This is so confusing!
  • The third example - We have set hours, minutes, and seconds as well. Needless to say, you can make use of any numbers, no need to bound it to 0-23, 0-59 or so!

Summary:

  • No support for Timezones.
  • The Date class is mutable. Not thread-safe.
  • Manipulating Date/Time is complicated and confusing.
  • No segregation between Date and Time.
  • No methods to construct Date from String (depricated)
  • Months represented as 0-11
  • Year represented as years past 1900
  • No methods to format date/time (depricated)


What are the problem with java.util.Calendar Class?

To overcome the problems with the util Date class, Java released java.util.Calendar class in version 1.1, but still made some same mistakes again. The Calendar class is mutable!. Also, the Calendar represents the Date as well as Time.

  • Timezone conversion is not possible!
  • Calendar class is Mutable!
  • Has no seperation between Date and Time!
  • Months are still repesented as 0-11, causing lot of confusion!
  • Has many performance issue because of the way it stores its state.
  • Calendar is not tread-safe
Let's see some examples:
       TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));

        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/Chicago"));
        System.out.println(cal.getTime()); //Prints in localtime: CDT

        Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));
        System.out.println(cal1.getTime()); //Prints in localtime: CDT

        cal1.setTimeZone(TimeZone.getTimeZone("IST"));
        System.out.println(cal1.getTime()); //Prints in localtime: CDT

        System.out.println(cal1.get(Calendar.MONTH)); // 7 = August
Output:
Sat Aug 14 09:41:31 CDT 2021
Sat Aug 14 09:41:31 CDT 2021
Sat Aug 14 09:41:31 CDT 2021
7


Conclusion:

If you are using Java 1.7 or below it is highly recommended to use the Joda-Time library. For Java 8+ users please make use of java.time API.

To know more please read: JSR 310: Date and Time API

Some References:
  1. https://stackoverflow.com/questions/1969442/whats-wrong-with-java-date-time-api
  2. https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/
  3. https://www.oracle.com/technical-resources/articles/java/jf14-date-time.html
  4. https://stackoverflow.com/questions/21228755/timezone-issue-while-constructing-java-util-date-object-from-timestamp
  5. https://stackoverflow.com/questions/230126/how-to-handle-calendar-timezones-using-java
  6. https://stackoverflow.com/questions/7670355/convert-date-time-for-given-timezone-java



Recent Posts:




Code2care is an initiative to publish and share varied knowledge in programming and technical areas gathered during day-to-day learnings and development activities.

Students and Software Developers can leverage this portal to find solutions to their various queries without re-inventing the wheel by referring to our easy to understand posts. Technical posts might include Learnings, Video Tutorials, Code Snippets, How Tos, Blogs, Articles, etc.