Conrad Weisert
Originally written February, 1996; minor format revisions and addendum 12 November 2009
©2009, Information Disciplines, Inc.
This article was a handout in an early Java course. It may be copied and distributed
freely as long as the copyright credit is included
We'd like to believe that the people who design the programming languages and other software development tools we use are top-notch professionals who understand long established principles of good programming practice. Unfortunately, we can't. Software technology is evolving so fast and new tools are appearing so often that major software vendors often have to entrust crucial design responsibilities to people who have little practical experience in large-scale high-quality software development.
Java's Date class is a sad illustration of this
phenomenon. As part of the standard class library included with all Java 1.0 implementations
this class ought to:
It fails on all counts, violating many principles of good programming and design.
Is Java's Date class a unique or unusually bad example?
Hardly. The languages and other tools we
use are a frustrating blend of components that range from the solidly conceived and superbly
implemented to the half-baked and sloppily coded.
Discriminating professionals—programmers and I.S. managers—scrutinize the tools they use and avoid embracing any component based solely on its having come from a respected source. Of course, we can't reinvent everything, and we have to be willing to settle for lower quality in a packaged component than we might be able to develop ourselves. Occasionally, however, we have to reject some standard or vendor's solution because it fails to meet our needs for functionality or maintainability.
There's so much wrong with Java's Date class that it's
hard to organize a point-by-point criticism. Here are some of its major shortcomings:
A crucial OOP principle is that we hide the underlying
data representation from client programs. Note, however, the second constructor which takes a
long parameter as well as the related
getTime and
setTime methods. The long
data item is the number of milliseconds since midnight, January 1, 1970!
Whether or not a given implementation of Date
actually uses that internal data representation (it's a good bet that it does), such an
unnecessary specific dependency tempts programmers to take all sorts of advantage of a
peculiarity that has nothing whatever to do with manipulating dates.
Those methods that extract or set the year use a biased representation starting in 1900.
After all the uproar over the year-2000 crisis this is astonishing in a public interface.
The same int data item could easily accommodate
the full year number. (Note: this doesn't mean that Java handles the year modulo 100;
the year 2001 is 101, so no information is lost. Still, what's the point?)
Numbering months from 0 (January) to 11 (December) flies in the face of every tradition both in programming and in the real world. One imagines a misguided programmer saving one or two instructions in subscripting a 0-origin array, and deciding to inflict his or her convenience on every user.
Using the word "Date" to mean day of the month (see methods
getDate and
setDate) when it has already been chosen as the name
of the class and thus a whole date is a beginning programmer's blunder. This is then
compounded by using the word "Day" which users would expect to denote the day of
the month, to mean day of the week.
The names before and
after to denote <
and > operations appear to
be unique to the Date class, and may therefore
impede generic functions and polymorphic
invocation. (The String class uses
compareTo,
and when we define other classes for which ordering is meaningful, e.g.
Money, we're likely to find
lessThan and
greaterThan more natural than
before and
after .)
With all those things wrong with Date we're even more
frustrated by not being able to do the things we need to do to dates without a lot of unnatural
and unreadable circumvention:
Date provides no direct way of computing the number
of days between two dates. The client programmer has to convert both dates to another
type:
duration = (endDate.getTime() - startDate.getTime()) / 86400000;
(86400000 is the number of milliseconds in a day.)
Although this is the inverse of the above, it's easier (although hardly any more readable),
since Date lets us compute an unnormalized
date:
endDate.setTime(startDate.getTime()); // Copy the whole date
endDate.setDate(duration // Increment
+ endDate.getDate()); // the day portion
A Date class that supports day-of-the-week should
also support week-number within the year. This is frequently needed in manufacturing,
project management, and other scheduling applications.
The result of toString() is unlikely to suit any
application's needs, except perhaps as some sort of readable time stamp. (This is due, in
part, to the misguided decision to bundle Date and time-of-day together, and call it Date.)
2009 Addendum:Sensible programmers were relieved a decade ago to learn that the awful Java 1.0 standard library class described above was to be "deprecated" in Java 1.1 and replaced by an entirely new set of date manipulation facilities. Java's designers and implementors, we thought, were responding to the torrent of complaints. The new facility would surely address most if not all of those complaints. A later article will examine how that turned out. |
Return to technical articles
Return to Java topics
Return to IDI home page
Last Modified, 12 November 2009