Numbers and Dates - Java 8 Recipes, 2th Edition (2014)

Java 8 Recipes, 2th Edition (2014)

CHAPTER 4. Numbers and Dates

Numbers play a significant role in many applications. As such, it is helpful to know how to use them correctly within the context of the work that you are trying to perform. This chapter helps you understand how to perform some of the most basic operations with numbers, and it also provides insight on performing advanced tasks such as working with currency.

Dates are also important as they can be used for many purposes within an application. In Java 8, the new Date-Time package called java.time was introduced. The Date-Time API uses the calendar defined in ISO-8601 as the default. Therefore, the calendar is based on the Gregorian calendar system, and in this chapter, you will learn how to work with date, time, and time zone data. The Date-Time API adheres to several design principles, in that it’s clear, fluent, immutable, and extensible. The API uses a clear language that is concise and very well defined. It is also very fluent, so code dealing with date-time data is easy to read and understand. Most of the classes within the Date-Time API are immutable, so in order to alter a date-time object you must create a modified copy of the original. As such, many of the methods in the date-time classes are named accordingly, such as of() and with(), so that you know you are creating a copy rather than altering the original. Lastly, the new Date-Time API can be extended in many cases, allowing it to be useful in many contexts.

The Date-Time API is made up of a rich set of classes, providing solutions that were very difficult to achieve in previous APIs. Even though there are many different classes, most of them contain a similar set of methods, so the same principles can be utilized throughout all of the date and time units. Table 4-1 lists the common set of methods that you will find in most of the date-time classes.

Table 4-1. Date-Time API’s Common Methods

Method

Description

at

Combines one object with another.

format

Applies the specified format to a temporal object, producing a string.

from

Converts input parameters to an instance of the target class.

get

Returns a part of the state of the target object.

is

Queries the target object.

minus

Returns a modified copy of the target object with the specified amount of time subtracted.

of

Creates an instance, using specified input parameters for validation.

parse

Parses an input string to produce an instance of the target class.

plus

Returns a modified copy of the target object with the specified amount of time added.

to

Converts an object to a different type.

with

Returns a modified copy of the target object with the specified element changed (equivalent to a setter).

As mentioned previously, the Date-Time API is fluent; therefore, each of its classes is located in a clearly marked package. Table 4-2 lists the packages that make up the Date-Time API, along with brief descriptions of the classes that can be found in each.

Table 4-2. Date-Time API Packages

Package

Description

java.time

The core classes of the API. These classes are used for working with date-time data based on the ISO-8601 standard. These classes are immutable and thread-safe.

java.time.chrono

The API for using calendar systems other than ISO-8601.

java.time.format

Classes for formatting date-time data.

java.time.temporal

Extended API that allows interpolations between date-time classes.

java.time.zone

Classes supporting time zone data.

This chapter presents a brief overview of some commonly used date-time features. If you will be performing significant work with dates and times, you should read the Date-Time API documentation that is available online.

4-1. Rounding Float and Double Values to Integers

Problem

You need to be able to round floating-point numbers or doubles in your application to Integer values.

Solution

Use one of the java.lang.Math round() methods to round the number into the format you require. The Math class has two methods that can be used for rounding floating-point numbers or Double values. The following code demonstrates how to use each of these methods:

public static int roundFloatToInt(float myFloat){
return Math.round(myFloat);
}

public static long roundDoubleToLong(double myDouble){
return Math.round(myDouble);
}

The first method, roundFloatToInt(), accepts a floating-point number and uses the java.lang.Math class to round that number to an Integer. The second method, roundDoubleToLong(), accepts a Double value and uses the java.lang.Math class to round thatDouble to a Long.

How It Works

The java.lang.Math class contains plenty of helper methods to make our lives easier when working with numbers. The round() methods are no exception as they can be used to easily round floating-point or double values. One version of the java.lang.Math round() methodaccepts a float as an argument. It will round the float to the closest int value, with ties rounding up. If the argument is NaN, then a zero will be returned. When arguments that are positive or negative infinity are passed into round(), a result equal to the value of Integer.MAX_VALUE orInteger.MIN_VALUE, respectively, will be returned. The second version of the java.lang.Math round() method accepts a double value. The double value is rounded to the closest long value, with ties rounding up. Just like the other round(), if the argument is Not a Number (NaN), a zero will be returned. Similarly, when arguments that are positive or negative infinity are passed into round(), a result equal to the value of Long.MAX_VALUE or Long.MIN_VALUE, respectively, will be returned.

Image Note NaN, POSITIVE_INFINITY, and NEGATIVE_INFINITY are constant values defined within the Float and Double classes. NaN (Not a Number) is an undefined or unrepresentable value. For example, a NaN value can be produced by dividing 0.0f by 0.0f. The values represented by POSITIVE_INFINITY and NEGATIVE_INFINITY refer to values that are produced by operations that generate such extremely large or negative values of a particular type (floating-point or double) that they cannot be represented normally. For instance, 1.0/0.0 or -1.0/0.0 would produce such values.

4-2. Formatting Double and Long Decimal Values

Problem

You need to be able to format double and long numbers in your application.

Solution

Use the DecimalFormat class to format and round the value to the precision your application requires. In the following method, a double value is accepted and a formatted string value is printed:

public static void formatDouble(double myDouble){
NumberFormat numberFormatter = new DecimalFormat("##.000");
String result = numberFormatter.format(myDouble);
System.out.println(result);
}

For instance, if the double value passed into the formatDouble() method is 345.9372, the following will be the result:

345.937

Similarly, if the value .7697 is passed to the method, the following will be the result:

.770

Each of the results is formatted using the specified pattern and then rounded accordingly.

How It Works

The DecimalFormat class can be used along with the NumberFormat class to round and/or format double or long values. NumberFormat is an abstract class that provides the interface for formatting and parsing numbers. This class provides the ability to format and parse numbers for each locale, and obtain formats for currency, percentage, integers, and numbers. By itself, the NumberFormat class can be very useful as it contains factory methods that can be used to obtain formatted numbers. In fact, little work needs to be done in order to obtain a formatted string. For example, the following code demonstrates calling some factory methods on the NumberFormat class:

// Obtains an instance of NumberFormat class
NumberFormat format = NumberFormat.getInstance();

// Format a double value for the current locale
String result = format.format(83.404);
System.out.println(result);

// Format a double value for an Italian locale
result = format.getInstance(Locale.ITALIAN).format(83.404);
System.out.println(result);

// Parse a String into a Number
try {
Number num = format.parse("75.736");
System.out.println(num);
} catch (java.text.ParseException ex){
System.out.println(ex);
}

To format using a pattern, the DecimalFormat class can be used along with NumberFormat. In the solution to this recipe, you saw that creating a new DecimalFormat instance by passing a pattern to its constructor would return a NumberFormat type. This is becauseDecimalFormat extends the NumberFormat class. Because the NumberFormat class is abstract, DecimalFormat contains all the functionality that NumberFormat contains, plus added functionality for working with patterns. Therefore, it can be used to work with different formats from the locales just as you have seen in the previous demonstration. This provides the ultimate flexibility when working with double or long formatting.

As mentioned previously, the DecimalFormat class can take a string-based pattern in its constructor. You can also use the applyPattern() method to apply a pattern after the fact. Each pattern contains a prefix, numeric part, and suffix, which allow you to format a particular decimal value to the required precision and include leading digits and commas as needed. The symbols used to build patterns are displayed in Table 4-3. Each of the patterns also contains a positive and negative subpattern. These two subpatterns are separated by a semicolon (;) and the negative subpattern is optional. If there is no negative subpattern present, the localized minus sign is used. For instance, a complete pattern example would be ###,##0.00;(###,##0.00).

Table 4-3. DecimalFormat Pattern Characters

Character

Description

#

Digit; blank if no digit is present

0

Digit; zero if no digit is present

.

Decimal

-

Minus or negative sign

,

Comma or grouping separator

E

Scientific notation separator

;

Positive and negative subpattern separator

The DecimalFormat class provides enough flexibility to format double and long values for just about every situation.

4-3. Comparing int Values

Problem

You need to compare two or more int values.

Solution #1

Use the comparison operators to compare integer values against one another. In the following example, three int values are compared against each other, demonstrating various comparison operators:

int int1 = 1;
int int2 = 10;
int int3 = -5;

System.out.println(int1 == int2); // Result: false
System.out.println(int3 == int1); // Result: false
System.out.println(int1 == int1); // Result: true
System.out.println(int1 > int3); // Result: true
System.out.println(int2 < int3); // Result: false

As you can see, comparison operators will generate a Boolean result.

Solution #2

Use the Integer.compare(int,int) method to compare two int values numerically. The following lines could compare the same int values that were declared in the first solution:

System.out.println("Compare method -> int3 and int1: " + Integer.compare(int3, int1));
// Result -1
System.out.println("Compare method -> int2 and int1: " + Integer.compare(int2, int1));
// Result 1

How It Works

Perhaps the most commonly used numeric comparisons are against two or more int values. The Java language makes it very easy to compare an int using the comparison operators (see Table 4-4).

Table 4-4. Comparison Operators

Operator

Function

==

Equal to

!=

Not equal to

>

Greater than

<

Less than

>=

Greater than or equal to

<=

Less than or equal to

The second solution to this recipe demonstrates the integer compare() method that was added to the language in Java 7. This static method accepts two int values and compares them, returning a 1 if the first int is greater than the second, a 0 if the two int values are equal, and a -1if the first int value is less than the second. To use the Integer.compare() method, pass two int values as demonstrated in the following code:

Integer.compare(int3, int1));
Integer.compare(int2, int1));

Just like in your math lessons at school, these comparison operators will determine whether the first integer is equal to, greater than, or less than the second integer. Straightforward and easy to use, these comparison operators are most often seen within the context of an if statement.

4-4. Comparing Floating-Point Numbers

Problem

You need to compare two or more floating-point values in an application.

Solution #1

Use the Float object’s compareTo() method to perform a comparison of one float against another. The following example shows the compareTo() method in action:

Float float1 = new Float("9.675");
Float float2 = new Float("7.3826");
Float float3 = new Float("23467.373");

System.out.println(float1.compareTo(float3)); // Result: -1
System.out.println(float2.compareTo(float3)); // Result: -1
System.out.println(float1.compareTo(float1)); // Result: 0
System.out.println(float3.compareTo(float2)); // Result: 1

The result of calling the compareTo() method is an integer value. A negative result indicates that the first float is less than the float that it is being compared against. A zero indicates that the two float values are equal. Lastly, a positive result indicates that the first float is greater than the float that it is being compared against.

Solution #2

Use the Float class compare() method to perform the comparison. The following example demonstrates the use of the Float.compare(float, float) method.

System.out.println(Float.compare(float1, float3)); // Result: -1
System.out.println(Float.compare(float2, float3)); // Result: -1
System.out.println(Float.compare(float1, float1)); // Result: 0
System.out.println(Float.compare(float3, float2)); // Result: 1

How It Works

The most useful way to compare two float objects is to use the compareTo() method. This method will perform a numeric comparison against the given float objects. The result will be an integer value indicating whether the first float is numerically greater than, equal to, or less than the float that it is compared against. If a float value is NaN, it is considered to be equal to other NaN values or greater than all other float values. Also, a float value of 0.0f is greater than a float value of -0.0f.

An alternative to using compareTo() is the compare() method, which is also native to the Float class. The compare() method was introduced in Java 1.4, and it is a static method that compares two float values in the same manner as compareTo(). It only makes the code read a bit differently. The format for the compare() method is as follows:

Float.compare(primitiveFloat1, primitiveFloat2)

The compare() method shown will actually make the following call using compareTo():

new Float(float1).compareTo(new Float(float2)

In the end, the same results will be returned using either compareTo() or compare().

4-5. Calculating Monetary Values

Problem

You are developing an application that requires the use of monetary values and you are not sure which data type to use for storing and calculating currency values.

Solution

Use the BigDecimal data type to perform calculation on all monetary values. Format the resulting calculations using the NumberFormat.getCurrencyInstance() helper method. In the following code, three monetary values are calculated using a handful of the methods that are part of the BigDecimal class. The resulting calculations are then converted into double values and formatted using the NumberFormat class. First, take a look at how these values are calculated:

BigDecimal currencyOne = new BigDecimal("25.65");
BigDecimal currencyTwo = new BigDecimal("187.32");
BigDecimal currencyThree = new BigDecimal("4.86");
BigDecimal result = null;
String printFormat = null;

// Add all three values
result = currencyOne.add(currencyTwo).add(currencyThree);
// Convert to double and send to formatDollars(), returning a String
printFormat = formatDollars(result.doubleValue());
System.out.println(printFormat);

// Subtract the first currency value from the second
result = currencyTwo.subtract(currencyOne);
printFormat = formatDollars(result.doubleValue());
System.out.println(printFormat);

Next, let’s take a look at the formatDollars() method that is used in the code. This method accepts a double value and performs formatting on it using the NumberFormat class based on the U.S. locale. It then returns a string value representing currency:

public static String formatDollars(double value){
NumberFormat dollarFormat = NumberFormat.getCurrencyInstance(Locale.US);
return dollarFormat.format(value);
}

As you can see, the NumberFormat class allows for currency to be formatted per the specified locale. This can be very handy if you are working with an application that deals with currency and has an international scope.

$217.83
$161.67

Image Note JSR 354, the Money and Currency API, was under development at the time of this writing, and it is due to become part of Java 9. See the JSR for more information at https://jcp.org/en/jsr/detail?id=354.

How It Works

Many people attempt to use different number formats when working with currency. While it might be possible to use any type of numeric object to work with currency, the BigDecimal class was added to the language to help satisfy the requirements of working with currency values, among other things. Perhaps the most useful feature of the BigDecimal class is that it provides control over rounding. This is essentially why such a class is so useful for working with currency values. The BigDecimal class provides an easy API for rounding values, and also makes it easy to convert to double values, as the solution to this recipe demonstrates.

Image Note The use of BigDecimal for working with monetary values is a good practice. However, it can come at some performance expense. Depending on the application and performance requirements, it might be worth using Math.round() to achieve basic rounding if performance becomes an issue.

To provide specific rounding with the BigDecimal class, you should use a MathContext object or the RoundingMode enumeration values. In either case, such precision can be omitted by using a currency-formatting solution such as the one demonstrated in the solution example.BigDecimal objects have mathematical implementations built into them, so performing such operations is an easy task. The arithmetic operations that you can use are described in Table 4-5.

Table 4-5. BigDecimal Arithmetic Methods

Method

Description

add()

Adds one BigDecimal object value to another.

subtract()

Subtracts one BigDecimal object value from another.

multiply()

Multiplies the value of one BigDecimal object by another.

abs()

Returns the absolute value of the given BigDecimal object value.

pow(n)

Returns the BigDecimal to the power of n; the power is computed to unlimited precision.

After performing the calculations you require, call the doubleValue() method on the BigInteger object to convert and obtain a double. You can then format the double using the NumberFormat class for currency results.

4-6. Randomly Generating Values

Problem

An application that you are developing requires the use of randomly generated numbers.

Solution #1

Use the java.util.Random class to help generate the random numbers. The Random class was developed for the purpose of generating random numbers for a handful of the Java numeric data types. This code demonstrates the use of Random to generate such numbers:

// Create a new instance of the Random class
Random random = new Random();

// Generates a random Integer
int myInt = random.nextInt();

// Generates a random Double value
double myDouble = random.nextDouble();

// Generates a random float
float myFloat = random.nextFloat();

// Generates a random Gaussian double
// mean 0.0 and standard deviation 1.0
// from this random number generator's sequence.
double gausDouble = random.nextGaussian();

// Generates a random Long
long myLong = random.nextLong();

// Generates a random boolean
boolean myBoolean = random.nextBoolean();

Solution #2

Make use of the Math.random() method. This will produce a double value that is greater than 0.0, but less than 1.0. The following code demonstrates the use of this method:

double rand = Math.random();

How It Works

The java.util.Random class uses a 48-bit seed to generate a series of pseudo-random values. As you can see from the example in the solution to this recipe, the Random class can generate many different types of random number values based on the given seed. By default, the seed is generated based on a calculation derived from the number of milliseconds that the machine has been active. However, the seed can be set manually using the Random setSeed() method. If two Random objects have the same seed, they will produce the same results.

It should be noted that there are cases in which the Random class might not be the best choice for generating random values. For instance, if you are attempting to use a thread-safe instance of java.util.Random, you might run into performance issues if you’re working with many threads. In such a case, you might consider using the ThreadLocalRandom class instead. To see more information regarding ThreadLocalRandom, see the documentation athttp://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadLocalRandom.html.

Similarly, if you require the use of a cryptographically secure Random object, consider the use of SecureRandom. Documentation regarding this class can be found at http://docs.oracle.com/javase/8/docs/api/java/security/SecureRandom.html.

The java.util.Random class comes in very handy when you need to generate a type-specified random value. Not only is it easy to use but it also provides a wide range of options for return type. Another easy technique is to use the Math.random() method, which produces adouble value that is within the range of 0.0 to 1.0, as demonstrated in solution #2. Both techniques provide a good means of generating random values. However, if you need to generate random numbers of a specific type, java.util.Random is the best choice.

4-7. Obtaining the Current Date Without Time

Problem

You are developing an application for which you would like to obtain the current date, not including the time, to display on a form.

Solution

Make use of the Date-Time API to obtain the current date. The LocalDate class represents an ISO calendar in the year-month-day format. The following lines of code capture the current date and display it:

LocalDate date = LocalDate.now();
System.out.println("Current Date:" + date);

How It Works

The Date-Time API makes it easy to obtain the current date, without including other information such as time. To do so, import the java.time.LocalTime class and call on its now() method. The LocalTime class cannot be instantiated, as it is immutable and thread-safe. A call to thenow() method returns another LocalDate object, containing the current date in the year-month-day format.

Another version of the now() method accepts a java.time.Clock object as a parameter and returns the date based on that clock. For instance, the following lines of code demonstrate how to obtain a Clock that represents the system time:

Clock clock = Clock.systemUTC();
LocalDate date = LocalDate.now(clock);

In previous releases, there were other ways to obtain the current date, but usually the time came with the date and then formatting had to be done to remove the unneeded time digits. The new java.time.LocalDate class makes it possible to work with dates separate from times.

4-8. Obtaining a Date Object Given Date Criteria

Problem

You want to obtain a date object, given a year-month-day specification.

Solution

Invoke the LocalDate.of() method for the year, month, and day for which you want to obtain the object. For example, suppose that you want to obtain a date object for a specified date in November of 2000. You could pass that date criteria to the LocalDate.of() method, as demonstrated in the following lines of code:

LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 11);
System.out.println("Date from specified date: " + date);

Here’s the result:

Date from specified date: 2000-11-11

How It Works

The LocalDate.of() method accepts three values as parameters. Those parameters represent the year, month, and day. The year parameter is always treated as an int value. The month parameter can be presented as an int value, which uses an enum that represents the month. TheMonth enum will return an int value for each month, with JANUARY returning a 1 and DECEMBER returning a 12. Therefore, Month.NOVEMBER returns an 11. A Month object could also be passed as the second parameter instead of as an int value. Lastly, the day of the month is specified by passing an int value as the third parameter to the of() method.

Image Note For more information regarding the Month enum, see the online documentation at http://docs.oracle.com/javase/8/docs/api/java/time/Month.html.

4-9. Obtaining a Year-Month-Day Date Combination

Problem

You would like to obtain the year, year-month, or month of a specified date.

Solution #1

To obtain the year-month of a specified date, use the java.time.YearMonth class. This class is used to represent the month of a specific year. In the following lines of code, the YearMonth object is used to obtain the year and month of the current date and another specified date.

YearMonth yearMo = YearMonth.now();
System.out.println("Current Year and month:" + yearMo);
YearMonth specifiedDate = YearMonth.of(2000, Month.NOVEMBER);
System.out.println("Specified Year-Month: " + specifiedDate);

Here’s the result:

Current Year and month: 2014-12
Specified Year-Month: 2000-11

Solution #2

To obtain the month-day for the current date or a specified date, simply make use of the java.time.MonthDay class. The following lines of code demonstrate how to obtain a month-day combination.

MonthDay monthDay = MonthDay.now();
System.out.println("Current month and day: " + monthDay);
MonthDay specifiedDate = MonthDay.of(Month.NOVEMBER, 11);
System.out.println("Specified Month-Day: " + specifiedDate);

Here’s the result:

Current month and day: --12-14
Specified Month-Day: --11-11

Note that by default, MonthDay does not return a very useful format. For more help with formatting, see Recipe 4-17.

How It Works

The Date-Time API includes classes that make it easy to obtain the information that your application requires for a date. Two of those are the YearMonth and MonthDay classes. The YearMonth class is used to obtain the date in year-month format. It contains a few methods that can be used to obtain the year-month combination. As demonstrated in the solution, you can call the now() method to obtain the current year-month combination. Similar to the LocalDate class, YearMonth also contains an of() method that accepts a year in int format, and an number that represents the month of the year. In the solution, the Month enum is used to obtain the month value.

Similar to the YearMonth class, MonthDay obtains the date in a month-day format. It also contains a few different methods for obtaining the month-day combination. Solution #2 demonstrates two such techniques. Obtaining the current month-day combination by calling the now()method and using the of() method to obtain a month-day combination for a specified date. The of() method accepts an int value for the month of the year as its first parameter, and for the second parameter it accepts an int value indicating the day of the month.

4-10. Obtaining and Calculating Based on the Current Time

Problem

You would like to obtain the current time so that it can be used to stamp a given record. You would also like to perform calculations on that time.

Solution

Use the LocalTime class, which is part of the new Date-Time API, to obtain and display the current time. In the following lines of code, the LocalTime class is demonstrated.

LocalTime time = LocalTime.now();
System.out.println("Current Time: " + time);

Once the time has been obtained, methods can be called against the LocalTime instance to achieve the desired result. In the following lines of code, there are some examples of using the LocalTime methods:

// atDate(LocalDate): obtain the local date and time
LocalDateTime ldt = time.atDate(LocalDate.of(2011,Month.NOVEMBER,11));
System.out.println("Local Date Time object: " + ldt);

// of(int hours, int min): obtain a specific time
LocalTime pastTime = LocalTime.of(1, 10);

// compareTo(LocalTime): compare two times. Positive
// return value returned if greater
System.out.println("Comparing times: " + time.compareTo(pastTime));

// getHour(): return hour in int value (24-hour format)
int hour = time.getHour();
System.out.println("Hour: " + hour);

// isAfter(LocalTime): return Boolean comparison
System.out.println("Is local time after pastTime? " + time.isAfter(pastTime));

// minusHours(int): Subtract Hours from LocalTime
LocalTime minusHrs = time.minusHours(5);
System.out.println("Time minus 5 hours: " + minusHrs);

// plusMinutes(int): Add minutes to LocalTime
LocalTime plusMins = time.plusMinutes(30);
System.out.println("Time plus 30 mins: " + plusMins);

Here are the results:

Current Time: 22:21:08.419
Local Date Time object: 2011-11-11T22:21:08.419
Comparing times: 1
Hour: 22
Is local time after pastTime? true
Time minus 5 hours: 17:21:08.419
Time plus 30 mins: 22:51:08.419

How It Works

Sometimes it is necessary to obtain the current system time. The LocalTime class can be used to obtain the current time by calling its now() method. Similarly to the LocalDate class, the LocalTime.now() method can be called to return a LocalTime object that is equal to the current time. The LocalTime class also contains several methods that can be utilized to manipulate the time. The examples contained in the solution provide a brief overview of the available methods.

Let’s take a look at a handful of examples to provide some context for how the LocalTime methods are invoked. To obtain a LocalTime object set to a specific time, invoke the LocalTime.of(int, int) method, passing int parameters representing the hour and minute.

// of(int hours, int min): obtain a specific time
LocalTime pastTime = LocalTime.of(1, 10);

The atDate(LocalDate) instance method is used to apply a LocalDate object to a LocalTime instance, returning a LocalDateTime object (for more information, see Recipe 4-11).

LocalDateTime ldt = time.atDate(LocalDate.of(2011,Month.NOVEMBER,11));

There are several methods that can be used for obtaining portions of the time. For instance, the getHour(), getMinute(), getNano(), and getSecond() methods can be used to return those specified portions of the LocalTime object.

int hour = time.getHour();
int min = time.getMinute();
int nano = time.getNano();
int sec = time.getSecond();

Several comparison methods are also available for use. For example, the compareTo(LocalTime) method can be used to compare one LocalTime object to another. isAfter(LocalTime) can be used to determine if the time is after another, and isBefore(LocalTime) is used to specify the opposite. If calculations are needed, several methods are available, including:

· minus(long amountToSubtract, TemporalUnit unit)

· minus(TemporalAmount amount)

· minusHours(long)

· minusMinutes(long)

· minusNanos(long)

· minusSeconds(long)

· plus(long amountToAdd, TemporalUnit unit)

· plus(TemporalAmount amount)

· plusHours(long)

· plusMinutes(long)

· plusNanos(long)

· plusSeconds(long)

To see all of the methods contained in the LocalTime class, see the online documentation at http://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html.

4-11. Obtaining and Using the Date and Time Together

Problem

In your application, you want to display not only the current date, but also the current time.

Solution #1

Make use of the LocalDateTime class, which is part of the new Date-Time API, to capture and display the current date and time. The LocalDateTime class contains a method named now(), which can be used to obtain the current date and time together. The following lines of code demonstrate how to do so:

LocalDateTime ldt = LocalDateTime.now();
System.out.println("Local Date and Time: " + ldt);

The resulting LocalDateTime object contains both the date and time, but no time zone information. The LocalDateTime class also contains additional methods that provide options for working with date-time data. For instance, to return a LocalDateTime object with a specified date and time, pass parameters of int type to the LocalDateTime.of() method, as follows:

// Obtain the LocalDateTime object of the date 11/11/2000 at 12:00
LocalDateTime ldt2 = LocalDateTime.of(2000, Month.NOVEMBER, 11, 12, 00);

The following examples demonstrate a handful of the methods that are available in a LocalDateTime object:

// Obtain the month from LocalDateTime object
Month month = ldt.getMonth();
int monthValue = ldt.getMonthValue();
System.out.println("Month: " + month);
System.out.println("Month Value: " + monthValue);

// Obtain day of Month, Week, and Year
int day = ldt.getDayOfMonth();
DayOfWeek dayWeek = ldt.getDayOfWeek();
int dayOfYr = ldt.getDayOfYear();
System.out.println("Day: " + day);
System.out.println("Day Of Week: " + dayWeek);
System.out.println("Day of Year: " + dayOfYr);

// Obtain year
int year = ldt.getYear();
System.out.println("Date: " + monthValue + "/" + day + "/" + year);

int hour = ldt.getHour();
int minute = ldt.getMinute();
int second = ldt.getSecond();
System.out.println("Current Time: " + hour + ":" + minute + ":" + second);

// Calculation of Months, etc.
LocalDateTime currMinusMonths = ldt.minusMonths(12);
LocalDateTime currMinusHours = ldt.minusHours(10);
LocalDateTime currPlusDays = ldt.plusDays(30);
System.out.println("Current Date and Time Minus 12 Months: " + currMinusMonths);
System.out.println("Current Date and Time MInus 10 Hours: " + currMinusHours);
System.out.println("Current Date and Time Plus 30 Days:" + currPlusDays);

Here’s the result:

Day: 18
Day Of Week: WEDNESDAY
Day of Year: 352
Date: 12/18/2013
Current Time: 23:8:41
Current Date and Time Minus 12 Months: 2012-12-18T23:41:34.084
Current Date and Time MInus 10 Hours: 2014-12-18T13:41:34.084
Current Date and Time Plus 30 Days:2014-01-17T23:41:34.084

Solution #2

If you only need to obtain the current date without going into calendar details, use the java.util.Date class to generate a new Date object. Doing so will cause the new Date object to be equal to the current system date. In the following code, you can see how easy it is to create a new Date object and obtain the current date:

Date date = new Date();

System.out.println(date);
System.out.println(date.getTime());

The result will be a Date object that contains the current date and time taken from the system that the code is run on, including the time zone information, as shown following listing. The time is the number of milliseconds since January 1, 1970, 00:00:00 GMT.

Sat Sep 10 14:45:57 CDT 2011
1315683957625

Solution #3

If you need to be more precise regarding the calendar, use the java.util.Calendar class. Although working with the Calendar class will make your code longer, the results are much more precise. The following code demonstrates just a handful of the capabilities of using this class to obtain the current date:

Calendar gCal = Calendar.getInstance();

// Month is based upon a zero index, January is equal to 0,
// so we need to add one to the month for it to be in
// a standard format
int month = gCal.get(Calendar.MONTH) + 1;int day = gCal.get(Calendar.DATE);
int yr = gCal.get(Calendar.YEAR);

String dateStr = month + "/" + day + "/" + yr;
System.out.println(dateStr);

int dayOfWeek = gCal.get(Calendar.DAY_OF_WEEK);

// Print out the integer value for the day of the week
System.out.println(dayOfWeek);

int hour = gCal.get(Calendar.HOUR);
int min = gCal.get(Calendar.MINUTE);
int sec = gCal.get(Calendar.SECOND);

// Print out the time
System.out.println(hour + ":" + min + ":" + sec);

// Create new DateFormatSymbols instance to obtain the String
// value for dates
DateFormatSymbols symbols = new DateFormatSymbols();
String[] days = symbols.getWeekdays();
System.out.println(days[dayOfWeek]);

// Get crazy with the date!
int dayOfYear = gCal.get(Calendar.DAY_OF_YEAR);
System.out.println(dayOfYear);

// Print the number of days left in the year
System.out.println("Days left in " + yr + ": " + (365-dayOfYear));

int week = gCal.get(Calendar.WEEK_OF_YEAR);
// Print the week of the year
System.out.println(week);

As demonstrated by this code, it is possible to obtain more detailed information regarding the current date when using the Calendar class. The results of running the code will look like the following:

9/10/2011
7
2:45:57
Saturday
253
Days left in 2011: 112
37

How It Works

Many applications require the use of the current calendar date. It is often also necessary to obtain the current time. There are different ways to do that, and the solution to this recipe demonstrates three of them. The Date-Time API includes a LocalDateTime class that enables you to capture the current date and time by invoking its now() method. A specified date and time can be obtained by specifying the corresponding int and Month type parameters when calling LocalDateTime.of(). There are also a multitude of methods available for use via a LocalDateTimeinstance, such as getHours(), getMinutes(), getNanos() and getSeconds(), which allow for finer-grained control of the date and time. An instance of LocalDateTime also contains methods for performing calculations, conversions, comparisons, and more. For brevity, all of the methods are not listed here, but for more information, refer to the online documentation at http://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html. Solution #1 to this recipe demonstrates the use of the LocalDateTime, showcasing how to perform calculations and obtain portions of the date and time for further use.

By default, the java.util.Date class can be instantiated with no arguments to return the current date and time. The Date class can also be used to return the current time of day via the getTime() method. As mentioned in the solution, the getTime() method returns the number of milliseconds since January 1, 1970, 00:00:00 GMT, represented by the Date object that is in use. There are several other methods that can be called against a Date object with regard to breaking down the current date and time into more granular intervals. For instance, the Date class has the methods getHours(), getMinutes(), getSeconds(), getMonth(), getDay(), getTimezoneOffset(), and getYear(). However, it is not advisable to use any of these methods, with the exception of getTime(), because each has been deprecated by the use of the java.time.LocalDateTime and the java.util.Calendar get() method. When some method or class is deprecated, that means it should no longer be used because it might be removed in some future release of the Java language. However, a few of the methods contained within the Date class have not been tagged as deprecated, so the Date class will most likely be included in future releases of Java. The methods that were left intact include the comparison methods after(), before(), compareTo(), setTime(), and equals(). Solution #2 to this recipe demonstrates how to instantiate a Date object and print out the current date and time.

As mentioned previously, the Date class has many methods that have become deprecated and should no longer be used. In solution #3 of this recipe, the java.util.Calendar class is demonstrated as one successor for obtaining much of this information. The Calendar class was introduced in JDK 1.1, at which time many of the Date methods were deprecated. As you can see from solution #3, the Calendar class contains all the same functionality that is included in the Date class, except the Calendar class is much more flexible. The Calendar class is actually an abstract class that contains methods that are used for converting between a specific time and date, and manipulating the calendar in various ways. The Calendar, as demonstrated in solution #3, is one such class that extends the Calendar class and therefore provides this functionality. The Calendar class has gained a few new methods in Java 8. The new methods in java.util.Calendar are listed in Table 4-6.

Table 4-6. New Methods for java.util.Calendar in Java 8

Method Name

Description

getAvailableCalendarTypes()

Returns un-modifiable set containing all supported calendar types.

getCalendarType()

Returns the calendar type of this calendar.

toInstant()

Converts to an instant.

For some applications, the Date class will work fine. For instance, the Date class can be useful when working with timestamps. However, if the application requires detailed manipulation of dates and times then it is advisable to use a LocalDateTime or the Calendar class, which both include all the functionality of the Date class and more features as well. All solutions to this recipe are technically sound; choose the one that best suits the needs of your application.

4-12. Obtaining a Machine Timestamp

Problem

You need to obtain a machine-based timestamp from the system.

Solution

Utilize an Instant class, which represents the start of a nanosecond on the timeline based on machine time. In the following example, an Instant is used to obtain the system timestamp. The Instant is also utilized in other scenarios, such as when calculating different dates based on the Instant.

public static void instants(){
Instant timestamp = Instant.now();
System.out.println("The current timestamp: " + timestamp);

//Now minus three days
Instant minusThree = timestamp.minus(3, ChronoUnit.DAYS);
System.out.println("Now minus three days:" + minusThree);

ZonedDateTime atZone = timestamp.atZone(ZoneId.of("GMT"));
System.out.println(atZone);

Instant yesterday = Instant.now().minus(24, ChronoUnit.HOURS);
System.out.println("Yesterday: " + yesterday);
}

Here is the result:

The current timestamp: 2014-12-27T05:36:42.199Z
Now minus three days:2014-12-24T05:36:42.199Z
2014-12-27T05:36:42.199Z[GMT]
Yesterday: 2014-12-26T05:36:42.253Z

How It Works

The Date-Time API introduces a new class named Instant, which represents the start of a nanosecond on the timeline in machine-based time. Being based on machine time, the value for an Instant counts from the EPOCH (January 1, 1970 00:00:00Z). Any values prior to the EPOCH are negative, and after the EPOCH the values are positive. The Instant class is perfect for obtaining a machine timestamp, as it includes all pertinent date and time information to the nanosecond.

An Instant class is static and immutable, so to obtain the current timestamp, the now() method can be called. Doing so returns a copy of the current Instant. The Instant also includes conversion and calculation methods, each returning copies of the Instant or other types. In the solution, the now() method returns the current timestamp, and then a couple of examples follow, showing how to perform calculations and obtain information on the Instant.

The Instant is an important new feature in JDK 8, as it makes it easy to work with current time and date data. The other date and time classes, such as LocalDateTime, are useful as well. However, the Instant is the most accurate timestamp as it’s based on nanosecond accuracy.

4-13. Converting Dates and Times Based on the Time Zone

Problem

The application you are developing has the potential to be utilized throughout the world. In some areas of the application, static dates and times need to be displayed, rather than the system date and time. In such cases, those static dates and times need to be converted to suit the particular time zone in which the application user is currently residing.

Solution

The Date-Time API provides the proper utilities for working with time zone data via the Time Zone and Offset classes. In the following scenario, suppose that the application is working with reservations for rental vehicles. You could rent a vehicle in one time zone and return it in another. The following lines of code demonstrate how to print out an individual’s reservation in such a scenario. The following method, named scheduleReport, accepts LocalDateTime objects representing check-in and check-out date/time, along with ZoneIds for each. This method could be used by an airline to print time-zone information for a particular flight.

public static void scheduleReport(LocalDateTime checkOut, ZoneId checkOutZone,
LocalDateTime checkIn, ZoneId checkInZone){

ZonedDateTime beginTrip = ZonedDateTime.of(checkOut, checkOutZone);
System.out.println("Trip Begins: " + beginTrip);

// Get the rules of the check out time zone
ZoneRules checkOutZoneRules = checkOutZone.getRules();
System.out.println("Checkout Time Zone Rules: " + checkOutZoneRules);

//If the trip took 4 days
ZonedDateTime beginPlus = beginTrip.plusDays(4);
System.out.println("Four Days Later: " + beginPlus);

// End of trip in starting time zone
ZonedDateTime endTripOriginalZone = ZonedDateTime.of(checkIn, checkOutZone);
ZonedDateTime endTrip = ZonedDateTime.of(checkIn, checkInZone);
int diff = endTripOriginalZone.compareTo(endTrip);
String diffStr = (diff >=0) ? "NO":"YES";
System.out.println("End trip date/time in original zone: " + endTripOriginalZone);
System.out.println("End trip date/time in check-in zone: " + endTrip );
System.out.println("Original Zone Time is less than new zone time? " +
diffStr );
ZoneId checkOutZoneId = beginTrip.getZone();
ZoneOffset checkOutOffset = beginTrip.getOffset();
ZoneId checkInZoneId = endTrip.getZone();
ZoneOffset checkInOffset = endTrip.getOffset();

System.out.println("Check out zone and offset: " + checkOutZoneId + checkOutOffset);
System.out.println("Check in zone and offset: " + checkInZoneId + checkInOffset);

}

Here is the result:

Trip Begins: 2014-12-13T13:00-05:00[US/Eastern]
Four Days Later: 2014-12-17T13:00-05:00[US/Eastern]
End trip date/time in original zone: 2014-12-18T10:00-05:00[US/Eastern]
End trip date/time in check-in zone: 2014-12-18T10:00-07:00[US/Mountain]
Original Zone Time is less than new zone time? YES
Check out zone and offset: US/Eastern-05:00
Check in zone and offset: US/Mountain-07:00

How It Works

Time zones add yet another challenge for developers, and the Java Date-Time API provides an easy facet for working with them. The Date-Time API includes a java.time.zone package, which contains a number of classes that can assist in working with time zone data. These classes provide support for time zone rules, data, and resulting gaps and overlaps in the local timeline that are typically the result of daylight savings conversions. The classes that make up the zone package are outlined in Table 4-7.

Table 4-7. Time Zone Classes

Class Name

Description

ZoneId

Specifies zone identifier and is used for conversions.

ZoneOffset

Specifies a time zone offset from Greenwich/UTC time.

ZonedDateTime

A date-time object that also handles the time zone data with time zone offset from Greenwich/UTC time.

ZoneRules

Rules defining how a zone offset varies for a specified time zone.

ZoneRulesProvider

Provider of time zone rules to a particular system.

ZoneOffsetTransition

Transition between two offsets by a discontinuity in the local timeline.

ZoneOffsetTransitionRule

Rules expressing how to create a transition.

Starting with the most fundamental time zone class, ZoneId, each time zone contains a particular time zone identifier. This identifier can be useful for assigning a particular time zone to a date-time. In the solution, the ZoneId is used to calculate any differences between two time zones.ZoneId identifies the rules that should be used for converting, based on a particular offset, either fixed or geographical region-based. For more details on ZoneId, see the documentation at http://docs.oracle.com/javase/8/docs/api/java/time/ZoneId.html.

ZonedDateTime is an immutable class that is utilized for working with date-time and time zone data together. This class represents an object, much like LocalDateTime, that includes the ZoneId. It can be used to express all facets of a date, including year, month, day, hours, minutes, seconds, nanos, and time zone. The class contains a bevy of methods that are useful for performing calculations, conversions, and so on.. For brevity, the methods that are contained in ZonedDateTime are not listed here, but you can read about each of them in the documentation athttp://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html.

ZoneOffset specifies a time zone offset from Greenwich/UTC time. You can find the offset for a particular time zone by invoking the ZonedDateTime.getOffset() method. The ZoneOffset class includes methods that make it easy to break down an offset into different time units. For instance, the getTotalSeconds() method returns the total of hours, minutes, and seconds fields as a single offset that can be added to a time. Refer to the online documentation for more information athttp://docs.oracle.com/javase/8/docs/api/java/time/ZoneOffset.html.

There are many rules that can be defined for determining how zone offset varies for a single time zone. The ZoneRules class is used to define these rules for a zone. For instance, ZoneRules can be called on to specify or determine if daylight savings time is a factor. An Instant orLocalDateTime can also be passed to ZoneRules methods such as getOffset() and getTransition() to return ZoneOffset or ZoneOffsetTransition. For more information on ZoneRules, refer to the online documentation athttp://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html.

Another time zone class that is used often is ZoneOffsetTransition. This class models the transition between the spring and autumn offsets as a result of daylight savings time changes. It is used to determine if there is a gap between transitions, obtaining the duration of a transition, and so on. For more information on ZoneOffsetTransition, see the online documentation at http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneOffsetTransition.html.

ZoneRulesProvider, ZoneOffsetTransitionRule, and other classes are typically not utilized as often as others for working with dates and time zones. These classes are useful for managing configuration of time zone rules and transitions.

Image Note The classes within the java.time.zone package are significant, in that there is a multitude of methods that can be invoked on each class. This recipe provides a primer for getting started, with only the basics of time zone usage. For more detailed information, see the online documentation.

4-14. Comparing Two Dates

Problem

You want to determine if one date is greater than another.

Solution

Utilize one of the compareTo() methods that are part of the Date-Time API classes. In the following solution, two LocalDate objects are compared and an appropriate message is displayed.

public static void compareDates(LocalDate ldt1,
LocalDate ldt2) {
int comparison = ldt1.compareTo(ldt2);
if (comparison > 0) {
System.out.println(ldt1 + " is larger than " + ldt2);
} else if (comparison < 0) {
System.out.println(ldt1 + " is smaller than " + ldt2);
} else {
System.out.println(ldt1 + " is equal to " + ldt2);
}

}

How It Works

Many of the Date-Time API classes contain a method that is used to compare two different date-time objects. In the solution to this example, the LocalDate.compareTo() method is used to determine if one LocalDate object is greater than another. The compareTo() method returns a negative int value if the first LocalDate is greater than the second, a zero if they are equal, and a positive number if the second LocalDate is greater than the first.

Each of the date-time classes that contain a compareTo() has the same outcome. That is, an int value is returned indicating if the first object is greater than, less than, or equal to the second. Each of the classes that contains the compareTo() method is listed here:

· Duration

· LocalDate

· LocalDateTime

· LocalTime

· Instant

· MonthDay

· OffsetDateTime

· OffsetTime

· Year

· YearMonth

· ZoneOffset

4-15. Finding the Interval Between Dates and Times

Problem

You need to determine how many hours, days, weeks, months, or years have elapsed between two dates or times.

Solution #1

Utilize the Date-Time API to determine the difference between two dates. Specifically, make use of the Period class to determine the period of time, in days, between two dates. The following example demonstrates how to obtain the interval of days, months, and years between two dates.

Image Note This example shows the difference in days, months, and years, but not the cumulative days or months between two dates. To determine the total cumulative days, months, and years between two dates, read on for solutions #2 and #3.

LocalDate anniversary = LocalDate.of(2000, Month.NOVEMBER, 11);
LocalDate today = LocalDate.now();
Period period = Period.between(anniversary, today);
System.out.println("Number of Days Difference: " + period.getDays());
System.out.println("Number of Months Difference: " + period.getMonths());
System.out.println("Number of Years Difference: " + period.getYears());

Here is the result:

Number of Days Difference: 16
Number of Months Difference: 1
Number of Years Difference: 13

Solution #2

Use the java.util.concurrent.TimeUnit enum to perform calculations between given dates. Using this enum, you can obtain the integer values for days, hours, microseconds, milliseconds, minutes, nanoseconds, and seconds. Doing so will allow you to perform the necessary calculations.

// Obtain two instances of the Calendar class
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();

// Set the date to 01/01/2010:12:00
cal2.set(2010,0,1,12,0);
Date date1 = cal2.getTime();
System.out.println(date1);

long mill = Math.abs(cal1.getTimeInMillis() - date1.getTime());
// Convert to hours
long hours = TimeUnit.MILLISECONDS.toHours(mill);
// Convert to days
Long days = TimeUnit.HOURS.toDays(hours);
String diff = String.format("%d hour(s) %d min(s)", hours,
TimeUnit.MILLISECONDS.toMinutes(mill) - TimeUnit.HOURS.toMinutes(hours));
System.out.println(diff);

diff = String.format("%d days", days);
System.out.println(diff);

// Divide the number of days by seven for the weeks
int weeks = days.intValue()/7;
diff = String.format("%d weeks", weeks);
System.out.println(diff);

The output of this code will be formatted to display strings of text that indicate the differences between the current date and the Date object that is created.

Solution #3

To determine the total cumulative difference in days, months, years, or other time unit, use the ChronoUnit class. The following code demonstrates how to utilize the ChronoUnit class to determine the number of days and years between two dates.

LocalDate anniversary = LocalDate.of(2000, Month.NOVEMBER, 11);
LocalDate today = LocalDate.now();
long yearsBetween = ChronoUnit.YEARS.between(anniversary, today);
System.out.println("Years between dates: " + yearsBetween);

long daysBetween = ChronoUnit.DAYS.between(anniversary, today);
System.out.println("Days between dates:" + daysBetween);

Here are the results:

Years between dates: 13
Days between dates: 4794

How It Works

As with most programmatic techniques, there is more than one way to perform date calculations with Java. The Date-Time API includes a few new techniques for determining time intervals. The new Period class is used to determine the period of difference between two units for specified objects. To obtain a Period between two date-time objects, call the Period.between() method, passing the two date-time objects for which you’d like to obtain the Period. The Period has a number of methods that can be used to break down the intervals into different units. For instance, the number days in the period of the two date-time objects can be obtained using the getDays() method. Similarly, the getMonths() and getYears() methods can be called to return the number of months or years in the period.

The Date-Time API also includes a ChronoUnit Enum that can be used to work with calendar systems other than ISO, providing unit-based access to manipulate date and time. Each of the unit values within the Enum contains a number of methods for performing manipulations. One such method is between(), which returns a single unit of time only in the specified unit between the two given date-time objects. In the solution, it is used to return years and days using ChronoUnit.YEARS.between() and ChronoUnit.DAYS.between(), respectively.

One of the most useful techniques is to perform calculations based on the given date’s time in milliseconds. This provides the most accurate calculation because it works on the time at a very small interval: milliseconds. The current time in milliseconds can be obtained from a Calendarobject by calling the getTimeInMillis() method against it. Likewise, a Date object will return its value represented in milliseconds by calling the getTime() method. As you can see from the solution to this recipe, the first math that is performed is the difference between the given dates in milliseconds. Obtaining that value and then taking its absolute value will provide the base that is needed to perform the date calculations. In order to obtain the absolute value of a number, use the abs() method that is contained in the java.lang.Math class, shown in the following line of code:

long mill = Math.abs(cal1. getTimeInMillis() - date1.getTime());

The absolute value will be returned in long format. The TimeUnit enum can be used in order to obtain different conversions of the date. It contains a number of static enum constant values that represent different time intervals, similar to those of a Calendar object. Those values are displayed here.

Image Note An enum type is a type whose fields consist of a fixed set of constant values. Enum types were welcomed to the Java language in release 1.5.

· DAYS

· HOURS

· MICROSECONDS

· MILLISECONDS

· MINUTES

· NANOSECONDS

· SECONDS

The values speak for themselves with regard to the conversion interval they represent. By calling conversion methods against these enums, long values representing the duration between two dates can be converted. As you can see in the solution to this recipe, first the time unit is established using the enum and then a conversion call is made against that time unit. Take, for instance, the following conversion. First, the time unit of TimeUnit.MILLISECONDS is established. Second, the toHours() method is called against it and a long value that is represented by the mill field is passed as an argument:

TimeUnit.MILLISECONDS.toHours(mill)

This code can be translated in English as follows: “The contents of the field mill are represented in milliseconds; convert those contents into hours.” The result of this call will be the conversion of the value within the mill field into hours. By stacking the calls to TimeUnit, more precise conversions can be made. For instance, the following code converts the contents of the mill field into hours and then into days:

TimeUnit.HOURS.toDays(TimeUnit.MILLISECONDS.toHours(mill))

Again, the English translation can be read as, “The contents of the field mill are represented in milliseconds. Convert those contents into hours. Next, convert those hours into days.”

TimeUnit can make time interval conversion very precise. Combining the precision of the TimeUnit conversions along with mathematics will allow you to convert the difference of two dates into just about any time interval.

4-16. Obtaining Date-Time from a Specified String

Problem

You want to parse a string into a date-time object.

Solution

Utilize the parse() method of a temporal date-time class to parse a string using a predefined or custom format. The following lines of code demonstrate how to parse a string into a date or date-time object using variations of the parse() method.

// Parse a string to form a Date-Time object
LocalDate ld = LocalDate.parse("2014-12-28");
LocalDateTime ldt = LocalDateTime.parse("2014-12-28T08:44:00");
System.out.println("Parsed Date: " + ld);
System.out.println("Parsed Date-Time: " + ldt);

// Using a different Parser
LocalDate ld2 = LocalDate.parse("2014-12-28", DateTimeFormatter.ISO_DATE);
System.out.println("Different Parser: " + ld2);

// Custom Parser
String input = "12/28/2013";
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
LocalDate ld3 = LocalDate.parse(input, formatter);
System.out.println("Custom Parsed Date: " + ld3);
} catch (DateTimeParseException ex){
System.out.println("Not parsable: " + ex);
}

Here is the result:

Parsed Date: 2014-12-28
Parsed Date-Time: 2014-12-28T08:44
Different Parser: 2014-12-28
Custom Parsed Date: 2014-12-28

How It Works

The temporal classes of the Date-Time API include a parse() method, which can be used to parse a given input string using a specified format. By default, the parse() method will format based on the target object’s default DateTimeFormatter. For example, to parse the string"2014-01-01", the default LocalDate.parse() method can be called.

LocalDate date = LocalDate.parse("2014-01-01");

However, another DateTimeFormatter can be specified as a second argument to the parse() method. DateTimeFormatter is a final class used for formatting and printing dates and times. It contains a number of built-in formatters that can be specified to coerce strings into date-time objects. For example, to parse based on the standard ISO_DATE format without offset, call DateTimeFormatter.ISO_DATE, as demonstrated in the solution to this recipe. For more information regarding DateTimeFormatter, see the online documentation athttp://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html.

Oftentimes, it is necessary to parse strings of text into date-time objects. Such tasks are made easy with the parse() method being built into many of the core date-time classes.

4-17. Formatting Dates for Display

Problem

Dates need to be displayed by your application using a specific format. You want to define that format once and apply it to all dates that need to be displayed.

Solution #1

Utilize the DateTimeFormatter class, part of the new Date-Time API, to format dates and times according to the pattern you want to use. The DateTimeFormatter class includes an ofPattern() method, which accepts a string pattern argument to designate the desired pattern. Each of the temporal date-time classes includes a format() method, which accepts a DateTimeFormatter and returns the string-based format of the target date-time object. In the following lines of code, the DateTimeFormatter is demonstrated:

DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MMMM dd yyyy");

LocalDateTime now = LocalDateTime.now();
String output = now.format(dateFormatter);
System.out.println(output);

DateTimeFormatter dateFormatter2 = DateTimeFormatter.ofPattern("MM/dd/YY HH:mm:ss");
String output2 = now.format(dateFormatter2);
System.out.println(output2);

DateTimeFormatter dateFormatter3 = DateTimeFormatter.ofPattern("hh 'o''clock' a, zzzz");
ZonedDateTime zdt = ZonedDateTime.now();
String output3 = zdt.format(dateFormatter3);
System.out.println(output3);

Here is the result:

December 28 2013
12/28/13 10:44:06
10 o'clock AM, Central Standard Time

Solution #2

Use the java.util.Calendar class to obtain the date that you require and then format that date using the java.text.SimpleDateFormat class. The following example demonstrates the use of the SimpleDateFormat class:

// Create new calendar
Calendar cal = Calendar.getInstance();

// Create instance of SimpleDateFormat class using pattern
SimpleDateFormat dateFormatter1 = new SimpleDateFormat("MMMMM dd yyyy");
String result = null;

result = dateFormatter1.format(cal.getTime());
System.out.println(result);

dateFormatter1.applyPattern("MM/dd/YY hh:mm:ss");
result = dateFormatter1.format(cal.getTime());
System.out.println(result);

dateFormatter1.applyPattern("hh 'o''clock' a, zzzz");
result = dateFormatter1.format(cal.getTime());
System.out.println(result);

Running this example would yield the following result:

June 22 2011
06/22/11 06:24:41
06 o'clock AM, Central Daylight Time

As you can see from the results, the DateTimeFormatter and SimpleDateFormat classes make it easy to convert a date into just about any format.

How It Works

Date formatting is a common concern when it comes to any program. People like to see their dates in a certain format for different situations. The Java language contains a couple of handy utilities for proper formatting of date-time data. Specifically, the newer API includes theDateTimeFormatter class, and previous editions of Java SE include the SimpleDateFormat class, each of which can come in handy for performing formatting processes.

The DateTimeFormatter class is a final class that has the primary purpose of printing and formatting date-time objects. To obtain a DateTimeFormatter that can be applied to objects, call the DateTimeFormatter.ofPattern() method, passing the string-based pattern that represents the desired output. Table 4-8 lists the different pattern characters that can be used within a string-based pattern. The resulting DateTimeFormatter can then be applied to any temporal date-time object by calling the object’s format() method and passing theDateTimeFormatter as an argument. The result will be the date-time object formatted according to the specified template pattern.

Table 4-8. Pattern Characters

Character

Description

G

Era

y

Year

Y

Week year

M

Month in year

w

Week in year

W

Week in month

D

Day in year

d

Day in month

F

Day of week in month

E

Name of day in week

u

Number of day in week

a

AM/PM

H

Hour in day (0–23)

k

Hour in day (1–24)

K

Hour in AM/PM (0–11)

h

Hour in AM/PM (1–12)

m

Minute in hour

s

Second in minute

S

Millisecond

z

General time zone

Z

RFC 822 time zone

X

ISO 8601 time zone

The SimpleDateFormat class was created in previous editions of Java, so you don’t have to perform manual translations for a given date.

Image Note Different date formats are used within different locales, and the SimpleDateFormat class facilitates locale-specific formatting.

To use the class, an instance must be instantiated either by passing a string-based pattern as an argument to the constructor or by passing no argument to the constructor at all. The string-based pattern provides a template that should be applied to the given date and then a string representing the date in the given pattern style is returned. A pattern consists of a number of different characters strung together. Table 4-8 shows the different characters that can be used within a pattern.

Any of the pattern characters can be placed together in a string and then passed to the SimpleDateFormat class. If the class is instantiated without passing a pattern, the pattern can be applied later using the class’s applyPattern() method. The applyPattern() method also comes in handy when you want to change the pattern of an instantiated SimpleDateFormat object, as seen in the solution to this recipe. The following excerpts of code demonstrate the application of a pattern:

SimpleDateFormat dateFormatter1 = new SimpleDateFormat("MMMMM dd yyyy");
dateFormatter1.applyPattern("MM/dd/YY hh:mm:ss");

Once a pattern has been applied to a SimpleDateFormat object, a long value representing time can be passed to the SimpleDateFormat object’s format() method. The format() method will return the given date\time formatted using the pattern that was applied. The string-based result can then be used however your application requires.

4-18. Writing Readable Numeric Literals

Problem

Some of the numeric literals in your application are rather long and you want to make it easier to tell how large a number is at a glance.

Solution

Use underscores in place of commas or decimals in larger numbers in order to make them more readable. The following code shows some examples of making your numeric literals more readable by using underscores in place of commas:

int million = 1_000_000;
int billion = 1_000_000_000;
float ten_pct = 1_0f;
double exp = 1_234_56.78_9e2;

How It Works

Sometimes working with large numbers can become cumbersome and difficult to read. Because of the release of Java SE7, underscores can now be used with numeric literals in order to make code a bit easier to read. The underscores can appear anywhere between digits in a numeric literal. This allows for the use of underscores in place of commas or spaces to separate the digits and make them easier to read.

Image Note Underscores cannot be placed at the beginning or end of a number, adjacent to a decimal point or floating-point literal, prior to an F or L suffix, or in positions where a string of digits is expected.

4-19. Declaring Binary Literals

Problem

You are working on an application that requires the declaration of binary numbers.

Solution

Make use of binary literals to make your code readable. The following code segment demonstrates the use of binary literals:

int bin1 = 0b1100;
short bin2 = 0B010101;
short bin3 = (short) 0b1001100110011001;
System.out.println(bin1);
System.out.println(bin2);
System.out.println(bin3);

This will result in the following output:

12
21
-26215

How It Works

Binary literals became part of the Java language with the release of JDK 7. The types byte, short, int, and long can be expressed using the binary number system. This feature can help to make binary numbers easier to recognize in code. In order to use the binary format, simply prefix the number with 0b or 0B.

Summary

Numbers and dates play an integral role in most applications. The Java language provides a bevy of classes that can be used to work with different kinds of numbers, and format them to fit most situations. This chapter reviewed some techinques that can be used for rounding and formatting numbers, as well as generating random values. A new Date and Time package has been included with the release of Java 8, bringing a refreshing, easy to use API for obtaining and working with dates. This chapter covered the basics of the new Date and Time package, and much more is covered online: http://docs.oracle.com/javase/tutorial/datetime/.