You can use instance methods like getXX() to query LocalTime on its hour, minutes, seconds, and nanoseconds. All these methods return an int value:
LocalTime time = LocalTime.of(16, 20, 12, 98547); System.out.println(time.getHour()); System.out.println(time.getMinute()); System.out.println(time.getSecond()); System.out.println(time.getNano());
Here’s the output:
16 20 12 98547
The correct method names for querying LocalTime are get-Hour(), getMinute(), getSecond(), and getNano(). Watch out for exam questions that use invalid method names like getHours(), getMinutes(), getSeconds(), or getNanoSeconds().
You can use the instance methods isAfter() and isBefore() to check whether a time is after or before the specified time. The following code outputs true:
You can use the instance methods minusHours(), minusMinutes(), minusSeconds(), and minusNanos() to create and return a copy of LocalTime instances with the specified period subtracted. The method names are self-explanatory. For example, minus-Hours(int) returns a copy of a LocalTime instance with the specified period in hours subtracted. The following example calculates and outputs the time when Shreya should leave from her office to watch a movie, given that the movie starts at 21:00 hours and it takes 35 minutes to commute to the movie theater:
LocalTime movieStartTime = LocalTime.parse("21:00:00"); int commuteMin = 35; LocalTime shreyaStartTime = movieStartTime.minusMinutes(commuteMin); System.out.println("Start by " + shreyaStartTime + " from office");
Here’s the output of the preceding code:
Start by 20:25 from office
Unlike the getXXX() methods, minusXXX() methods use the plural form: getHour() versus minusHours(), getMinute() versus minusMinutes(), getSecond() versus minusSeconds(), and getNano() versus minusNanos().
The plusHours(), plusMinutes(), plusSeconds(), and plusNanos() methods accept long values and add the specified hours, minutes, seconds, or nanoseconds to time, returning its copy as LocalTime. The following example uses the addSeconds() and isAfter() methods to add seconds to a time and compares it with another time:
int worldRecord = 10; LocalTime raceStartTime = LocalTime.of(8, 10, 55); LocalTime raceEndTime = LocalTime.of(8, 11, 11); if (raceStartTime.plusSeconds(worldRecord).isAfter(raceEndTime)) System.out.println("New world record"); else System.out.println("Try harder");
The output of the preceding code looks like this:
Try harder
LocalTime is immutable. Calling any method on its instance won’t modify its value.
The withHour(), withMinute(), withSecond(), and withNano() methods accept an int value and return a copy of LocalTime with the specified value altered. In the following example, a new LocalTime instance with the minute value 00 is created:
LocalTime startTime = LocalTime.of(5, 7, 9); if (startTime.getMinute() < 30) startTime = startTime.withMinute(0); System.out.println(startTime);
Here’s the output:
05:00:09
The LocalTime class defines the atDate() method to combine a LocalDate with itself to create LocalDateTime:
LocalTime time = LocalTime.of(14, 10, 0); LocalDate date = LocalDate.of(2016,02,28); LocalDateTime dateTime = time.atDate(date); System.out.println(dateTime);
Here’s the output:
2016-02-28T14:10
The class LocalTime defines the method atDate(), which can be passed a LocalDate instance to create a LocalDateTime instance.
If you want to store both date and time (without the time zone), use the class LocalDateTime. It stores a value like 2050-06-18T14:20:30:908765 (year-month-dayThours:minutes:seconds:nanoseconds).
The LocalDateTime class uses the letter T to separate date and time values in its printed value.
You can consider this class to offer the functionality of both the LocalDate and Local-Time classes. This class defines similar methods as those defined by the LocalDate and LocalTime classes. So instead of discussing individual methods of this class, here’s an example that covers the important methods of this class:
In the next section, you’ll discover how you can perform calculations with date and time using the Period class.
People often talk about periods of years, months, or days. With the Java 8 Date API, you can use the Period class to do so. The Period class represents a date-based amount in years, months, and days, like 2 years, 5 months, and 10 days. To work with a time-based amount in seconds and nanoseconds, you can use the Duration class.
The Duration class can be used to store amounts of time like 1 hour, 36 minutes, or 29.4 seconds. But this class isn’t explicitly covered in this exam (and this book). It’s covered in the OCP Java SE 8 Programmer II exam.
You can add or subtract Period instances from the LocalDate and LocalDateTime classes. Period is also an immutable class and hence safe to use in a multithreaded environment. Let’s get started by instantiating Period.
With a private constructor, the Period class defines multiple factory methods to create its instances. The static methods of(), ofYears(), ofMonths(), ofWeeks(), and ofDays() accept int values to create periods of years, months, weeks, or days:
A period of 35 days is not stored as 1 month and 5 days. Its individual elements, that is, days, months, and years, are stored the way it is initialized.
You can also define negative periods by passing negative integer values to all the preceding methods. Here’s a quick example:
You can define positive or negative periods of time. For example, you can define Period instances representing 15 or -15 days.
You can also parse a string to instantiate Period by using its static method parse. This method parses string values of the format PnYnMnD or PnW, where n represents a number and the letters (P, Y, M, D, and W) represent parse, year, month, day, and week. These letters can exist in lower- or uppercase. Each string must start with the letter p or P and must include at least one of the four sections, that is, year, month, week, or day. For the string format PnW, the count of weeks is multiplied by 7 to get the number of days. You can also define negative periods using parse(). If you precede the complete string value passed to parse() with a negative sign (-), it’s applied to all values. If you place a negative sign just before an individual number, it applies only to that section. Here are some examples to instantiate a period of five years (notice the use of uppercase and lowercase letters and + and – signs):
The following examples define periods of separate durations:
Period p5Yrs7 = Period.parse("P5y1m2d"); Period p5Yrs8 = Period.parse("p9m"); Period p5Yrs9 = Period.parse("P60d"); Period p5Yrs10 = Period.parse("-P5W");
When passed to System.out.println(), the variables in the preceding code will result in the following output:
P5Y1M2D P9M P60D P-35D
If you pass invalid string values to parse(), the code will compile but will throw a runtime exception.
You can also use the static method between(LocalDate dateInclusive, LocalDate dateExclusive) to instantiate Period:
The static method between accepts two LocalDate instances and returns a Period instance representing the number of years, days, and months between the two dates. The first date is included, but the second date is excluded in the returned Period. Here’s a quick way to remember it: period = end date – start date.
In everyday life, it’s common to add or subtract periods of days, months, or years from a date. The Period class implements the interface TemporalAmount, so it can be used with the methods plus() and minus() defined in the classes LocalDateTime and LocalDate. The following example adds a period of a day to a LocalDate instance:
LocalDate date = LocalDate.of(2052, 01, 31); System.out.println(date.plus(Period.ofDays(1)));
Here’s the output of the preceding code:
2052-02-01
What happens when you add a period of a month to January 31 of any year? Do you get the last day of February or the first day of March? The following example adds a period of a month to a LocalDateTime instance:
LocalDateTime dateTime = LocalDateTime.parse("2052-01-31T14:18:36"); System.out.println(dateTime.plus(Period.ofMonths(1)));
The output of the preceding code looks like this:
2052-02-29T14:18:36
Because Period instances can represent positive or negative periods (like 15 days or -15 days), you can subtract days from a LocalDate or LocalDateTime by calling the method plus.
Similarly, you can use the method minus() with the classes LocalDate and LocalDateTime to subtract a period of years, months, weeks, or days:
LocalDateTime dateTime = LocalDateTime.parse("2020-01-31T14:18:36"); System.out.println(dateTime.minus(Period.ofYears(2))); LocalDate date = LocalDate.of(2052, 01, 31); System.out.println(date.minus(Period.ofWeeks(4)));
Here’s the output:
2018-01-31T14:18:36 2052-01-03
You can use the instance methods getYears(), getMonths(), and getDays() to query a Period instance on its years, months, and days. All these methods return an int value:
Period period = Period.of(2,4,40); System.out.println(period.getYears()); System.out.println(period.getMonths()); System.out.println(period.getDays());
The preceding code outputs the following:
2 4 40
When you initialize a Period instance with days more than 31 or months more than 12, it doesn’t recalculate its years, months, or days components-.
You can query whether any of three units of a Period is negative using the methods isNegative and isZero. A Period instance is zero if all three units are zero. The isNegative method returns true if at least one of its three components is strictly negative (<0):
You can use the instance methods minus(TemporalAmount), minusDays(long), minus-Weeks(long), minusMonths(long), minusYears(long), and multipliedBy(int) to create and return a copy of Period instances with the specified period subtracted or modified. The method names are self-explanatory. For an example, minusDays(long) returns a copy of a Period instance with the specified days subtracted. You can use the following example to send out reminders to your friends (limited to printing a message) for an event, say a birthday celebration, if it’s due in 10 days:
LocalDate bday = LocalDate.of(2020, 10, 29); LocalDate today = LocalDate.now(); Period period10Days = Period.of(0, 0, 10); if (bday.minus(period10Days).isBefore(today)) System.out.println("Time to send out reminders to friends");
In the class Period, both the getXXX() methods and minusXXX() methods use the plural form: getYears(), minusHours().
What happens when you subtract a Period representing one month (P1M) from a Period representing 10 days (P10D)? Would you get a Period representing 20 days or a Period representing -1 month and 10 days? Let’s find out using the following code, which also includes quick sample code on the usage of all the minusXXX methods:
Period period10Days = Period.of(0, 0, 10); Period period1Month = Period.of(0, 1, 0); System.out.println(period10Days.minus(period1Month)); System.out.println(period10Days.minusDays(5)); System.out.println(period10Days.minusMonths(5)); System.out.println(period10Days.minusYears(5));
Here’s the output:
P-1M10D P5D P-5M10D P-5Y10D
When you subtract Period instances using the minusXXX() methods, the individual elements are subtracted. Subtracting P10D from P1M returns P1M-10D and not P20D.
The Period class defines multipliedBy(int), which multiplies each element in the period by the integer value:
The method multipliedBy(int) in the class Period is used to modify all elements of a Period instance. Period doesn’t define a “divideBy()” method. Both the getXXX() methods and minusXXX() methods use the plural form getYears(), minusHours().
The plus(TemporalAmount), plusDays(long), plusWeeks(long), plusMonths(long), and plusYears(long) methods add to Period instances and return the modified value as a Period. Like the minusXXX() methods, all the plusXXX() methods add individual elements:
Period period5Month = Period.of(0, 5, 0); Period period10Month = Period.of(0, 10, 0); Period period10Days = Period.of(0, 0, 10); System.out.println(period5Month.plus(period10Month)); System.out.println(period10Days.plusDays(35)); System.out.println(period10Days.plusMonths(5)); System.out.println(period10Days.plusYears(5));
The output of the preceding code is as follows:
P15M P45D P5M10D P5Y10D
Adding a Period of 10 months to a Period of 5 months gives 15 months, not 1 year and 3 months.
The withDays(), withMonths(), and withYears() methods accept an int value and return a copy of Period with the specified value altered.
The method toTotalMonths() returns the total number of months in the period by multiplying the number of years by 12 and adding the number of months:
A Period can be used as an argument to the LocalDate one-parameter plus() and minus() methods. What happens when you want to add 3 months and 10 days to a given date? The number of months per year is constant but the number of days per month isn’t. A glimpse at the plus() and minus() methods in the LocalDate source code shows that years are converted to months and months are always handled before days.
In the next section, you’ll work with the class DateTimeFormatter.
Defined in the package java.time.format, the class DateTimeFormatter can be used to format and parse date and time objects. In this section, you’ll use this class to format or parse date and time objects using predefined constants (like ISO_LOCAL_DATE), using patterns (like yyyy-MM-dd) or localized styles like long or short.
The first step to format or parse a date or time object is to access a DateTime-Formatter and then call format or parse methods on either date or time objects or DateTimeFormatter. Let’s work in detail with these steps, starting with multiple ways to instantiate or access a DateTimeFormatter object.
You can instantiate or access a DateTimeFormatter object in multiple ways:
Starting with the first option, you can instantiate a DateTimeFormatter to work with date, time, or date/time objects by calling its ofXXX static method and passing it a FormatStyle value (FormatStyle.FULL, FormatStyle.LONG, FormatStyle.MEDIUM, or FormatStyle.SHORT):
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL); DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG); DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT);
The methods ofLocalizedDate, ofLocalizedTime, and ofLocalizedDateTime format date and time objects according to the locale (language, region, or country) of the system on which your code executes. So the output might vary slightly across systems.
Table 4.2 shows how a date or time object will be formatted by using the different Format-Style values.
FormatStyle |
Example |
---|---|
FormatStyle.FULL | Saturday, August 11, 2057 |
FormatStyle.LONG | August 11, 2057 |
FormatStyle.MEDIUM | Aug 11, 2057 |
FormatStyle.SHORT | 8/11/57 |
FormatStyle.FULL | |
FormatStyle.LONG | |
FormatStyle.MEDIUM | 2:30:15 PM |
FormatStyle.SHORT | 2:30 PM |
You can access a DateTimeFormatter object by using the public and static fields of this class:
DateTimeFormatter formatter5 = DateTimeFormatter.ISO_DATE;
Table 4.3 lists a few predefined formatters that are relevant for this exam.
Predefined formatter |
Example |
---|---|
BASIC_ISO_DATE | 20570811 |
ISO_DATE/ISO_LOCAL_DATE | 2057-08-11 |
ISO_TIME/ISO_LOCAL_TIME | 14:30:15.312 |
ISO_DATE_TIME/ISO_LOCAL_DATE_TIME | 2057-08-11T14:30:15.312 |
You can instantiate a DateTimeFormatter using a pattern (of letters and symbols) by using the static method ofPattern and passing it a string value:
DateTimeFormatter formatter6= DateTimeFormatter.ofPattern("yyyy MM dd");
You can use the preceding code to format a date, say August 11, 2057, as 2057 08 11. Table 4.4 lists the letters that can be used to define such patterns.
Symbol |
Meaning |
Example |
---|---|---|
y, Y | year | 2057; 57 |
M | month of year | 8; 08; Aug; August |
D | day of year | 223 |
d | day of month | 11 |
E | day of week | Sat |
e | localized day of week | 7; Sat |
a | a.m. or p.m. of day | pm |
h | clock hour of a.m./p.m. | 03 |
H | hour of day | 14 |
m | minute of hour | 30 |
s | second of minute | 15 |
' | escape for text |
A DateTimeFormatter can define rules to format or parse a date object, time object, or both.
To format a date or time object, you can use either the instance format method in date/time objects or the instance format method in the DateTimeFormatter class. Behind the scenes, the format method in date and time objects simply calls the format method in DateTimeFormatter. Table 4.5 lists the available format methods.
TemporalAccessor is an interface, implemented by the classes LocalDate, LocalTime, and LocalDateTime. You won’t get explicit questions on this interface on the exam.
Defined in |
Return type |
Method signature and description |
---|---|---|
LocalDate | String | format(DateTimeFormatter) Formats this date object using the specified DateTimeFormatter |
LocalTime | String | format(DateTimeFormatter) Formats this time object using the specified DateTimeFormatter |
LocalDateTime | String | format(DateTimeFormatter) Formats this date/time object using the specified DateTimeFormatter |
DateTimeFormatter | String | format(TemporalAccessor) Formats a date/time object using this formatter |
Watch out for the count and type of arguments passed to the instance method format. When calling format on a LocalDate, LocalTime, or LocalDateTime instance, pass a DateTimeFormatter instance as a method parameter. When calling format on DateTimeFormatter, pass a LocalDate, LocalTime, or LocalDateTime instance as a method argument.
The method format in DateTimeFormatter formats a date or time object to a String using the rules of the formatter. The following example formats a LocalDate object using the style FormatStyle (styles are listed in table 4.2):
What happens if you pass a time object (LocalTime) instead of a date object (LocalDate) in the preceding code? Will it compile or execute successfully (changes are shown in bold)?
The preceding code will compile successfully but won’t execute. It will throw a runtime exception because the formatter defines rules to format a date object (created using ofLocalizedDate()), but its format() is passed a time object.
If you pass a date object to the method format on a DateTimeFormatter instance that defines rules to format a time object, it will throw a runtime exception.
Formatting date and time objects using DateTimeFormatter, which are created using string patterns, is interesting (and confusing). Take note of the case of the letters used in the patterns. M and m or D and d are not the same. Also, using a pattern letter doesn’t specify the count of digits or texts. For an example, using Y or YYYY to format a date object returns the same results. Following are examples that use different patterns:
LocalDate date = LocalDate.of(2057,8,11); LocalTime time = LocalTime.of(14,30,15); DateTimeFormatter d1 = DateTimeFormatter.ofPattern("y"); DateTimeFormatter d2 = DateTimeFormatter.ofPattern("YYYY"); DateTimeFormatter d3 = DateTimeFormatter.ofPattern("Y M D"); DateTimeFormatter d4 = DateTimeFormatter.ofPattern("e"); DateTimeFormatter t1 = DateTimeFormatter.ofPattern("H h m s"); DateTimeFormatter t2 = DateTimeFormatter.ofPattern("'Time now:'HH mm a"); System.out.println(d1.format(date)); System.out.println(d2.format(date)); System.out.println(d3.format(date)); System.out.println(d4.format(date)); System.out.println(t1.format(time)); System.out.println(t2.format(time));
Here’s the output of the preceding code:
2057 2057 2057 8 223 7 14 2 30 15 Time now:14 30 PM
If you're confused between M, m, D, and d, remember that an uppercase letter represents a bigger duration period. So M is for month and m is for minutes. Similarly, D represents day of year; d represents day of month.
You can also format date and time objects by calling the format method in date or time objects and passing it a DateTimeFormatter instance.
If you access Java’s source code, you’ll notice that the format and parse methods in date and time classes simply call the format and parse methods on a DateTimeFormatter instance.
To parse a date or time object, you can use either the static parse method in date/time objects or the instance parse method in the DateTimeFormatter class. Behind the scenes, the parse method in date/time objects simply calls the parse method in DateTimeFormatter. Table 4.6 lists the available parse methods.
The parse methods are defined as static methods in the classes LocalDate, LocalTime, and LocalDateTime. The class DateTimeFormatter defines the parse method as an instance method.
When calling parse on LocalDate, LocalTime, or LocalDateTime instances, you might not specify a formatter. In this case DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.ISO_LOCAL_TIME, and DateTimeFormatter.ISO_LOCAL_DATE_TIME are used to parse text, respectively.
Let’s work with the method parse of LocalDate, LocalTime, or LocalDateTime to parse a string value using a DateTimeFormatter, producing a date or time object:
DateTimeFormatter d1 = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse("2057-01-29", d1 );
The following line throws a DateTimeParseException because this mechanism works only if all components are present. For example, the pattern yyyy-MM-dd with “2057-01-29” works fine. The component order doesn’t matter; hence, using dd-yyyy-MM to parse “29-2057-01” works too and yields January 29, 2057 as well:
DateTimeFormatter d1 = DateTimeFormatter.ofPattern("yyyy"); LocalDate date = LocalDate.parse("2057", d1);
Similarly, you can call the parse method to create instances of LocalTime and LocalDateTime.
3.145.101.81