1 Why do I need a new date and time library?
A perennial annoyance for Java developers is the lack of support for date and time use cases for ordinary developers.
For example, existing classes (such as java.util.date and SimpleDateFormatter) are non-thread-safe, leading to potential concurrency problems for users that the average developer would expect to deal with when writing date-handling code. Some date and time classes also exhibit fairly poor API design. For example, the year java.util.Date starts at 1900, the months start at 1, and the days start at 0, which is not very intuitive.
These and other issues have led to the flourishing of third-party date and Time libraries, such as Joda-time.
To address these issues and provide better support in the JDK kernel, a new date and time API has been designed for Java SE 8 without these issues. The project was co-led by Joda-time (Stephen Colebourne) and Oracle authors under JSR 310, appearing in the Java SE 8 package java.Time.
2 core Ideas
Immutable value class
One of the serious drawbacks of Java’s existing formatters is that they are not thread-safe. This places a burden on the developer to use them in a thread-safe manner and consider concurrency issues in their daily work with date-processing code. The new API avoids this problem by ensuring that all of its core classes are immutable and express well-defined values.
domain-driven
The new API model is very precise with Date and Time rigorously representing the different use case class fields. This differs from previous Java libraries, which were poor in this respect. For example, java.util.date represents a moment on the timeline (a wrapper for milliseconds since the UNIX era), but if toString() is called, it turns out that it has a time zone, causing confusion among developers.
This focus on domain-driven design provides long-term benefits in terms of clarity and ease of understanding, but when migrating from previous apis to Java SE 8, you may need to consider your application’s domain-date model.
Separate them in chronological order
The new API makes it possible to use different calendar systems to meet the needs of users in certain parts of the world, such as Japan or Thailand, who are not necessarily ISO-8601 compliant. Doing so imposes no additional burden on most developers, who simply need to use standard chronological order.
3 LocalDate, LocalTime, and LocalDateTime
3.1 Advantages over Date
- Date and SimpleDateFormatter are not thread-safe, while LocalDate and LocalTime, like String, are final – thread-safe and cannot be modified.
- Date The months start at 0. January is 0 and December is 11. LocalDate month and week are changed to enum.
- Date is a “universal interface” that contains the Date, time, and number of milliseconds. Having some data is useless if all you need is the date or time. In the new Java 8, dates and times are explicitly divided into LocalDate and LocalTime. LocalDate cannot contain a time, and LocalTime cannot contain a date. Of course, LocalDateTime can contain both date and time.
- Date (e.g., push back a few days/push back a few days/calculate whether a year is a leap year/calculate the first day, the last day, the first Monday of a month, etc.)
Both are local because they represent the date and time from the perspective of the observer, such as a calendar on a desk or a clock on a wall.
There are also compound classesLocalDateTime
This is a pairing of LocalDate and LocalTime.
Time zones separate the context of different observers and are set aside here; These local classes should be used when context is not required. These classes can even be used to represent time on distributed systems with consistent time zones.
Commonly used API
now()
Gets the current date in the default time zone system clock. This method queries the system clock in the default time zone to get the current date. Using this method will prevent the use of an alternate clock for testing because the clock is hard-coded.
Easy to add or subtract days without having to do the calculations yourself!
plusMonths
Returns the specified number of months LocalDate added to this copy. This method will specify the amount in the months field in three steps:
- Adds the entered number of months to the month-of-year field
- Verify whether the result date is invalid
- Adjust day-of-month, if necessary, to the last valid date
For example, 2007-03-31 plus a month would result in an invalid date of April 31, 2007. Instead of returning an invalid result, 2007-04-30 is the last valid date. The immutability of the calling instance is not affected by this method.
4 Creating an Object
The factory method
All of the core classes in the new API are constructed using skilled factory methods.
- When a value is constructed through its constituent field, it is called a factory of
- When converting from other types, the factory is called from
- There are also parsing methods that take strings as arguments.
Getter agreed
- To get the value from the Java SE 8 class, standard Java getter conventions are used as follows:
Changing object values
You can also change the object value to perform the calculation. Because all the core classes in the new API are immutable, these methods with are called and return new objects instead of using setters. There are also calculation methods based on different fields.
regulator
The new API also has the concept of a adjuster — a block of code that can be used to wrap common processing logic. You can write a WithAdjuster to set one or more fields, and a PlusAdjuster to add or subtract fields. Value classes can also act as modifiers, in which case they update the values of the fields they represent. Built-in regulators are defined by the new API, but if you have specific business logic that you want to reuse, you can write your own.
import static java.time.temporal.TemporalAdjusters.*;
LocalDateTime timePoint = ...
foo = timePoint.with(lastDayOfMonth());
bar = timePoint.with(previousOrSame(ChronoUnit.WEDNESDAY));
// Use value classes as adjusters
timePoint.with(LocalTime.now());
Copy the code
5 truncation
The new API supports different points of accuracy by providing types that represent dates, times, and dates with time, but clearly the concept of accuracy is higher than that.
The truncatedTo method exists to support this use case, where it allows you to truncate values to fields as follows
LocalTime truncatedTime = time.truncatedTo(ChronoUnit.SECONDS);
Copy the code
Six time zones
The native classes we looked at earlier abstract away the complexity introduced by time zones. A time zone is a set of rules that correspond to areas of the same standard time. There are about 40 of them. Time zones are defined by their offset from Coordinated Universal Time (UTC). They move roughly in sync, but with some differences.
Time zones can be represented by two identifiers: abbreviations, such as “PLT”, and longer ones, such as “Asia/Karachi”. When designing your application, consider when time zones are appropriate and when offsets are needed.
ZoneId
Is the identifier of the region. Each ZoneId rule corresponds to rules that define the time zone for that location. When designing software, if you consider using strings such as “PLT” or “Asia/Karachi”, you should use this domain class instead. An example use case is to store a user’s preferences for its time zone.
ZoneOffset
Is the time period of difference between Greenwich/UTC and time zones. Available in specificZoneId
Is parsed at a specific time, as shown in Listing 7.
ZoneOffset offset = ZoneOffset.of("+ 2");
Copy the code
Class 7 time zone
ZonedDateTime is a date and time with a fully qualified time zone. This solves any offset at any point in time. Best practice: To represent dates and times independent of the context of a particular server, use ZonedDateTime.
ZonedDateTime.parse("2007-12-03T10:15:30+01:00[Europe/Paris]");
Copy the code
OffsetDateTime is the date and time with the resolved offset. This is useful for serializing data to a database and should also be used as a serialization format for logging timestamps if the server is in a different time zone.
OffsetTime is the time with a definite offset as follows:
OffsetTime time = OffsetTime.now();
// changes offset, while keeping the same point on the timeline
OffsetTime sameTimeDifferentOffset = time.withOffsetSameInstant(
offset);
// changes the offset, and updates the point on the timeline
OffsetTime changeTimeWithNewOffset = time.withOffsetSameLocal(
offset);
// Can also create new object with altered fields as before
changeTimeWithNewOffset
.withHour(3)
.plusSeconds(2);
OffsetTime time = OffsetTime.now();
// changes offset, while keeping the same point on the timeline
OffsetTime sameTimeDifferentOffset = time.withOffsetSameInstant(
offset);
// changes the offset, and updates the point on the timeline
OffsetTime changeTimeWithNewOffset = time.withOffsetSameLocal(
offset);
// Can also create new object with altered fields as before
changeTimeWithNewOffset
.withHour(3)
.plusSeconds(2);
Copy the code
Java already has a TimeZone class, java.util.TimeZone, but Java SE 8 does not use it because all JSR 310 classes are immutable and time zones are variable.
8 Period
Period stands for something like “three months and one day.” It’s the distance along the time line. This is in stark contrast to the other classes we’ve discussed so far, which are the focus of the timeline.
// 3 years, 2 months, 1 day
Period period = Period.of(3.2.1);
// Use period to change the date value
LocalDate newDate = oldDate.plus(period);
ZonedDateTime newDateTime = oldDateTime.minus(period);
// Components of a Period are represented by ChronoUnit values
assertEquals(1, period.get(ChronoUnit.DAYS));
// 3 years, 2 months, 1 day
Period period = Period.of(3.2.1);
// You can modify the values of dates using periods
LocalDate newDate = oldDate.plus(period);
ZonedDateTime newDateTime = oldDateTime.minus(period);
// Components of a Period are represented by ChronoUnit values
assertEquals(1, period.get(ChronoUnit.DAYS));
Copy the code
9 Duration
Duration is a distance measured in time along a time line that accomplishes a similar purpose, Period, but with different precision:
Duration 3 s and 5 ns
Duration duration = Duration.ofSeconds(3.5);
Duration oneDay = Duration.between(today, yesterday);
// A duration of 3 seconds and 5 nanoseconds
Duration duration = Duration.ofSeconds(3.5);
Duration oneDay = Duration.between(today, yesterday);
Copy the code
You can perform normal addition, subtraction, and “with” operations on a Duration instance, and you can use Duration to modify the value of a date or time.
10 chronology
To meet the needs of developers using non-ISO calendar systems, Java SE 8 introduced Chronology, which stands for the calendar system and acts as a factory for points in time in the calendar system. There are also some interfaces that correspond to core point in time classes, but pass
Chronology:
ChronoLocalDate
ChronoLocalDateTime
ChronoZonedDateTime
Chronology:
ChronoLocalDate
ChronoLocalDateTime
ChronoZonedDateTime
Copy the code
These classes are only suitable for developers who are developing highly internationalized applications and need to consider a local calendar system, and should not be used by developers who do not have these requirements. Some calendar systems don’t even have the concept of a month or a week, so calculations need to be done through a very general field API.
11 Other apis
Java SE 8 also has classes for some other common use cases. There is a MonthDay class with a Month and a Day pair that is useful for representing birthdays. The YearMonth class covers use cases with credit card start and expiration dates and scenarios where people don’t specify dates.
JDBC in Java SE 8 will support these new types without changing the public JDBC API. The existing generic setObject and getObject methods are sufficient.
These types can be mapped to vendor-specific database types or ANSI SQL types.
12 summary
Java SE 8 comes with a new date and time API in java.time, providing developers with much improved security and functionality. The new API models the domain well and provides a large number of classes for modeling a variety of developer use cases.