Handling dates in Java

May 11, 2011 2 comments

Inspired by a dzone article I decided to take a stab on this old issue which I’ve had to tackle quite a few times over the years.

The date/time API in Java is notoriously painful to work with. Not to make it any easier, there are also some things that are generally not very well understood about it. Perhaps the biggest misconception is that Date objects contain time zone and DST information. They do not. Date in Java is only a glorified long. Ie. it is a wrapper for milliseconds elapsed since 00:00:00 UTC on 1 January 1970, aka the epoch. Understanding this makes reasoning about time in Java a lot easier.

Okay, so Date is only a bunch of milliseconds. What if I need the representation of some arbitrary date? Do I calculate it from the epoch? How about printing a date? No worries, DateFormat is here to help. The API documentation states that “DateFormat is an abstract class for date/time formatting subclasses which formats and parses dates or time”. DateFormat needs a date pattern which it uses for parsing and formatting. Once provided, using DateFormat is pretty straight-forward.

//parsing a date from string
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date dateOne = df.parse("2011-02-08 10:00:00 +0300");

//formatting a string representation given a date and a pattern
String dateStr = new SimpleDateFormat("EE, dd MMMM yyyy z").format(dateOne);
System.out.println(dateStr); //Tue, 08 February 2011 EET

Since DateFormat is an abstract class, we need an implementation for instantiating it. That’s what we get with SimpleDateFormat. The cool thing about DateFormat is that it isn’t overly complex to use and given enough information it handles time zones as well.

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date dateOne = df.parse("2011-02-08 10:00:00 +0300");
Date dateTwo = df.parse("2011-02-08 08:00:00 +0100");

//compare the millisecond representations
long timeDiff = dateOne.getTime() - dateTwo.getTime();

System.out.println(String.format("difference %s milliseconds.", timeDiff));
//difference 0 milliseconds.

Here we parsed two dates from strings and compared them. The (wall clock) time in the dates is different but since they are in separate time zones, they actually represent the same point in time.

DateFormat looks pretty simple. However, there is more than meets the eye. One could think that besides the date pattern, DateFormat is essentially a stateless parser/formatter. Wrong! This is hinted by the methods getCalendar() and setCalendar(Calendar newCalendar). Ie. a Calendar object plays an essential role in the implementation of DateFormat.

This is where things start to go downhill. First of all, DateFormat is not thread safe. The API document states this clearly: “Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.” You might be tempted to create a set of static convenience methods using DateFormat and place them in a util class which can easily be used from all over the codebase. Don’t do that! The chances are, you will run into hairy concurrency issues.

What if we need to add or subtract seconds or minutes or some other time unit to/from the date? There are at least a couple of ways of doing this, none of which is particularly elegant and the current Date API itself doesn’t provide a method for doing so. First of all you can expose the implementation details and manipulate the milliseconds directly. Date has a method getTime() for that purpose.

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date dateOne = df.parse("2011-02-08 10:00:00 +0200");
//2011-02-08 10:00:00 +0200

//an hour worth of milliseconds
long hour = 1000 * 60 * 60;

//Create a new Date from milliseconds
Date dateTwo = new Date(dateOne.getTime() + (2 * hour));
System.out.println(df.format(dateTwo));
//2011-02-08 12:00:00 +0200

//Change the milliseconds of an existing date
dateTwo.setTime(dateOne.getTime() + (3 * hour));
System.out.println(df.format(dateTwo));
//2011-02-08 13:00:00 +0200

When you need to convert time units to other time units, a utility class called TimeUnit can save you time and make the code more readable.

//Instead of...
long hour = 1000 * 60 * 60;
dateTwo.setTime(dateOne.getTime() + (3 * hour));

//...you could write
dateTwo.setTime(dateOne.getTime() + TimeUnit.HOURS.toMillis(3));

You may have noticed that the dates were printed in the same timezone as dateOne was parsed. This is only a coincidence, since unless explicitly specified, DateFormat uses the system time zone which in this case just happens to be +0200  (EET in normal time). Consider the following:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date dateOne = df.parse("2011-02-08 10:00:00 +0100");
System.out.println(df.format(dateOne));
//2011-02-08 11:00:00 +0200

df.setTimeZone(TimeZone.getTimeZone("CET"));
System.out.println(df.format(dateOne));
//2011-02-08 10:00:00 +0100

As you can see, the first day is not formatted with the time zone offset +0100 even though it was parsed from such a string. If you want to get the String representation of a Date in a certain time zone, you have to explicitly set a TimeZone object to the DateFormat. Here the TimeZone object was created by using a static factory method getTimeZone(String timeZoneId). An array of available time zone ids can be accessed by the method getAvailableIDs(). The time zone offset can also be set using the method setRawOffset(int offsetMillis). For public constructors, consult the TimeZone API.

I mentioned there are at least couple of ways for changing a date. In addition to manipulating the milliseconds directly, a Calendar object can be used. Calendar is an abstract base class for calendar implementations. For instantiating it, you need its implementation, GregorianCalendar.

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
Date date = df.parse("2010-11-08 10:00:00 +0200");

Calendar cal = new GregorianCalendar();
cal.setTime(date);
TimeZone helsinkiTz = TimeZone.getTimeZone("Europe/Helsinki");
cal.setTimeZone(helsinkiTz);
cal.add(Calendar.HOUR_OF_DAY, 2);
Date newDate = cal.getTime();

df.setTimeZone(helsinkiTz);
System.out.println(df.format(newDate));
//2010-11-08 12:00:00 +0200

For me, Calendar is the single biggest reason why date/time manipulation in Java is unpleasant to work with. The API is not very well designed. It is outdated and it also has several misleading characteristics. By outdated, I refer to its heavy use of int constants. Calendar was added to the Java standard library before we had enums in the language, but even though enums have been around since Java 1.5, the Calendar API makes no use of them.

If the code is written using the static final ints in the Calendar class, the code can be semi-readable. However, because of the way the API was designed, it easily leads to code, where magic numbers or custom constants are used in place of the named constants in the Calendar class. This is confusing for the reader and can cause some tricky bugs.

//the calendar object from the previous example holding the date
//2010-11-08 12:00:00 +0200
cal.set(Calendar.MONTH, 1);

What do you think the new Date is? If you thought the month was changed to January, you guessed wrong. The new month is February. Ie. Calendar.FEBRUARY = 1.  Not so easy to spot.

One common case where the date/time API doesn’t shine is when you need to find out some property of a date. Eg. the day or the month or the year. I’m not too happy about the options provided for this. You can use DateFormat to format the date to a string and then parse the needed information, but that’s error-prone and not very elegant. Another way is to create a calendar, set the time zone and use the method getField() with the correct constant, but this is not very straight-forward either for such a simple task.

Yet another poorly supported feature is time periods. There are no classes manipulating intervals between dates, doing calculation for them etc.

Alternatives

Is the JDK standard date/time API the only option? Fortunately not. Perhaps the best-known alternative is an open source library called Joda-Time. Joda-Time was born out of frustration with the standard API. Not everyone is happy with Joda-Time either. Another open source library, Date4j is a light-weight alternative, that may appeal to those who don’t need n+1 classes for handling their dates. Then there is JSR 310, which is the proposal for the new and improved Date/Time API coming for Java SE 7. JSR 310 is largely based on Joda-Time. JDK 7 is supposed to be released later this year. We’ll see…

Categories: java Tags: ,

Clojure multimethods

January 6, 2011 5 comments

I have just began my adventures in Clojure land. So far it seems exotic for someone who’s just beginning to grasp the marvels of functional programming and for whom Lisp has previously been just magic inside parentheses. However, even though my experience with Clojure is very limited, I’ve already noticed that it is a very enabling language.

I’m planning to post brief introductions or tutorials on Clojure’s features on this blog, mostly to educate myself. I’m sure I won’t be able to avoid errors. If you spot one, please let me know. I’m also very interested to learn what is and what isn’t idiomatic in Clojure. I hope my Clojure code doesn’t turn into Fortran. ;)

One of the interesting features of Clojure (and some other languages) is multimethods. They are basically Clojure’s way of implementing runtime polymorphism. A multimethod is a method that dispatches a call to a specific function (method) implementation  based on some property of its argument(s).

Example 1:

(defmulti animal (fn [x] x))
(defmethod animal "dog" [x] "Woof!")
(defmethod animal "lolcat" [x] "I can has cheezburger")
(defmethod animal :default [x] "Unknown animal")

Running in REPL:
user=>(animal "dog")
"Woof!"

user=>(animal "lolcat")
"I can has cheezburger"

user=>(animal "giraffe")
"Unknown animal"

user=>(animal ["some" "unrelated" "stuff"])
"Unknown animal"

Here (fn [x] x) is the dispatching function which dispatches the call to the correct function implementation. In other words, it evaluates its argument(s) and produces a dispatching value which is used for finding  the actual implementation (defmethod). In this example, a simple string is used as an argument. It evaluates to itself and nothing more. The third defmethod is the default implementation which is called if none of the other defmethods match the dispatching value.

Example 2:

(defmulti thoughts-of (fn [person] (person :name)))

(defmethod thoughts-of "Guido" [person]
    (str (person :name) " has lost his shrubbery."))

(defmethod thoughts-of "Rich" [person]
    (str (person :name) " values laziness."))

(defmethod thoughts-of nil [person] "--")

(defmethod thoughts-of :default [person]
    (str (person :name) " is not a well-known thinker."))

Running in REPL:

user=>(thoughts-of {:name "Guido"})
"Guido has lost his shrubbery."

user=>(thoughts-of {:name "Rich"})
"Rich values laziness."

user=>(thoughts-of {:name "Tero"})
"Tero is not a well-known thinker."

user=>(thoughts-of {})
"--"

Here a hash-map is used as an argument and the value of the dispatch method is the the value found from the map using the keyword :name as a key. In the example the map itself is used as a function which takes the key as an argument.

Alternative ways for writing the same dispatching function would be:

(fn [person] (:name person))
Keyword as a function in the body of the dispatching function.

(fn [person] (get person :name))
Using the function get. This is perhaps the most conventional way.

:name
Using the keyword alone as the dispatching function. This is effectively the same as the first alternative but with less boilerplate.

Multiple dispatch mechanism is not unique to Clojure. Eg. as far as I know Python doesn’t natively support it but provides several ways for achieving it. In languages like Java and C++, multiple dispatch is difficult to implement.

For further reading, see:

Wikipedia article on multiple dispatch contains examples in other programming languages.

More theory and examples:
Clojure’s Approach to Polymorphism: Method Dispatch

New year’s resolutions of a software developer

January 2, 2011 4 comments

I registered this account for some time ago but I haven’t really posted anything yet so I decided that a new year’s resolution would be a great way to start.

To sum up my plans for 2011, I’m going to improve my skills on various topics and become better at my profession. I’m planning to take small steps to learn something new everyday.

I categorized the goals under separate topics but many of them overlap.

In no specific order, here goes:

Programming languages:
Primary goal:
Learn Clojure, Ruby, Scala and JavaScript.
Implement something nontrivial with each of them.

Secondary goal:
Improve Python and PHP skills. Learn Groovy.

Functional programming:
Learn all the fundamental concepts related to functional programming.
Implement something nontrivial with a functional programming language.

Parallel programming:
Implement something nontrivial that (effectively) uses parallel programming techniques.

JavaEE platform:
Finish the JEE6 showcase project.
Read at least one book that’s related to JavaEE technologies.

JVM:
Learn the details of the JVM:
Memory handling and tweaking the memory options, custom class loaders etc.

Client-side web development:
Read a book about JavaScript.
Learn and use JavaScript frameworks, primarily jQuery.
Improve CSS skills.
Do some sort of HTML5 showcase project.

Cloud:
Implement something nontrivial with some cloud technology (like GAE).

NoSQL:
Use at least one NoSql DBMS in some hobby project.

Teach/inspire other people to learn:
Organize a study group or training session(s) at work.

Be active online:
Blog and comment other people’s blog posts. Tweet. Answer the questions of others.

I consider it a success if I manage to get some of my colleaques or friends excited about some technology they didn’t previously know about.

Blogging:
Write a blog post at least once a month.

Books about software development:
Finish at least a book per quarter. Aim for a book per month.

Productivity and use of time:
Read at least one book related to developer productivity.
Apply the required knowledge/techniques to work and hobby projects.

And finally, don’t take things too seriously. Remember to keep it fun. :)

Categories: learning Tags:

Hello multiverse

June 6, 2010 3 comments

Good things come to those who wait…

Categories: Uncategorized
Follow

Get every new post delivered to your Inbox.