JavaRush /Java Blog /Random EN /An intuitive, robust library for working with times and d...
theGrass
Level 24
Саратов

An intuitive, robust library for working with times and dates is finally available in Java (Part 1).

Published in the Random EN group
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.
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 . Here is a small list of existing problems in its implementation:
  • 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.
    In 2001, the Joda-Time project was created . His goal was simple - to create a high-quality library for working with dates and times in Java . It took some time, but version 1.0 was eventually released and quickly became very popular and widely used. Over time, developers increasingly demanded that a library of similar convenience be provided as part of the JDK . With the participation of Michael Nascimento Santos from Brazil, the JSR-310 project was launched , which is the official process for creating and integrating a new API for working with dates and times in the JDK .
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
    Most developers will mostly use the base package and formatting, and perhaps java.time.temporal . So, even though 68 new types have been added, developers will only use about a third of them.
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.
Time and date as values
    It's worth spending a little time understanding what makes LocalDate a value. Values ​​are simple data types that are completely interchangeable; when they are equal, the identity of the objects becomes meaningless. A classic example of a value class is String . We compare strings using equals() , and we don't care whether the objects are identical when compared with the == operator . Most of the classes for working with dates and times are also values. So, comparing them using the == operator is a bad idea, as stated in the documentation. For those interested in learning more, check out my recent definition of VALJOs , which outlines a strict set of rules that value objects in Java must follow , including immutability, factory methods, and proper definition of equals() , hashCode , toString() , and compareTo . () .
Alternative calendars
The LocalDate     class , like all the main classes in java.time , is bound to a single calendar - as described in the ISO-8601 standard . Standard 8601 describes the worldwide standard calendar, also known as the Gregorian calendar. A standard year includes 365 days, a leap year - 366. Every fourth year is a leap year unless it is divisible by 100 or is divisible by 400. The year before the first year of a new era is considered zero for ease of calculation. The first consequence of this being the default system is that the results do not always match those calculated using GregorianCalendar . The GregorianCalendar class has a built-in switch to the Julian system for all dates before October 15, 1582. In the Julian system, every fourth year was a leap year, without exception. The question is, since the transition from one system to another is a historical fact, why doesn't java.time model it? Yes, because different countries switched to the Gregorian system at different times, and considering only the date of the Vatican transition we will get incorrect data for most other countries. For example, the British Empire, including the colonies in North America, switched to the Gregorian calendar on September 14, 1752, almost 200 years later. Russia did not change its calendar until February 14, 1918, and Sweden’s transition is generally a murky matter. As a result, the actual meaning of dates before 1918 varies greatly depending on circumstances. The authors of the LocalDate code made a completely rational decision not to model the transition from the Julian calendar to the Gregorian calendar at all, in order to avoid discrepancies. The second consequence of using ISO-8601 as the default calendar in all core classes is that an additional set of classes is required to handle the remaining calendars. The Chronology interface is the basis for working with alternative calendars, allowing you to find the desired calendar by locale name. Java 8 comes with 4 additional calendars - Thai Buddhist, Mingguo (Taiwanese), Japanese and Islamic. Other calendars may come with programs. Each calendar has a special date class such as ThaiBuddhistDate , MinguoDate , JapaneseDate and HijrahDate . It makes sense to use them in very highly localized applications, such as those for the Japanese government. An additional interface, ChronoLocalDate , is used as a core abstraction of the four classes above along with LocalDate, which allows you to write code independent of the calendar type used. Although this abstraction exists, its use is not recommended. Understanding why this abstraction is not recommended is important to understanding how the entire java.time API works . The bottom line is that most of the code that is written without reference to a specific calendar turns out to be non-working. For example, you cannot be sure that there are 12 months in a year, but some developers add 12 months and think that they have added a whole year. You cannot be sure that all months contain approximately the same number of days - in the Coptic calendar there are 12 months of 30 days, and 1 month of five or six days. Also, you cannot be sure that the number of the next year will be 1 more than the current one, because in the Japanese calendar, years are counted from the proclamation of the next emperor (in this case, even 2 days of the same month can belong to different years). The only way to write high-quality and working code that works with several calendars at once is that the core of your code, which performs all operations on dates and times, must be written using a standard calendar, and only when entering/outputting dates should it be converted to other calendar systems. That is, it is recommended to use LocalDate for storage and all date manipulations in your application. And only when localizing input and output dates should you use ChronoLocalDate , which is usually obtained from the calendar class stored in the user profile. True, most applications do not need such serious localization. If you need a more detailed explanation of everything described in this chapter, welcome to the documentation of the ChronoLocalDate class .      Continuation of the article      Original article
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION