Java finally has an intuitive, reliable way to work with dates and times. The principles of date and time are fundamental in many applications. Various things like birth dates, rental dates, event times, and store opening hours are all based on dates and times, but Java SE didn't provide a convenient way to work with them. Starting with Java SE 8 , there was a set of java.time packages - which provide a well-structured API for working with dates and times.
Here is a small list of existing problems in its implementation:
Background
When Java first came out, in version 1.0 , the only class for working with dates and times was java.util.Date . The first thing the developers noticed was that it does not represent a “date”. In fact, it represents a moment in time, accurate to milliseconds, measured from the date January 1, 1970. However, based on the fact that Date ’s toString() method displays the date and time in the time zone specified in the machine’s java settings , some developers mistakenly concluded that Date can work with time zones. Fixing this class turned out to be so difficult (or so lazy) that in version 1.1 we had to add a new class - java.util.Calendar . Unfortunately, the Calendar class turned out to be not much better than Date .- Changeable. Classes such as date and time should be immutable.
- Offsets. Years in Date start from 1900, months in both classes start from zero.
- Names. Date is not actually a "date", and Calendar is not a calendar.
- Formatting. Formatting only works with Date, not Calendar, and is not thread safe.
Review
The new java.time API contains 5 packages:- java.time - the base package containing objects to store values
- java.time.chrono - provides access to different calendars
- java.time.format - date and time formatting and recognition
- java.time.temporal - low-level libraries and advanced functionality
- java.time.zone - classes for working with time zones
Dates
The LocalDate class is one of the most important in the new API . It contains an immutable value that represents a date. You cannot set the time or time zone. The name "local" may be familiar to you from Joda-Time , and originally comes from the ISO-8601 standard . It means precisely the absence of a time zone. Essentially, LocalDate is a description of a date, such as "April 5th, 2014". The actual time of this date will differ depending on your time zone. For example, in Australia this date will be 10 hours earlier than in London, and 18 hours earlier than in San Francisco. The LocalDate class has all the commonly needed methods:LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)
In our example, we see a date created using a factory method (all constructors are private). Next we ask the object for some data. Please note that
the Month and
DayOfWeek enumerations are designed to make the code more readable and reliable. In the following example we will see how to modify the date. Since the class is immutable, the result will be new objects, but the original one will remain as it was.
LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09
These are relatively simple changes, but often you need to make more complex date modifications. There is a special mechanism for this in
the java.time API - TemporalAdjuster . Its purpose is to provide a built-in tool that allows you to manipulate dates, for example getting an object corresponding to the last day of the month. Some of them are included in
the API , but you can add your own. Using modifiers is very easy, but it requires static imports:
import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));
Using modifiers greatly simplifies your code. Nobody wants to see a lot of manual date manipulation. If some kind of date manipulation occurs several times in your project, write your own modifier and your team can use it as an already written and tested component.