Java 8 java.time.temporal. TemporalAdjuster tutorial with examples

This tutorial explains how date and time adjustments can be performed using Java 8’s new TemporalAdjuster interface with examples. It starts off with explaining what is a TemporalAdjuster and its purpose. It then goes through the list of predefined Temporal Adjusters provided by the TemporalAdjusters class. Next, the two ways (or methods) of using Temporal Adjusters for date adjustment viz Temporal.with() and TemporalAdjuster.adjustInto() are explained with code examples. Lastly, the tutorial explains how to define a custom TemporalAdjuster implementation of one’s own using lambda expressions, in case the predefined Temporal Adjusters are not able to serve your date-time adjustment requirements.

What is a Temporal Adjuster
Certain date-time modification operations may need to be applied to dates repeatedly based on business and application requirements. In Java 8’s new Date-Time APIClick to Read Overview of Java 8’s new Date-Time API, these date-time modification operations can be abstracted out as individual java.time.temporal.TemporalAdjuster instances.

These individual TemporalAdjuster instances can then be used to carry out the desired date modifications, or adjustments, as and when required. By abstracting out date adjustment strategies, application can be designed against the TemporalAdjuster contract. The design of such systems can then remain closed for modification. At the same time, the design remains open for extension by allowing different Temporal Adjustment implementations. Such a design, which allows multiple strategies to be used at runtime, while the application design itself remains constant, apart from adhering to the Open-Closed PrincipleClick to Read Tutorial on Open-Closed Principle, is also typical of a strategy design patternClick to Read Strategy Design Pattern Tutorial implementation.

Examples of common Temporal Adjusters – Date modification instructions such as finding the next working day, or the next Monday, last day of the week, first working day of the month are all examples of standard date calculation scenarios. All of these scenarios involve adjusting a given date to arrive at another date as per the adjustment requirement.

Java designers have, in fact, thought of the most common of such date adjustment scenarios, and provided predefined TemporalAdjuster implementations via the TemporalAdjusters class. Let us first take a look at TemporalAdjusters and the predefined Temporal Adjusters it provides.

Predefined Temporal Adjusters
java.time.temporal.TemporalAdjusters has provided static factory methods to access predefined commonly used Temporal Adjusters. These are –

Table: Predefined Temporal Adjusters in TemporalAdjusters class

Method Name Purpose
firstDayOfMonth(), lastDayOfMonth() Get first/last day of month.
firstDayOfNextMonth() Get first day of previous month.
firstDayOfNextYear() Get first day of next year.
firstDayOfYear(), lastDayOfYear() Get first/last day of year.
firstInMonth(), lastInMonth() Get first/last occurrence of a DayOfWeekClick to Read Tutorial on Java 8’s DayOfWeek Enum in month.
next(), previous() Next/Previous occurrence of DayOfWeek.
nextOrSame(), previousOrSame() Next/current DayOfWeek
dayOfWeekInMonth() Ordinal DayOfWeek in month

If any of the above date adjustments matches your requirement, then you don’t need to implement a new TemporalAdjuster of your own. Simply go ahead and get a reference to the instance of your required date adjuster using the static factory method mentioned above.

We have now understood what a Temporal Adjuster is used for, and also had a look at the set of predefined Temporal Adjusters. Let us now see the two ways (or methods) for using a Temporal Adjuster in code.

Two methods for using Temporal Adjusters in code
Temporal Adjusters can be coded for using either of these two methods –

  1. Using Temporal.with() method (recommended way)Temporal is the parent interface of all the new Date-Time classes in Java 8. It defines the default method named with() with the following signature –
    default Temporal with(TemporalAdjuster adjuster)

    Where,
           – adjuster is an instance of TemporalAdjuster containing the logic for adjusting the Temporal object on which this method is invoked.
           – the method returns an immutable instance of Temporal which will be of the same type (subclass of Temporal) on which this method is invoked.
           – among the two methods for using Temporal Adjusters, this method is recommended due to better readability.

    So, given a date, if you want to find out the last day of the month in which that date occurs, then finding the required date is quite simple using the TemporalAdjuster instance returned by TemporalAdjusters.lastDayOfMonth() method. Let us see a code snippet showing the use of Temporal.with() method and couple of predefined Temporal Adjusters.

    Date adjustment using Temporal.with() method
    //Using TemporalAdjusters.lastDayOfMonth()
    LocalDate localDate= LocalDate.now();
    LocalDate lastDayOfMonth=localDate.with(TemporalAdjusters.lastDayOfMonth());
    System.out.println("Last day of month of "+localDate+" is: "+lastDayOfMonth);
    
    //Using TemporalAdjusters.firstDayOfNextMonth()
    LocalDate firstDayOfNextMonth=localDate.with(TemporalAdjusters.firstDayOfNextMonth());
    System.out.println("First day of next month for "+localDate+" is: "+firstDayOfNextMonth);
    
     OUTPUT of the above code
    Last day of month for 2017-01-11 is:   2017-01-31
    First day of next month for 2017-01-11 is:   2017-02-01
    Explanation of the code

    • LocalDate.now() method is used to get the current date from the System clock. The value returned is ‘2017-01-11’ and is stored in a variable named localDate.
    • localDate.with() method is invoked with the parameter being the TemporalAdjuster instance returned by TemporalAdjusters.lastDayOfMonth() method.
    • The adjusted date, i.e.last day of the month for localDate, is returned by the with() method, and assigned to lastDayOfMonth variable. Note that the type of localDate and lastDayOfMonth is the same i.e. LocalDate.
    • Next, the value for lastDayOfMonth is printed correctly as ‘2017-01-31’.
    • In the same manner, first day of next month for localDate is determined using the with() method. This time the parameter of the with() method is the TemporalAdjuster returned by TemporalAdjusters.firstDayOfNextMonth().
    • Value of firstDayOfNextMonth is determined correctly and printed as ‘2017-02-01’.
  2. Using TemporalAdjuster.adjustInto() methodTemporalAdjuster interface defines a method named adjustInto() with the following signature –
    Temporal adjustInto(Temporal temporal);

    Where,
           – temporal parameter is an instance of a subtype of Temporal which needs to be adjusted. I.e. this parameter is the temporal value based on which calculation has to be performed.
           – the method returns an immutable instance of Temporal which will be of the same type (subclass of Temporal) as the input parameter.
           – among the two methods for using Temporal Adjusters, this method is not recommended due to less readability.

    Let us take the same use cases for seeing adjustInto() method in action as we took for with() method. I.e. given a date, we want to find out the last day of the month in which that date occurs, and the first day of the next month.

    Date adjustment using TemporalAdjuster.adjustInto() method
    //Using TemporalAdjusters.lastDayOfMonth()
    LocalDate localDate= LocalDate.now();
    LocalDate lastDayOfMonth=(LocalDate)TemporalAdjusters.lastDayOfMonth().adjustInto(localDate);
    System.out.println("Last day of month for "+localDate+" is: "+lastDayOfMonth);
    
    //Using TemporalAdjusters.firstDayOfNextMonth()
    LocalDate firstDayOfNextMonth = (LocalDate)TemporalAdjusters.firstDayOfNextMonth().adjustInto(localDate);
    System.out.println("First day of next month for "+localDate+" is: "+firstDayOfNextMonth);
    
     OUTPUT of the above code
    Last day of month for 2017-01-11 is:   2017-01-31
    First day of next month for 2017-01-11 is:   2017-02-01
    Explanation of the code

    • LocalDate.now() method is used to get the current date from the System clock. The value returned is ‘2017-01-11’ and is stored in a variable named localDate.
    • adjustInto() method is invoked on the TemporalAdjuster instance obtained using the method TemporalAdjusters.lastDayOfMonth(). localDate, which is to be adjusted to last date of the month, is passed as a parameter to the adjustInto() method.
    • The value returned by the adjustInto() method is typecast into a LocalDate and assigned to the variable named lastDayOfMonth.
    • Note that the typecasting needed for adjustInto() is not required when adjusting dates using with() method we saw earlier.
    • Value for lastDayOfMonth is printed correctly as ‘2017-01-31’.
    • Similarly, first day of next month is calculated using TemporalAdjuster obtained from TemporalAdjusters.firstDayOfNextMonth() method and is printed correctly as ‘2017-02-01’.

Defining a custom Temporal Adjuster
If your date adjustment requirement is not fulfilled by any of the predefined Temporal Adjusters provided by the TemporalAdjusters class, then you will need to create a Temporal Adjuster of your own.

TemporalAdjuster interface in Java 8 is a functional interfaceClick to read tutorial on Functional Interfaces. It has a single method named adjustInto() which is the same method we saw in the earlier section. On account of TemporalAdjuster being a functional interface, creating its implementation is straightforward.

To create your custom implementation of a TemporalAdjuster, all you need to do is define a lambda expressionClick to read Lambda Expressions tutorial, whose function descriptorClick to Read Tutorial explaining function descriptors matches the signature of adjustInto() method. Then you can chose to either pass this lambda expression as a parameter to Temporal.with() method. Or, you can use this instance of TemporalAdjuster created using the lambda expression and invoke the adjustInto() method on it.

To understand better, let us now see a code snippet which defines a TemporalAdjuster using a lambda expression and then uses it for date adjustment. The custom Temporal Adjuster in the example will do the simple taks of adding 2 days to the date being adjusted.

Creating a custom TemporalAdjuster using a lambda expression
package com.javabrahman.java8.time;
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class CustomTemporalAdjuster {
  public static void main(String args[]) {
    LocalDate localDate = LocalDate.now();
    TemporalAdjuster add2days = (Temporal date) -> ((LocalDate)date).plusDays(2);
    System.out.println("2 days added to "+localDate+" gives: "+localDate.with(add2days));
  }
}
 OUTPUT of the above code
2 days added to  2017-01-11  gives:   2017-01-13
Explanation of the code

  • CustomTemporalAdjuster first creates an instance of LocalDate, named localDate, using LocalDate.now() method. The value stored in localDate is ‘2017-01-11’.
  • Next an implementation of TemporalAdjuster, named add2days, is created by defining its functionality using a lambda expression – (Temporal date) -> ((LocalDate)date).plusDays(2).
  • The lambda takes a Temporal as input named date. In this case the Temporal type needs to be a LocalDate. Hence, when the lambda is evaluated, date is typecast to LocalDate and 2 days are added to it.
  • Using the Temporal.with() method add2days is used to adjust the value of localDate. The adjusted value is then printed and as expected the resulting date is moved forward by 2 days to ‘2017-01-13’.
  • Note that this is a very simple example showing how to implement a custom TemporalAdjuster using a lambda expression. It does not take care of possible exception scenarios such as passing a Temporal which is not a LocalDate which will potentially lead to typecast exception, and similar exceptions.

Summary
In the above tutorial we first understood what is TemporalAdjuster interface via its definition and purpose, looked at predefined Temporal Adjusters which can be accessed through TemporalAdjusters class, understood the two methods for coding these date adjustments, and lastly understood how to define custom TemporalAdjuster implementation of our own using a lambda expression.

 

Digiprove sealCopyright © 2014-2019 JavaBrahman.com, all rights reserved.