[9.3] Create and manipulate calendar data using classes from java.time.LocalDateTime, java.time.LocalDate, java.time.LocalTime, java.time.format.DateTimeFormatter, java.time.Period3
The new Date and Time API in Java 8 simplifies working with date and time objects. It includes classes and interfaces with simple and informative method names. As you work with the classes LocalDate, LocalTime, LocalDateTime, Period, and DateTimeFormatter in this section, you’ll notice that these classes define methods with similar names (which have similar purposes). Table 4.1 lists the method prefix, its type, and its use (from Oracle Java documentation).
Prefix |
Method type |
Use |
---|---|---|
of | static | Creates an instance where the factory is primarily validating the input parameters, not converting them. |
from | static | Converts the input parameters to an instance of the target class, which may involve losing information from the input. |
parse | static | Parses the input string to produce an instance of the target class. |
format | instance | Uses the specified formatter to format the values in the temporal object to produce a string. |
get | instance | Returns a part of the state of the target object. |
is | instance | Queries the state of the target object. |
with | instance | Returns a copy of the target object with one element changed; this is the immutable equivalent to a set method on a JavaBean. |
plus | instance | Returns a copy of the target object with an amount of time added. |
minus | instance | Returns a copy of the target object with an amount of time subtracted. |
to | instance | Converts this object to another type. |
at | instance | Combines this object with another. |
The preceding table might not seem to add a lot of value at this point. But as you go through the following sections, you’ll realize the similarity in the names of the methods that are defined in the date and time classes.
Let’s get started with the class LocalDate.
To store dates like a birthday or anniversary, visiting a place, or starting a job, school, or college, you don’t need to store the time. LocalDate will work perfectly in this case.
LocalDate can be used to store dates like 2015-12-27 without time or time zones. LocalDate instances are immutable and hence safe to be used in a multithreaded environment.
The LocalDate constructor is marked private, so you must use one of the factory methods to instantiate it. The static method of() accepts year, month, and day of month:
In the new Date and Time API, introduced with Java 8, January is represented by int value 1 and not 0. The old Calendar-based API hasn’t changed in Java 8 and still uses 0-based month numbering.
To get the current date from the system clock, use the static method now():
LocalDate date3 = LocalDate.now();
You can also parse a string in the format 2016-02-27 to instantiate LocalDate. Here’s an example:
LocalDate date2 = LocalDate.parse("2025-08-09");
If you pass invalid values to parse() or of(), you’ll get DateTimeParseException. The format of the string passed to parse() must be exactly of the format 9999-99-99. The month and date values passed to parse() must be of two digits; a single digit is considered an invalid value. For days and months with values 1–9, pass 01–09.
You can use instance methods like getXX() to query LocalDate on its year, month, and date values. The date can be queried as day-of-month, day-of-week, and day-of-year. The month value can be retrieved as the enum constant Month or as an int value:
LocalDate date = LocalDate.parse("2020-08-30"); System.out.println(date.getDayOfMonth()); System.out.println(date.getDayOfWeek()); System.out.println(date.getDayOfYear()); System.out.println(date.getMonth()); System.out.println(date.getMonthValue()); System.out.println(date.getYear());
The output of the preceding code looks like this:
30 SUNDAY 243 AUGUST 8 2020
You can use the instance methods isAfter() or isBefore() to determine whether a date is chronologically before or after another date:
The LocalDate class defines methods with the names minusXX(), plusXX(), and withXX() to manipulate the date values. The API architects have used the names that make their purpose explicit. Because LocalDate is an immutable class, all the methods create and return a copy. The minusXX() methods return a copy of the date with the specified days, months, or years subtracted from it:
LocalDate bday = LocalDate.of(2052,03,10); System.out.println(bday.minusDays(10)); System.out.println(bday.minusMonths(2)); System.out.println(bday.minusWeeks(30)); System.out.println(bday.minusYears(1));
Here’s the output of the preceding code:
2052-02-29 2052-01-10 2051-08-13 2051-03-10
LocalDate is immutable. All the methods that seem to manipulate its value return a copy of the LocalDate instance on which it’s called.
The plusXX() methods return a copy of the date instance after adding the specified days, months, or years to it:
LocalDate launchCompany = LocalDate.of(2016,02,29); System.out.println(launchCompany.plusDays(1)); System.out.println(launchCompany.plusMonths(1)); System.out.println(launchCompany.plusWeeks(7)); System.out.println(launchCompany.plusYears(1));
Here’s the output of the preceding code:
2016-03-01 2016-03-29 2016-04-18 2017-02-28
All additions, subtractions, or replacements to LocalDate consider leap years.
The withXX() methods return a copy of the date instance replacing the specified day, month, or year in it:
LocalDate firstSex = LocalDate.of(2036,02,28); System.out.println(firstSex.withDayOfMonth(1)); System.out.println(firstSex.withDayOfYear(1)); System.out.println(firstSex.withMonth(7)); System.out.println(firstSex.withYear(1));
The output of the preceding code looks like this:
2036-02-01 2036-01-01 2036-07-28 0001-02-28
The LocalDate class defines methods to convert it to LocalDateTime and long (representing the epoch date).
The LocalDate class defines overloaded atTime() instance methods. These methods combine LocalDate with time to create and return LocalDateTime, which stores both the date and time (the LocalDateTime class is covered in the next section):
LocalDate interviewDate = LocalDate.of(2016,02,28); System.out.println(interviewDate.atTime(16, 30)); System.out.println(interviewDate.atTime(16, 30, 20)); System.out.println(interviewDate.atTime(16, 30, 20, 300)); System.out.println(interviewDate.atTime(LocalTime.of(16, 30)));
Here’s the output of the preceding code:
2016-02-28T16:30 2016-02-28T16:30:20 2016-02-28T16:30:20.000000300 2016-02-28T16:30
If you pass any invalid hours, minutes, or seconds value to the method atTime, it will throw a DateTimeException at runtime.
You can use the method toEpochDay() to convert LocalDate to the epoch date—the count of days from January 1, 1970:
LocalDate launchBook = LocalDate.of(2016,2,8); LocalDate aDate = LocalDate.of(1970,1,8); System.out.println(launchBook.toEpochDay()); System.out.println(aDate.toEpochDay());
Here’s the output of the preceding code:
16839 7
In standard date and time, the epoch date refers to January 1, 1970, 00:00:00 GMT.
To store times like breakfast, conference talk start time, or in-store sale end time, you can use LocalTime. It stores time in the format hours-minutes-seconds (without a time zone) and to nanosecond precision. So you’re sure to see methods that accept nanoseconds as method arguments or methods that return this value. Like LocalDate, LocalTime is also immutable and hence safe to be used in a multithreaded environment.
The LocalTime constructor is private, so you must use one of the factory methods to instantiate it. The static method of() accepts hours, minutes, seconds, and nanoseconds:
The of() method uses a 24-hour clock to specify the hour value. What happens if you pass out-of-range values for hours, minutes, or seconds to of()? In this case, you’ll get a runtime exception, DateTimeException. You’ll get a compiler error if the range of values passed to a method doesn’t comply with the method’s argument type. Here’s an example:
LocalTime doesn’t define a method to pass a.m. or p.m. Use values 0–23 to define hours. If you pass out-of-range values to either hours, minutes, or seconds, you’ll get a runtime exception.
To get the current time from the system clock, use the static method now():
LocalDate date3 = LocalTime.now();
You can parse a string to instantiate LocalTime by using its static method parse(). You can either pass a string in the format 15:08:23 (hours:minutes:seconds) or parse any text using DateTimeFormatter (covered in the next section):
LocalTime time = LocalTime.parse("15:08:23");
If you pass invalid string values to parse(), the code will compile but will throw a runtime exception. If you don’t pass a DateTimeFormatter, the format of the string passed to parse() must be exactly of the format 99:99:99. The hours and minutes values passed to parse() must be two digits; a single digit is considered an invalid value. For hours and minutes with the value 0–9, pass 00–09.
You can use constants from the LocalTime class to work with predefined times:
Does that make you wonder whether the minimum and midnight times are equal? See for yourself; the following code outputs true:
18.116.67.70