Avoid the legacy date-time classes
So the whole Java Date/Calendar/GregorianCalendar thing is obviously a joke.
Yes, the old date-time classes bundled with the earliest versions of Java are an awful mess. Badly designed, clumsy attempts at improvements, many hacks.
But to be fair, those classes were a valiant effort in addressing a surprisingly tricky topic that the entire information industry has ignored for decades. Based on prior work at Taligent and IBM, the authors of those classes at least made an attempt where virtually all other programming languages, platforms, and tools take a pass with only the barest minimum of support for date-time handling.
Fortunately we now have the industry-leading java.time classes (JSR 310) built into Java 8 and later. These were inspired by the success of the Joda-Time project. Indeed both efforts were led by the same man, Stephen Colebourne.
java.time
Every single one of your bullet items of complaint is rectified by using java.time instead.
- 99% of Date is deprecated
Instant
replaces java.util.Date
. AFAIK, nothing is deprecated in java.time in Java 8 & Java 9.
- Date's Year is offset from 1900
Years have sane numbering in java.time, 2018
is the year 2018.
- Date's Month is zero-indexed while day is one-indexed
Months have sane numbering in java.time, 1-12 for January-December. Even better, the Month
enum provides objects to represent each month of the year rather than a mere integer number. So you get valid values, type-safety, and self-documenting code.
- Dates are mutable
Virtually all of java.time is immutable. Any calls to alter some aspect of a java.time object returns a new and distinct object. Even constructors are hidden, with static factory methods used instead.
- You're supposed to use a Calendar to create a date...
ZonedDateTime
replaces java.util.Calendar
.
- ... except you really have to use a GregorianCalendar
ZonedDateTime
replaces java.util.GregorianCalendar
too. The java.time framework uses interfaces mostly for internal-use only, encouraging apps to use only the concrete classes. This was a design decision specific to the needs of java.time as a framework and does not mean you should the same in your apps.
- Do a significant percent of developers want to use a different calendar?
Yes. Other calendaring systems are used by many people around the globe. The java.time framework provides for this via the Chronology
interface and AbstractChronology
class. The default chronology is IsoChronology
following the ISO 8601 standard used generally in the West. In Java 8 & 9, other bundled chronologies include Thai Buddhist, Hijrah (Islamic), Minguo (Taiwan), and Japanese Imperial. Third-parties may implement others. In the ThreeTen-Extra project, you’ll find additional chronologies for Accounting (proleptic 52/53-week per US IRS Publication 538 and the International Financial Reporting Standards), the British Julian-Gregorian cutover, Coptic (Christian Egypt), Discordian (Erisian), Ethiopic, International Fixed (Cotsworth plan, the Eastman plan), proleptic Julian, Pax, and Symmetry010 & Symmetry454. If only someone would implement the French Republican Calendar.
- Calendar.getTime() returns a Date
Just use Instant
as your basic building-block class in java.time, always representing a moment in UTC with a resolution of nanoseconds. The other types such as OffsetDateTime
& ZonedDateTime
can convert back-and-forth with Instant
.
- There's no Date math (like how far apart are two dates in years)
The java.time classes have many convenient plus…
/minus…
methods. Furthermore, java.time provides powerful TemporalAduster
implementations as well as enabling you to write your own. Also look to the ChronoUnit::between
method, such as ChronoUnit.YEARS.between( thisLocalDate , that LocalDate )
.
- Messing with milliseconds since epoch doesn't count
Look to Instant::toEpochMilli
and Instant.ofEpochMilli
if you must use count-from-epoch, but certainly not advisable. Better to use java.time objects and ISO 8601 strings to represent date-time values.
- You can't chain parts together to get an expression (like the date one year ago today)
The java.time classes are definitely designed for call-chaining. Example: LocalDate.now( ZoneId.of( "Europe/Paris" ) ).minusYears( 1 ).getDayOfWeek().getDisplayName( TextStyle.FULL , Locale.FRANCE )
> dimanche
. Sometimes appropriate, but don’t go nuts with it — that’s my advice.
- Probably more stuff
Yes many more problems with the old legacy classes. You will find java.time to be a radical departure from the old stuff, thoroughly modern and well-designed, a gigantic improvement.
One of the other problem areas is exchanging date-time values with a database. Note that with a JDBC driver compliant with JDBC 4.2 or later (JSR 221), you can avoid the date-time related java.sql classes such as java.sql.Timestamp
classes. Those old classes are related to the troublesome old legacy classes, and are no longer needed.
myPreparedStatement.setObject( … , instant ) ;
…and…
Instant instant = myResultSet.getObject( … , Instant.class ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?