Working with calendar data

Một phần của tài liệu Manning OCA java SE 8 programmer i certification guide (Trang 309 - 328)

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 DateTime- Formatter 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).

NOTE 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.

Table 4.1 Method prefixes, types, and their uses in the Date and Time API in Java 8

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.

[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.Period

279 Working with calendar data

4.6.1 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.

CREATING LOCALDATE

The LocalDate constructor is marked private, so you must use one of the factory meth- ods to instantiate it. The static method of() accepts year, month, and day of month:

LocalDate date1 = LocalDate.of(2015, 12, 27);

LocalDate date2 = LocalDate.of(2015, Month.DECEMBER, 27);

NOTE In the new Date and Time API, introduced with Java 8, January is rep- resented 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");

EXAM TIP If you pass invalid values to parse() or of(), you’ll get Date- TimeParseException. 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.

QUERYING LOCALDATE

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());

Accept month as int value

Accept month as enum constant

280 CHAPTER 4 Selected classes from the Java API and arrays

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:

LocalDate shreyaBday = LocalDate.parse("2002-08-30");

LocalDate paulBday = LocalDate.parse("2002-07-29");

System.out.println(shreyaBday.isAfter(paulBday));

System.out.println(shreyaBday.isBefore(paulBday));

System.out.println(shreyaBday.isBefore(shreyaBday));

MANIPULATING LOCALDATE

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 meth- ods 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

EXAM TIP 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));

Outputs true Outputs false

281 Working with calendar data

Here’s the output of the preceding code:

2016-03-01 2016-03-29 2016-04-18 2017-02-28

EXAM TIP 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

CONVERTINGTOANOTHERTYPE

The LocalDate class defines methods to convert it to LocalDateTime and long (repre- senting the epoch date).

The LocalDate class defines overloaded atTime() instance methods. These meth- ods 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

EXAM TIP If you pass any invalid hours, minutes, or seconds value to the method atTime, it will throw a DateTimeException at runtime.

282 CHAPTER 4 Selected classes from the Java API and arrays

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

NOTE In standard date and time, the epoch date refers to January 1, 1970, 00:00:00 GMT.

4.6.2 LocalTime

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 nanosec- onds as method arguments or methods that return this value. Like LocalDate, Local- Time is also immutable and hence safe to be used in a multithreaded environment.

CREATING LOCALTIME

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:

LocalTime timeHrsMin = LocalTime.of(12, 12);

LocalTime timeHrsMinSec = LocalTime.of(0, 12, 6);

LocalTime timeHrsMinSecNano = LocalTime.of(14, 7, 10, 998654578);

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 timeHrsMin = LocalTime.of(120, 12);

LocalTime timeHrsMin2 = LocalTime.of(9986545781, 12);

EXAM TIP 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.

Hours and

minutes Hours, minutes, and seconds

Hours, minutes, seconds, and nanoseconds

Runtime exception

Compilation error

283 Working with calendar data

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");

EXAM TIP 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.

USING LOCALTIMECONSTANTS

You can use constants from the LocalTime class to work with predefined times:

■ LocalTime.MIN—Minimum supported time, that is, 00:00

■ LocalTime.MAX—Maximum supported time, that is, 23:59:59.999999999

■ LocalTime.MIDNIGHT—Time when the day starts, that is, 00:00

■ LocalTime.NOON—Noontime, that is, 12:00

Does that make you wonder whether the minimum and midnight times are equal? See for yourself; the following code outputs true:

System.out.println(LocalTime.MIN.equals(LocalTime.MIDNIGHT));

QUERYING LOCALTIME

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

Outputs true

284 CHAPTER 4 Selected classes from the Java API and arrays

EXAM TIP The correct method names for querying LocalTime are get- Hour(), getMinute(), getSecond(), and getNano(). Watch out for exam ques- tions 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:

LocalTime shreyaFinishTime = LocalTime.parse("17:09:04");

LocalTime paulFinishTime = LocalTime.parse("17:09:12");

if(shreyaFinishTime.isBefore(paulFinishTime)) System.out.println("Shreya wins");

else System.out.println("Paul wins");

MANIPULATING LOCALTIME

You can use the instance methods minusHours(), minusMinutes(), minusSeconds(), and minusNanos() to create and return a copy of LocalTime instances with the speci- fied 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

EXAM TIP 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");

Outputs Shreya wins

285 Working with calendar data

The output of the preceding code looks like this:

Try harder

EXAM TIP 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 fol- lowing 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

COMBININGWITHANOTHERTYPE

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

EXAM TIP The class LocalTime defines the method atDate(), which can be passed a LocalDate instance to create a LocalDateTime instance.

4.6.3 LocalDateTime

If you want to store both date and time (without the time zone), use the class Local- DateTime. It stores a value like 2050-06-18T14:20:30:908765 (year-month-dayThours :minutes:seconds:nanoseconds).

NOTE 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

286 CHAPTER 4 Selected classes from the Java API and arrays

LocalTime classes. So instead of discussing individual methods of this class, here’s an example that covers the important methods of this class:

LocalDateTime prizeCeremony = LocalDateTime.parse("2050-06-05T14:00:00");

LocalDateTime dateTimeNow = LocalDateTime.now();

if (prizeCeremony.getMonthValue() == 6) System.out.println("Can't invite president");

else

System.out.println("President invited");

LocalDateTime chiefGuestDeparture =

LocalDateTime.parse("2050-06-05T14:30:00");

if (prizeCeremony.plusHours(2).isAfter(chiefGuestDeparture))

System.out.println("Chief Guest will leave before ceremony completes");

LocalDateTime eventMgrArrival = LocalDateTime.of(2050, 6, 5, 14, 30, 0);

if (eventMgrArrival.isAfter(prizeCeremony.minusHours(3)))

System.out.println("Manager is supposed to arrive 3 hrs earlier");

In the next section, you’ll discover how you can perform calculations with date and time using the Period class.

4.6.4 Period

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.

NOTE 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.

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:

Period period1 = Period.of(1, 2, 7);

Period period2 = Period.ofYears(2);

Parse String to LocalDateTime

Get current date and time Retrieve month as integer value

Check whether a LocalDateTime instance is before another LocalDateTime instance Instantiate LocalDateTime

using separate int values

1 year, 2 months, and 7 days

2 years

287 Working with calendar data

Period period3 = Period.ofMonths(5);

Period period4 = Period.ofWeeks(10);

Period period5 = Period.ofDays(15);

EXAM TIP A period of 35 days is not stored as 1 month and 5 days. Its individ- ual 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 pre- ceding methods. Here’s a quick example:

Period period6 = Period.ofDays(-15);

EXAM TIP 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 pre- cede 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):

Period p5Yrs1 = Period.parse("P5y");

Period p5Yrs2 = Period.parse("p5y");

Period p5Yrs3 = Period.parse("P5Y");

Period p5Yrs4 = Period.parse("+P5Y");

Period p5Yrs5 = Period.parse("P+5Y");

Period p5Yrs6 = Period.parse("-P-5Y");

System.out.println(p5Yrs1 + ":" + p5Yrs2);

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");

5 months 10 weeks 15 days

Period of -15 days

Period of 5 years

Outputs P5Y:P5Y

288 CHAPTER 4 Selected classes from the Java API and arrays

When passed to System.out.println(), the variables in the preceding code will result in the following output:

P5Y1M2D P9M P60D P-35D

EXAM TIP 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:

LocalDate carnivalStart = LocalDate.of(2050, 12, 31);

LocalDate carnivalEnd = LocalDate.of(2051, 1, 2);

Period periodBetween = Period.between(carnivalStart, carnivalEnd);

System.out.println(periodBetween);

EXAM TIP 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.

MANIPULATING LOCALDATEAND LOCALDATETIMEUSING PERIOD

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

Outputs P2D

Một phần của tài liệu Manning OCA java SE 8 programmer i certification guide (Trang 309 - 328)

Tải bản đầy đủ (PDF)

(706 trang)