TemporalAdjuster in Java

In this tutorial we will examine the TemporalAdjuster in Java. A TemporalAdjuster can be used to adjust a date or a temporal value.

A TemporalAdjuster is part of the new Date / Time API introduced in Java 8. You can read more about this API in the tutorial Introduction to the Java Date / Time API.

Temporal

The Temporal interface is implemented by many of the types in the new Date / Time API. It is used to represent a temporal value and provides a number of common operations that temporal types implement. Some of the types that implement this interface include:

  • Instant – a point in time
  • LocalDate – a representation of a date in the context where it is used
  • LocalDateTime – LocalDate with a time
  • OffsetDateTime – LocalDateTime with an offset
  • OffsetTime – A time with a offset
  • Year – a year
  • YearMonth – a year and month
  • ZonedDateTime – LocalDateTime with a timezone

In particular we’ll be looking at the method of the Temporal interface that allows us to adjust a temporal value using a TemporalAdjuster.

1
2
3
4
public interface Temporal extends TemporalAccessor {

    default Temporal with(TemporalAdjuster adjuster)  
}

TemporalAdjusters

TemporalAdjusters are used to modify the value of a temporal type. For example they allow us to adjust a date to the first, and last day of a month.

They come with a number of utility methods for performing common adjustments, such as:

  • firstDayOfMonth – Set to the first day of the current month
  • firstDayOfNextMonth – Set to the first day of the next month
  • firstDayOfYear – Set to the first day of the year
  • lastDayOfMonth – Set to the last day of the current month
  • lastDayOfYear – Set to the last day of the year
  • firstDayOfNextYear – Set to the first day of next year

The TemporalAdjusters utility class provides an intuitive API. You can read more about this class, and the methods it provides by visiting the Javadoc

Now that we have some background information, let’s look at some simple examples:

For the below examples we will use the date 2014-01-15:

1
LocalDate localDate = LocalDate.of(2014,1, 15)

Firstly we will move the above date to the first day of the month:

1
2
3
4
5
6
7
8
9
@Test
public void firstDayOfMonth() {
    LocalDate localDate = LocalDate.of(2014,1, 15);

    LocalDate firstDayOfMonth = localDate.with(TemporalAdjusters.firstDayOfMonth());

    String expected = "2014-01-01";
    assertEquals(expected, firstDayOfMonth.toString());
}

Next, we will adjust the date to the first friday of the month.

1
2
3
4
5
6
7
8
9
@Test
public void firstFridayOfMonth() {
    LocalDate localDate = LocalDate.of(2014,1, 15);

    LocalDate firstFridayOfMonth = localDate.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.FRIDAY));

    String expected = "2014-01-03";
    assertEquals(expected, firstFridayOfMonth.toString());
}

Above we use the method dayOfWeekInMonth this method takes an integer that represents the week number to adjust to, and also the day. This method returns a TemporalAdjuster instance, that is passed to the with method of the LocalDate instance, to adjust the temporal value.

1
2
3
4
5
6
7
@Test
public void nextFriday() {
    LocalDate localDate = LocalDate.of(2014,1, 15);
    LocalDate nextFriday = localDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
    String expected = "2014-01-17";
    assertEquals(expected, nextFriday.toString());
}

Above, we use the TemporalAdjusters.next method to adjust the date to the following Friday.

Create Custom TemporalAdjuster Implementations

A TemporalAdjuster provides a flexible mechanism to adjusting temporal values. In scenarios where we need to adjust dates in specific ways, or we want to reuse logic across application components, we have a number of options.

Lambda Expressions

We can create a TemporalAdjuster using a Lambda expression. This offers a good option when we may need to adjust temporal values on one off occasions.

1
2
3
4
5
6
7
8
@Test
public void temporalAdjuster_lambda() {
    LocalDate localDate = LocalDate.of(2014,1, 15);
    LocalDate previousDay = localDate.with((v) -> v.minus(1, ChronoUnit.DAYS));

    String expected = "2014-01-14";
    assertEquals(expected, previousDay.toString());
}

We can also use the TemporalAdjusters.ofDateAdjuster method that can be used to create a TemporalAdjuster.

1
2
3
4
5
6
7
8
9
@Test
public void temporalAdjustersOfDateAdjuster_lambda() {
    LocalDate localDate = LocalDate.of(2014,1, 15);
    TemporalAdjuster previousMonthAdjuster = TemporalAdjusters.ofDateAdjuster( (v) -> v.minus(1, ChronoUnit.MONTHS));
    LocalDate previousMonth = localDate.with(previousMonthAdjuster);

    String expected = "2013-12-15";
    assertEquals(expected, previousMonth.toString());
}

Above we use this static factory method to adjust a temporal value by subtracting a month.

Implement The TemplateAdjuster Interface

We can also create a custom TemplateAdjuster implementation by implementing the TemplateAdjuster Interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class NextBiannualTemporalAdjuster implements TemporalAdjuster {
    public static final TemporalAdjuster INSTANCE = new NextBiannualTemporalAdjuster();

    @Override
    public Temporal adjustInto(Temporal temporal) {
        if (temporal == null) {
            return null;
        }
        return temporal.plus(2, ChronoUnit.YEARS);
    }
}

Above we create a TemporalAdjuster to move a temporal value ahead by two years. Notice, we also create a singleton instance to facilitate reuse, and keep memory consumption to a minimum.

1
public static final TemporalAdjuster INSTANCE = new NextBiannualTemporalAdjuster();

Let’s write a test case for the above implementation:

1
2
3
4
5
6
7
8
@Test
public void temporalAdjuster_custom() {
    LocalDate localDate = LocalDate.of(2014, 1, 15);
    LocalDate nextBiannual = localDate.with(NextBiannualTemporalAdjuster.INSTANCE);

    String expected = "2016-01-15";
    assertEquals(expected, nextBiannual.toString());
}

Custom TemporalAdjuster Utility Class

Possibly the best approach is to follow the approach taken by the Java Date / Time API and create a custom utility class, to perform temporal adjustments.

1
2
3
4
5
public abstract class CustomTemporalAdjusters {
    public static TemporalAdjuster nextBiannual() {
        return NextBiannualTemporalAdjuster.INSTANCE;
    }
}
1
2
3
4
5
6
7
@Test
public void temporalAdjuster_customUtil() {
    LocalDate localDate = LocalDate.of(2014, 1, 15);
    LocalDate nextBiannual = localDate.with(CustomTemporalAdjusters.nextBiannual());
    String expected = "2016-01-15";
    assertEquals(expected, nextBiannual.toString());
}

Conclusion

In this short tutorial we examined what a Temporal Type is in Java, and how to adjust temporal values through the use of a TemporalAdjuster.