Making Sense of Java's Dates
Pages: 1, 2
It has to be said that implementation details have been oozing into the
APIs to an uncommon degree for the "new" date-handling classes. Up to a point,
this is a reflection of their intended use as base classes for customized
development, but it also seems to occasionally be a consequence of insufficient
clarity in the design of the public interfaces. Whether the
The additional functions offered by the
Calendar base class
fall into three categories. There are several static factory methods to obtain
instances initialized for arbitrary time zones and locales. As mentioned above,
all instances obtained this way have already been initialized to the
current time. No factory methods are provided to obtain a
Calendar instance initialized to an arbitrary point in time.
The second group of methods consists of the methods
after( Object ). They take arguments of type
Object, thus allowing these methods to be overridden in subclasses
for arbitrary types of arguments.
Finally, there are a number of functions to get and set additional properties, such as the current time zone. Among them are several methods that query the possible and actual minimum and maximum values of certain fields for the current calendar implementation.
When Does the Week Begin?
The documentation on the
GregorianCalendar is the only commonly available
Calendar. It provides an implementation of the basic
Calendar abstraction suitable for the interpretation of dates
according to the conventions used commonly in the West. It adds a number of
public constructors, as well as some functions specific to Gregorian Calendars,
TimeZone class and its subclasses are auxiliary classes,
Calendar to interpret dates according to the
selected time zone. Semantically, a time zone specifies a certain offset to be
added to GMT to reach the local time. Clearly, this offset changes when
daylight savings time (DST) is in effect. The
therefore needs to keep track not only of the additional offset to be applied
if DST is in effect, but also of the rules that determine when DST is
in effect, in order to calculate the local time for any given date and
The abstract base class
TimeZone provides basic methods to
handle "raw" (without taking DST into account) and actual offsets (in
milliseconds!), but implementation of any functionality related to DST rules is
left to subclasses, such as
SimpleTimeZone. The latter class
provides several ways to specify rules controlling the beginning and ending of
DST, such as a giving an explicit day in a month or a certain weekday following
a given date. Each
TimeZone also has a human-readable,
locale-dependent display name. Display names come in two styles:
Time zones are unambiguously determined by an identifier string. The base
class provides the static method
String getAvailableIDs() to obtain
all installed "well-known" standard time zones. (There are 557 for my
installation, using JDK 1.4.1.) The JavaDoc defines the proper syntax to build
custom time zone identifiers, if the need arises. Also provided are static
factory methods, to obtain
TimeZone instances — either for a
specific ID or the default for the current location.
SimpleTimeZone also provides some public constructors and,
surprisingly for an abstract class, so does
JavaDoc states: "For invocation by subclass constructors." Apparently, it
should have been declared
Calendar and related classes handle the locale-specific
interpretation of dates, the
DateFormat classes assist
with the transformation of dates to and from human-readable strings. When
representing points in time, an additional localization issue arises: not only
the language, but also the date format is locale-dependent
(U.S.: Month/Day/Year, Germany: Day.Month.Year, etc.). The
DateFormat utility tries to manage these differences for the
The abstract base class
DateFormat does not require (and does
not permit) the definition of arbitrary, programmer-defined date formats.
Instead, it defines four different format styles:
FULL (in increasing
order of verbosity). Given a locale and a style, the programmer can rely on the
class to use an appropriate date format.
The abstract base class
DateFormat does not define static
methods for formatting (date -> text) or parsing (text -> date). Instead, it
defines several static factory methods to obtain instances (of concrete
subclasses) initialized for a given locale and a chosen style. Since the
standard formats always include both date and time, additional factory
methods are available to obtain instances treating only the time or
date part. The
String format( Date ) and
Date parse( String
) methods then perform the transformation. Note that concrete subclasses
may choose to break this idiom.
Calendar object used internally to interpret dates is
accessible and can be modified, as are the employed
NumberFormat objects. However, the locale and style can no longer
be changed once the
DateFormat has been instantiated.
Also available are (abstract) methods for piece-wise parsing or formatting,
taking an additional
argument, respectively. There are two versions for each of these methods. One
takes or returns a
Date instance and the other takes or returns a
Object, to allow handling of alternatives to
Date in subclasses. The class defines several public static
variables with names ending in
_FIELD to identify the various
possible fields for use with
FieldPosition (cf. the JavaDoc
The only commonly available concrete subclass of
SimpleDateFormat. It provides all of the aforementioned
functionality, additionally allowing the definition of arbitrary date-formatting patterns. There is a rich syntax to specify formatting patterns; the
JavaDoc gives the full details. The pattern can be specified as an argument to
the constructors of this class or set explicitly.
Printing a Timestamp: A Cut-and-Paste Example
Imagine you want to print the current time in a user-defined format; for instance, to a log file. Here is how to do this:
The Classes in
The date-and-time-handling classes in the
java.util.Date. The fact that there are three of them
reflects the need to model the three standard SQL92 types
java.util.Date, all three classes in the SQL package are
thin wrappers around a numeric value representing a point in time. The
Time classes ignore the information
regarding the time of day or the calendar date, respectively.
Timestamp class, however, not only includes the usual time
and date information up to millisecond precision, but also allows storing
additional data to accurately represent a point in time with nanosecond
precision. (A nanosecond is a billionth of a second.)
Besides shadowing the corresponding SQL datatypes, these classes handle
transformations to and from SQL-conforming
To this end, each of the three classes overrides the
method. Furthermore, each class provides a static factory method,
valueOf( String ), which returns an instance of the class that it
has been invoked on, initialized to the time value represented by the
String passed to it. The format of the
representation for all of these methods is fixed by the SQL standard and cannot be
changed by the programmer.
The additional data required to store nanosecond information has not been
very well integrated with the rest of the data representing the usual time and
date information in the
Timestamp class. For example, calling
getTime() on a
Timestamp instance will return the
number of milliseconds since the start of the Unix epoch, ignoring the
nanosecond data. Similarly, according to the JavaDoc, the
hashCode() method has not been overridden in the subclass, and
therefore also ignores the nanosecond data.
The JavaDoc for
java.sql.Timestamp states that the
"inheritance relationship (...) really denotes implementation inheritance, and
not type inheritance," but even this statement is incorrect, since Java has no
notion of private (i.e. implementation) inheritance. Instead of inheriting
java.util.Date, all of the classes in the
java.sql.* package should have been designed to encapsulate
java.util.Date object, exposing only the methods required
— at the very least, methods such as
hashCode() should have
been properly overridden.
A final comment concerns the handling of time zones by the database engine.
The classes in the
java.sql.* package do not allow one to specify the
intended time zone explicitly. Database servers (or drivers) are free to
interpret this information as being valid in the server's local time zone, which
may be subject to change (for instance, due to daylight savings time).
From the foregoing discussion it should be clear that Java's date-handling
classes are not just complicated, but also poorly designed. Encapsulation is
leaky, the APIs are baroque and not well-organized, and uncommon idioms are
employed frequently for no good reason. The implementation holds additional
surprises (I suggest a look at the actual type of the object returned from
Calendar.getInstance( Locale ) for all available locales!) On
the other hand, the classes manage to treat all of the difficulties inherent in
internationalized date handling and, in any case, are here to stay. I hope
that this article was a little contribution in helping to clarify their proper
Call Me By My True Names
As a last example of the wonderful consistency and orthogonality of Java's APIs, I would like to list three (maybe there are more!) different methods to obtain the number of milliseconds since the start of the Unix epoch:
The author would like to thank Wilhelm Fitzpatrick (Seattle) for a careful reading of the manuscript and valuable comments.
- International Calendars in Java at IBM : A detailed white paper by one of the original authors on the genesis and intended usage of Java's date-handling classes. Highly recommended.
- IBM alphaWorks:
International Calendars: Additional subclasses of
Calendarfor Buddhist, Hebrew, Muslim, and Japanese calendars used to be available at IBM's alphaWorks. Unfortunately, they seem to be temporarily unavailable.
- Reingold on Calendars: Web site of Edward M. Reingold, author of Calendrical Calculations, the standard reference on calendars.
- About the Calendars: A brief overview of some of the more common international calendars.
- Thread on JavaLobby: A brief, but interesting, thread on JavaLobby. Apparently, some people considered the APIs of Java's date classes to be so bad that they filed an official bug-report to have them changed. Unfortunately, the request has been rejected.
Philipp K. Janert is a software project consultant, server programmer, and architect.
Return to ONJava.com