Temporal Arithmetic with Dates and Times – Date and Time

Temporal Arithmetic with Dates and Times

The temporal classes provide plus and minus methods that return a copy of the original object that has been incremented or decremented by a specific amount of time— for example, by number of hours or by number of months.

The LocalTime and LocalDate classes provide plus/minus methods to increment/ decrement a time or a date by a specific amount in terms of a time unit (e.g., hours, minutes, and seconds) or a date unit (e.g., years, months, and days), respectively. The LocalDateTime class provides plus/minus methods to increment/decrement a date-time object by an amount that is specified in terms of either a time unit or a date unit. For example, the plusMonths(m) and plus(m, ChronoUnit.MONTHS) method calls to a LocalDate object will return a new LocalDate object after adding the specified number of months passed as an argument to the method. Similarly, the minus-Minutes(mm) and minus(mm, ChronoUnit.MINUTES) method calls on a LocalTime class will return a new LocalTime object after subtracting the specified number of minutes passed as an argument to the method. The change is relative, and is reflected in the new temporal object that is returned. Such plus/minus methods are also called relative adjusters, in contrast to absolute adjusters (p. 1035). The ChronoUnit enum type implements the TemporalUnit interface (p. 1044).

Click here to view code image

// LocalTime, LocalDateTime
LocalTime/LocalDateTime minusHours(long hours)
LocalTime/LocalDateTime plusHours(long hours)
LocalTime/LocalDateTime minusMinutes(long minutes)
LocalTime/LocalDateTime plusMinutes(long minutes)
LocalTime/LocalDateTime minusSeconds(long seconds)
LocalTime/LocalDateTime plusSeconds(long seconds)
LocalTime/LocalDateTime minusNanos(long nanos)
LocalTime/LocalDateTime plusNanos(long nanos)

Return a copy of this LocalTime or LocalDateTime object with the specified amount either subtracted or added to the value of a specific time field. The calculation always wraps around midnight.

For the methods of the LocalDateTime class, a DateTimeException is thrown if the result exceeds the date range.

Click here to view code image

// LocalDate, LocalDateTime
LocalDate/LocalDateTime minusYears(long years)
LocalDate/LocalDateTime plusYears(long years)
LocalDate/LocalDateTime minusMonths(long months)
LocalDate/LocalDateTime plusMonths(long months)
LocalDate/LocalDateTime minusWeeks(long weeks)
LocalDate/LocalDateTime plusWeeks(long weeks)
LocalDate/LocalDateTime minusDays(long days)
LocalDate/LocalDateTime plusDays(long days)

Return a copy of this LocalDate or LocalDateTime with the specified amount either subtracted or added to the value of a specific date field.

All methods throw a DateTimeException if the result exceeds the date range.

The first four methods will change the day of the month to the last valid day of the month if necessary, when the day of the month becomes invalid as a result of the operation.

The last four methods will adjust the month and year fields as necessary to ensure a valid result.

Click here to view code image

// LocalTime, LocalDate, LocalDateTime
LocalTime/LocalDate/LocalDateTime minus(long amountToSub,
                                        TemporalUnit unit)
LocalTime/LocalDate/LocalDateTime plus(long amountToAdd, TemporalUnit unit)
boolean isSupported(TemporalUnit unit)

The minus() and plus() methods return a copy of this temporal object with the specified amount subtracted or added, respectively, according to the TemporalUnit specified. The ChronoUnit enum type implements the TemporalUnit interface, and its enum constants define specific temporal units (p. 1044).

The isSupported() method checks if the specified TemporalUnit is supported by this temporal object. It avoids an exception being thrown if it has been determined that the unit is supported.

The minus() or the plus() method can result in any one of these exceptions: DateTimeException (the amount cannot be subtracted or added), Unsupported-TemporalTypeException (unit is not supported), or ArithmeticException (numeric overflow occurred).

Click here to view code image

// LocalTime, LocalDate, LocalDateTime
LocalTime/LocalDate/LocalDateTime minus(TemporalAmount amountToSub)
LocalTime/LocalDate/LocalDateTime plus(TemporalAmount amountToAdd)

Return a copy of this temporal object with the specified temporal amount subtracted or added, respectively. The classes Period (p. 1057) and Duration (p. 1064) implement the TemporalAmount interface.

The minus() or the plus() method can result in any one of these exceptions: DateTimeException (the temporal amount cannot be subtracted or added) or ArithmeticException (numeric overflow occurred).

Click here to view code image

// LocalTime, LocalDate, LocalDateTime
long until(Temporal endExclusive, TemporalUnit unit)

Calculates the amount of time between two temporal objects in terms of the specified TemporalUnit (p. 1044). The start and the end points are this temporal object and the specified temporal argument endExclusive, where the end point is excluded. The result will be negative if the other temporal is before this temporal.

The until() method can result in any one of these exceptions: DateTime-Exception (the temporal amount cannot be calculated or the end temporal cannot be converted to the appropriate temporal object), UnsupportedTemporalType-Exception (unit is not supported), or ArithmeticException (numeric overflow occurred).

Click here to view code image

// LocalDate
Period until(ChronoLocalDate endDateExclusive)

Calculates the amount of time between this date and another date as a Period (p. 1057). The calculation excludes the end date. The LocalDate class implements the ChronoLocalDate interface.

Example 17.3 demonstrates what we can call temporal arithmetic, where a LocalDate object is modified by adding or subtracting an amount specified as days, weeks, or months. Note how the value of the date fields is adjusted after each operation. In Example 17.3, the date 2021-10-23 is created at (1), and 10 months, 3 weeks, and 40 days are successively added to the new date object returned by each plus method call at (2), (3), and (4), respectively, resulting in the date 2022-10-23. We then subtract 2 days, 4 weeks, and 11 months successively from the new date object returned by each minus() method call at (5), (6), and (7), respectively, resulting in the date 2021-10-23. The method calls at (5), (6), and (7) are passed the temporal unit explicitly. In Example 17.3, several assignment statements are used to print the intermediate dates, but the code can be made more succinct by method chaining.

Click here to view code image

LocalDate date = LocalDate.of(2021, 10, 23);             // 2021-10-23
date = date.plusMonths(10).plusWeeks(3).plusDays(40);    // Method chaining
System.out.println(date);                                // 2022-10-23
date = date.minus(2, ChronoUnit.DAYS)
           .minus(4, ChronoUnit.WEEKS)
           .minus(11, ChronoUnit.MONTHS);                // Method chaining
System.out.println(date);                                // 2021-10-23

The following code snippet illustrates the wrapping of time around midnight, as one would expect on a 24-hour clock. Each method call returns a new LocalTime object.

Click here to view code image

LocalTime witchingHour = LocalTime.MIDNIGHT              // 00:00
    .plusHours(14)                                       // 14:00
    .plusMinutes(45)                                     // 14:45
    .plusMinutes(30)                                     // 15:15
    .minusHours(15)                                      // 00:15
    .minusMinutes(15);                                   // 00:00

The next code snippet illustrates how the plusYears() method adjusts the day of the month, if necessary, when the year value is changed. The year in the date 2020-02-29 is changed to 2021 by adding 1 year, resulting in the following date: 2021-02-29. The plusYears() method adjusts the day of the month to the last valid day of the month, 28; as the year 2021 is not a leap year, the month of February cannot have 29 days.

Click here to view code image

LocalDate date5 = LocalDate.of(2020, 2, 29);  // Original: 2020-02-29
date5 = date5.plusYears(1);                   // Expected: 2021-02-29
System.out.println(“Date5: ” + date5);        // Adjusted: 2021-02-28

A temporal can also be adjusted by a temporal amount—for example, by a Period (p. 1057) or a Duration (p. 1064). The methods plus() and minus() accept the temporal amount as an argument, as shown by the code below.

Click here to view code image

LocalTime busDep = LocalTime.of(12, 15);                   // 12:15
Duration d1 = Duration.ofMinutes(30);                      // PT30M
LocalTime nextBusDep = busDep.plus(d1);                    // 12:45
LocalDate birthday = LocalDate.of(2020, 10, 23);           // 2020-10-23
Period p1 = Period.ofYears(1);                             // P1Y
LocalDate nextBirthday = birthday.plus(p1);                // 2021-10-23

The until() method can be used to calculate the amount of time between two compatible temporal objects. The code below calculates the number of days to New Year’s Day from the current date; the result, of course, will depend on the current date. In the call to the until() method at (1), the temporal unit specified is ChronoUnit.DAYS, as we want the difference between the dates to be calculated in days.

Click here to view code image

LocalDate currentDate = LocalDate.now();
LocalDate newYearDay = currentDate.plusYears(1).withMonth(1).withDayOfMonth(1);
long daysToNewYear = currentDate.until(newYearDay, ChronoUnit.DAYS); // (1)
System.out.println(“Current Date: ” + currentDate); // Current Date: 2021-03-08
System.out.println(“New Year’s Day: ” + newYearDay);// New Year’s Day: 2022-01-01
System.out.println(“Days to New Year: ” + daysToNewYear);// Days to New Year: 299

The statement at (1) below is meant to calculate the number of minutes until midnight from now, but throws a DateTimeException because it is not possible to obtain a LocalDateTime object from the end point, which is a LocalTime object.

Click here to view code image

long minsToMidnight = LocalDateTime.now()             // (1) DateTimeException!
         .until(LocalTime.MIDNIGHT.minusSeconds(1), ChronoUnit.MINUTES);

However, the statement at (2) executes normally, as both the start and end points are LocalTime objects.

Click here to view code image

long minsToMidnight = LocalTime.now()                 // (2)
         .until(LocalTime.MIDNIGHT.minusSeconds(1), ChronoUnit.MINUTES);

Example 17.3 Temporal Arithmetic

Click here to view code image

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class TemporalArithmetic {
  public static void main(String[] args) {
    LocalDate date = LocalDate.of(2021, 10, 23);           // (1)
    System.out.println(“Date:             ” + date);       // 2021-10-23
    date = date.plusMonths(10);                            // (2)
    System.out.println(“10 months after:  ” + date);       // 2022-08-23
    date = date.plusWeeks(3);                              // (3)
    System.out.println(“3 weeks after:    ” + date);       // 2022-09-13
    date = date.plusDays(40);                              // (4)
    System.out.println(“40 days after:    ” + date);       // 2022-10-23
    date = date.minus(2, ChronoUnit.DAYS);                 // (5)
    System.out.println(“2 days before:    ” + date);       // 2022-10-21
    date = date.minus(4, ChronoUnit.WEEKS);                // (6)
    System.out.println(“4 weeks before:   ” + date);       // 2022-09-23
    date = date.minus(11, ChronoUnit.MONTHS);              // (7)
    System.out.println(“11 months before: ” + date);       // 2021-10-23
  }
}

Output from the program:

Date:             2021-10-23
10 months after:  2022-08-23
3 weeks after:    2022-09-13
40 days after:    2022-10-23
2 days before:    2022-10-21
4 weeks before:   2022-09-23
11 months before: 2021-10-23

Leave a Reply

Your email address will not be published. Required fields are marked *