Could someone please advise the current “best practice” around
When writing new code, is it best to always favour
Date, or are there circumstances where
Date is the more appropriate datatype?
Date is a simpler class and is mainly there for backward compatibility reasons. If you need to set particular dates or do date arithmetic, use a Calendar. Calendars also handle localization. The previous date manipulation functions of Date have since been deprecated.
Personally I tend to use either time in milliseconds as a long (or Long, as appropriate) or Calendar when there is a choice.
Both Date and Calendar are mutable, which tends to present issues when using either in an API.
The best way for new code (if your policy allows third-party code) is to use the Joda Time library.
Calendarare really the same fundamental concept (both represent an instant in time and are wrappers around an underlying
One could argue that
Calendaris actually even more broken than
Dateis, as it seems to offer concrete facts about things like day of the week and time of day, whereas if you change its
timeZoneproperty, the concrete turns into blancmange! Neither objects are really useful as a store of year-month-day or time-of-day for this reason.
Calendaronly as a calculator which, when given
TimeZoneobjects, will do calculations for you. Avoid its use for property typing in an application.
Dateto generate display Strings.
If you’re feeling adventurous use Joda-Time, although it is unnecessarily complicated IMHO and is soon to be superceded by the JSR-310 date API in any event.
I have answered before that it is not difficult to roll your own
YearMonthDayclass, which uses
Calendarunder the hood for date calculations. I was downvoted for the suggestion but I still believe it is a valid one because Joda-Time (and JSR-310) are really so over-complicated for most use-cases.
Date is best for storing a date object. It is the persisted one, the Serialized one …
Calendar is best for manipulating Dates.
Note: we also sometimes favor java.lang.Long over Date, because Date is mutable and therefore not thread-safe. On a Date object, use setTime() and getTime() to switch between the two. For example, a constant Date in the application (examples: the zero 1970/01/01, or an applicative END_OF_TIME that you set to 2099/12/31 ; those are very useful to replace null values as start time and end time, especially when you persist them in the database, as SQL is so peculiar with nulls).
Dates should be used as immutable points in time;
Calendars are mutable, and can be passed around and modified if you need to collaborate with other classes to come up with a final date. Consider them analogous to
StringBuilder and you’ll understand how I consider they should be used.
(And yes, I know Date isn’t actually technically immutable, but the intention is that it should not be mutable, and if nothing calls the deprecated methods then it is so.)
I generally use Date if possible. Although it is mutable, the mutators are actually deprecated. In the end it basically wraps a long that would represent the date/time. Conversely, I would use Calendars if I have to manipulate the values.
You can think of it this way: you only use StringBuffer only when you need to have Strings that you can easily manipulate and then convert them into Strings using toString() method. In the same way, I only use Calendar if I need to manipulate temporal data.
For best practice, I tend to use immutable objects as much as possible outside of the domain model. It significantly reduces the chances of any side effects and it is done for you by the compiler, rather than a JUnit test. You use this technique by creating private final fields in your class.
And coming back to the StringBuffer analogy. Here is some code that shows you how to convert between Calendar and Date
String s = "someString"; // immutable string StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer buf.append("x"); assertEquals("someStringx", buf.toString()); // convert to immutable String // immutable date with hard coded format. If you are hard // coding the format, best practice is to hard code the locale // of the format string, otherwise people in some parts of Europe // are going to be mad at you. Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02"); // Convert Date to a Calendar Calendar cal = Calendar.getInstance(); cal.setTime(date); // mutate the value cal.add(Calendar.YEAR, 1); // convert back to Date Date newDate = cal.getTime(); // assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);
With Java 8, the new java.time package should be used.
Objects are immutable, time zones and day light saving are taken into account.
Date date = new Date(); ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
I always advocate Joda-time. Here’s why.
- the API is consistent and intuitive. Unlike the java.util.Date/Calendar APIs
- it doesn’t suffer from threading issues, unlike java.text.SimpleDateFormat etc. (I’ve seen numerous client issues relating to not realising that the standard date/time formatting is not thread-safe)
- it’s the basis of the new Java date/time APIs (JSR310, scheduled for Java 8. So you’ll be using APIs that will become core Java APIs.
A little bit late at party, but Java has a new Date Time API in JDK 8. You may want to upgrade your JDK version and embrace the standard. No more messy date/calendar, no more 3rd party jars.
advise the current “best practice” around
is it best to always favour
Avoid these legacy classes entirely. Use java.time classes instead.
- For a moment in UTC, use
(the modern equivalent of
- For a moment in a particular time zone, use
(the modern equivalent of
- For a moment in a particular offset-from-UTC, use
(no equivalent in legacy classes)
- For a date-time (not a moment) with unknown time zone or offset, use
(no equivalent in legacy classes)
The Answer by Ortomala Lokni is right to suggest using the modern java.time classes rather than the troublesome old legacy date-time classes (
Calendar, etc.). But that Answer suggests the wrong class as equivalent (see my comment on that Answer).
The java.time classes are a vast improvement over the legacy date-time classes, night-and-day difference. The old classes are poorly-designed, confusing, and troublesome. You should avoid the old classes whenever possible. But when you need to convert to/from the old/new, you can do so by calling new methods add to the old classes.
Searching Stack Overflow gives many hundreds of example Questions and Answers on using java.time. But here is a quick synopsis.
Instant instant = Instant.now();
Specify a proper time zone name in the format of
continent/region, such as
Pacific/Auckland. Never use the 3-4 letter abbreviation such as
IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = instant.atZone();
A time zone is a region’s history of changes in its offset-from-UTC. But sometimes you are given only an offset without the full zone. In that case, use the
ZoneOffset offset = ZoneOffset.parse( "+05:30" ); OffsetDateTime odt = instant.atOffset( offset );
Use of a time zone is preferable over use of a mere offset.
The “Local” in the
Local… classes means any locality, not a particular locality. So the name can be counter-intuitive.
LocalTime purposely lack any information about offset or time zone. So they do not represent actual moments, they are not points on the timeline. When in doubt or in confusion, use
ZonedDateTime rather than
LocalDateTime. Search Stack Overflow for much more discussion.
Do not conflate date-time objects with strings that represent their value. You can parse a string to get a date-time object, and you can generate a string from a date-time object. But the string is never the date-time itself.
Learn about standard ISO 8601 formats, used by default in the java.time classes.
Date should be re-developed. Instead of being a long interger, it should hold year, month, date, hour, minute, second, as separate fields. It might be even good to store the calendar and time zone this date is associated with.
In our natural conversation, if setup an appointment at Nov. 1, 2013 1pm NY Time, this is a DateTime. It is NOT a Calendar. So we should be able to converse like this in Java as well.
When Date is stored as a long integer (of mili seconds since Jan 1 1970 or something), calculating its current date depends on the calendar. Different calendars will give different date. This is from the prospective of giving an absolute time (eg 1 trillion seconds after Big Bang). But often we also need a convenient way of conversation, like an object encapsulating year, month etc.
I wonder if there are new advances in Java to reconcile these 2 objectives. Maybe my java knowledge is too old.
Btw “date” is usually tagged as “obsolete / deprecated” (I dont know exactly why) – something about it is wrote there
Java: Why is the Date constructor deprecated, and what do I use instead?
It looks like it’s a problem of the constructor only- way via new Date(int year, int month, int day), recommended way is via Calendar and set params separately .. (Calendar cal = Calendar.getInstance();