Java has no standard classes for handling pure dates without times. It does have the
These are among the worst bits of code ever written. You can do quite a bit with
- java.util.Date : for handling date/timestamps presuming
GMT (Greenwich Mean Time). It is the lemon of Java. It is mostly replaced by
GregorianCalendar. It is used mainly as if it were a Long wrapper for a
- java.util.GregorianCalendar : a date/timestamp and
time zone. The time zone is usually ignored.
- java.util.SimpleDateFormat : for converting dates to
and from human-comprehensible strings.
- java.util.TimeZone : represents a time zone. Watch
the capital Z. Watch out, Java does not name the time zones in the way Americans
are familiar with.
long timestamp = System.currentTimeMillis();
If you use pure longs, you don’t have to deal with
time zones, leap years, months with variable number of days, regional differences,
bulky objects, slow code and all the gotchas in the Date
and Calendar classes. SQL (Standard Query Language)
can’t screw up a long. It surely can a
SQLDate. Think hard to keep the bulk of your application
dealing with simple longs. Only use Date, Calendar or CalendarFormat when you need to input or output human-readable
There are a ton of surprises and bugs awaiting the unwary users of these
The java.util.Date class is crawling with gotchas. It
is a disgrace. It is the lemon of Java and deserves a giant string of raspberries.
In Java version 1.2, Date has
largely been deprecated, and replaced by something even more complicated,
The key to understanding Date is that it is
not a date class, but a timestamp class. Inside each date is stored
the number of milliseconds since 1970-01-01
UTC (Coordinated Universal Time/Temps Universel Coordonné) . It does
not record the time zone or the timestamp in local time. You choose
the time zone when you display the date with code like this:
With Date, you can’t have a date without a time.
Keep in mind that when you display the same Date with different time zones you will
sometimes get 1999-12-14, and sometimes 1999-12-25.
In contrast GregorianCalendar objects do contain a
TimeZone reference along with the date and time. Like
Dates, they are initialised with the current date and
time. Unfortunately, if they are not sure about the user’s time zone, the Sun
classes quietly revert to GMT, and in early versions of GregorianCalendar, seem to revert to PST (Pacific Standard Time)
if you so much as breathe on them. DateFormats also have
TimeZone that is similarly erratic. For code to work, your
clients must have configured the TimeZone correctly in the
OS (Operating System). You can’t help them
One way out is to use my BigDate class which handles dates from 999,999 BC to 999,999 AD. Sun has deprecated
most of the Date methods and replaced them with GregorianCalendar (which knows the TimeZone unlike Date). Date is still used for storing a date. GregorianCalendar would be far too bulky. GregorianCalendar has not nearly as many limitations as Date, it has got rid of those ridiculous 1900-based years, however it
is obscenely complicated, still relies on the old Date class and maintains a lot of
the Date lunacy such as 0-based months. Happily the documentation in
Java version 1.2 is better, though ambiguity whether
local or UTC parameters are wanted still plagues. Sun tends to be
careless about documenting units of measure. For example in early
JDK ’s you
never knew if TimeZone offsets were measured in
milliseconds, seconds or minutes. getTimeZoneOffset
returns minutes, but GregorianCalendar.get(Calendar.ZONE_OFFSET) returns milliseconds.
See essay on Dates and
- The deprecated new Date( String ) cannot be trusted to
recognise time zone TLAs (Three Letter Acronyms) such as
EST (Eastern Standard Time).
- Inconsistent capitalization. java.util.TimeZone, but
- Inconsistent naming. We have System.currentTimeMillis but Calendar.getTime
InMillis. Note also that new Date objects are initialised to the current date and time, not to a
null value. This gives you two ways to get the current time.
- Documentation is never clear on when you are using local and when
- Months are numbered starting at January=0, rather than 1 as everyone else on
the planet does. Yet days start at 1 as do days of the week with Sunday=1,
Monday=2,… Saturday=7. GregorianCalendar uses the
same idiotic convention. Be thankful for small mercies. DateFormat.parse behaves in the traditional way with 1=January,
though reputedly its isLenient mechanism does not
- getFirstDayOfWeek return Sunday=1 in the USA and
Monday=2 in France.
- TimeZone.getOffset wants a Sunday=1-based day of
week, which it ignores other than sometimes to check validity. The bug only shows
up on Sundays with an InvalidArgumentException in some
JVMs (Java Virtual Machines)
if you pass it a Sunday=0-based dayOfWeek. Your bug can thus easily leak through
- Dates prior to 1970 are not handled in
JDK (Java Development Kit) 1.0 but are handled
in Java version 1.6 or later and later.
- Monday is day 2, (half expects Monday to be day 0, the other half expects it to
be day 1, only the folks at Sun expect 2.). This is not properly documented.
- For Date, year 0=1900, year 100=2000. This has been
fixed in Calendar. Be careful if you are using both Date and Calendar in the same
- There is no reserved value for a null date.
- Dates are stored internally with a date and time in
automatically converted to local time. If you are not careful a date stored as
Saturday can come back a day earlier or later.
- In JDKs (Java Development Kits)
before 1.1.7, DateFormat uses
Standard Time) as the default not GMT
or local time as you might expect. To make it use local time you must do:
DateFormat.setTimeZone( TimeZone.getDefault() );
To get UTC, without any daylight saving correction, you can
DateFormat.setTimeZone( TimeZone.getTimeZone("UTC") );
You must configure your TimeZone property in your OS
(for example, in the Windows Control Panel) for TimeZone. getDefault to work. The
default time zone will be automatically configured in Java once you configure the correct time zone in your
However, selecting the right time zone is more than just selecting how many
hours off GMT
you are. You have to select the correct set of rules for when daylight savings
changes. Java does everything internally in GMT
and converts for display, so it is not enough just to manually reset your
PC (Personal Computer) clock in the spring
and fall. The configuring process can fail for exotic parts of the earth because
the time zone tables either in the OS
or Java are imperfect. Unfortunately, if you actually live in the
time zone, Java will think you want GMT
time without any daylight savings changes. The best solution to this I know so
far when your time zone is not properly supported is to roll your own
TimeZone object with
Alternatively, for applications, you can override the time zone on the java.exe
command line with something like
java.exe -Duser.timezone=Europe/London HelloWorld
Make sure the -D goes before the classname, or it will be interpreted as an arg
to your HelloWorld class. You may have to do this if the
JDK does not
properly recognise the name of the time zone that your OS
calls it. The names for time zones used in Java comes from a list maintained at
NIH (Not Invented Here)
by Arthur David Olson. Unfortunately, the common names such as
EST can mean
Eastern Standard Time: GMT +10 (in Australia)
Eastern Standard Time: GMT-5 (in the US)
so they are not suitable for international use. Pacific Time is called
America/Los_Angeles instead of America/PST. You have to
get out an atlas to find out if you are north of Los Angeles or South of Alaska.
The idea is America/Los_Angeles means PST/PDT, as appropriate.
PDT (Pacific Daylight Time)
would imply a daylight saving correction even in winter. It would have made more
sense to call it America Pacific Time or America PST/PDT. America/Los_Angeles only
has meaning for Californians. When testing time zone-sensitive code, keep in mind
that the switchover between daylight and standard time does not happen at
: a list of available time zones, and how your machine in currently configured
- The people who wrote Date and Calendar need to be sent to a class in English composition. The
key to clarity is a consistent vocabulary. They seem to think day,
date, time and timestamp are synonymous. They muddle
them hopelessly. The Date class is actually a timestamp,
not a date. The method names are misleading. Date.getDay gets you the day of the week. GregorianCalendar.get(Calendar.DATE) or Date.getDate gets you the day of the month. Date.getTime gets you a date/time stamp milliseconds since
1970, in Date, but gets you a
Date object in GregorianCalendar. java.sql.Date and
java.sql.Timestamp are just thin wrappers around
java.util.Date. As such, you can interconvert using the
getTime and setTime methods
with a long milliseconds since 1970 Jan 1 intermediary,
or simply cast to Date. In JDK
1.4+ the Calendar.getTimeInMillis() has been made public, so you can do it in
one step. Date/Calendar needs to be rewritten to use consistent vocabulary. Roman
emperors and popes started the calendar out in a rather confusing manner. Oracle
uses Date to mean a timestamp. C uses the January=0
convention. Sun authors had a failure of nerve to break with Byzantine traditions
of their predecessors.
- Dates and Calendars are
bulky. They are not a suitable way to carry around date information in
RAM (Random Access Memory). Happily, Date boils
down to a Long when serialised for external storage. There needs to be a
minimalist core TimeStamp class, that has no internal baggage, for storing raw
TimeStamps. In the meantime, I recommend you store them as longs or Longs.
- Within the Date class, even though the dates are
stored in GMT, they come out field by field in local time, e.g.
when using getDay and getMonth. there is a way to find out which local time it is using
with getTimezoneOffset, but there is no way to set the
time zone you want to use. You can set the default local time zone when formatting,
but it does not apply to your calculations based on getMonth etc. The calculations
you are doing may have nothing to do with local time. To add insult to injury, if
the client did not properly configure the time zone, the calculations could have
been quietly done relative to PST
(early JDK s) or GMT,
recent JDKs. BigDate
sidesteps the entire issue by working with pure dates, no times no time zones.
- The list of possible time zones is incomplete and ambiguously defined. For
example, BST (British Summer Time) as a time zone refers
to Bangkok Standard Time, not British Summer Time. In Solaris, when you want to
express your date in the MET (New York Metropolitan Opera) time zone
(continental european time zone), you get GMT
+ 3h30 : Teheran time.
- DateFormat.parse is broken in JDK
1.2.1. It is fixed in 1.2.2.
- Oracle SQL databases expect dates stored to be presented in
UTC, yet when you retrieve them they automatically
convert to local time. This is not what you want. A servlet’s local time has
no relation to the final client’s local time. Store dates as longs or ints to
avoid Oracle’s foolish meddling.
Oracle’s Javadoc on Date
class : available: