Temporal Arithmetic with Instants – Date and Time

Temporal Arithmetic with Instants

The Instant class provides plus and minus methods that return a copy of the original instant that has been incremented or decremented by a specific amount specified in terms of either seconds, milliseconds, or nanoseconds. Each amounts below is explicitly designated as a long to avoid problems if the amount does not fit into an int.

Click here to view code image

Instant event =
    Instant.EPOCH                    //            1970-01-01T00:00:00Z
           .plusSeconds(7L*24*60*60) // (+7days)   1970-01-08T00:00:00Z
           .plusSeconds(6L*60*60)    // (+6hrs)    1970-01-08T06:00:00Z
           .plusSeconds(5L*60)       // (+5mins)   1970-01-08T06:05:00Z
           .plusSeconds(4L)          // (+4s)      1970-01-08T06:05:04Z
           .plusMillis(3L*100)       // (+3ms)     1970-01-08T06:05:04.003Z
           .plusNanos(2L*1_000)      // (+2micros) 1970-01-08T06:05:04.003002Z
           .plusNanos(1L);           // (+1ns)     1970-01-08T06:05:04.003002001Z

However, it is more convenient to express the above calculation using the plus(amount, unit) method, which also allows the amount to be qualified by a unit. This is illustrated by the statement below, which is equivalent to the one above.

Click here to view code image

Instant ptInTime =
     Instant.EPOCH                          // 1970-01-01T00:00:00Z
            .plus(7L, ChronoUnit.DAYS)      // 1970-01-08T00:00:00Z
            .plus(6L, ChronoUnit.HOURS)     // 1970-01-08T06:00:00Z
            .plus(5L, ChronoUnit.MINUTES)   // 1970-01-08T06:05:00Z
            .plus(4L, ChronoUnit.SECONDS)   // 1970-01-08T06:05:04Z
            .plus(3L, ChronoUnit.MILLIS)    // 1970-01-08T06:05:04.003Z
            .plus(2L, ChronoUnit.MICROS)    // 1970-01-08T06:05:04.003002Z
            .plus(1L, ChronoUnit.NANOS);    // 1970-01-08T06:05:04.003002001Z

The code below shows the plus() method of the Instant class that takes a Duration (p. 1064) as the amount to add.

Click here to view code image

Instant start = Instant.EPOCH
                       .plus(20, ChronoUnit.MINUTES);// 1970-01-01T00:20:00Z
Duration length = Duration.ZERO.plusMinutes(90);     // PT1H30M (90 mins)
Instant end = start.plus(length);                    // 1970-01-01T01:50:00Z

The until() method calculates the amount of time between two instants in terms of the unit specified in the method.

Click here to view code image

long eventDuration1 = start.until(end, ChronoUnit.MINUTES);  // 90 minutes
long eventDuration2 = start.until(end, ChronoUnit.HOURS);    // 1 hour

As an Instant does not represent an amount of time, but a point on the timeline, it cannot be used in temporal arithmetic with other temporal objects. Although an Instant incorporates a date, it is not possible to access it in terms of year and month.

Click here to view code image

Instant plusSeconds/minusSeconds(long seconds)
Instant plusMillis/minusMillis(long millis)
Instant plusNanos/minusNanos(long nanos)

Return a copy of this instant, with the specified amount added or subtracted. Note that the argument type is long.

The methods throw a DateTimeException if the result is not a valid instant, and an ArithmeticException if numeric flow occurs during the operation.

Click here to view code image

Instant plus(long amountToAdd, TemporalUnit unit)
Instant minus(long amountToSub, TemporalUnit unit)

Return a copy of this instant with the specified amount added or subtracted, respectively, where the specified TemporalUnit qualifies the amount (p. 1044).

The following units, defined as constants by the ChronoUnit class, can be used to qualify the amount: NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS, and DAYS (p. 1044).

A method call can result in any one of these exceptions: DateTimeException (if the operation cannot be performed), UnsupportedTemporalTypeException (if the unit is not supported), or ArithmeticException (if numeric overflow occurs).

Click here to view code image

Instant isSupported(TemporalUnit unit)

Returns true if the specified unit is supported (p. 1044), in which case, the unit can be used in plus/minus operations on an instant. If the specified unit is not supported, the plus/minus methods that accept a unit will throw an exception.

Click here to view code image

Instant plus(TemporalAmount amountToAdd)
Instant minus(TemporalAmount amountToSubtract)

Return a copy of this instant, with the specified amount added or subtracted. The amount is typically defined as a Duration.

A method call can result in any one of these exceptions: DateTimeException (if the operation cannot be performed) or ArithmeticException (if numeric overflow occurs).

Click here to view code image

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 end points are this temporal object and the specified temporal argument, where the end point is excluded.

The start point is an Instant, and the end point temporal is converted to an Instant, if necessary.

The following units, defined as constants by the ChronoUnit class, can be used to indicate the unit in which the result should be returned: NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS, and DAYS (p. 1044).

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

Comparing Instants – Date and Time

Comparing Instants

The methods isBefore() and isAfter() can be used to determine if one instant is before or after the other on the timeline, respectively.

Click here to view code image

// instA is  1970-01-01T00:00:00.000000500Z
// instB is  1949-03-01T12:30:15Z
// instC is -1949-03-01T12:30:15Z
out.println(instA.isBefore(instB));              // false
out.println(instA.isAfter(instC));               // true

The Instant class also overrides the equals() method and the hashCode() method of the Object class, and implements the Comparable<Instant> interface. Instants can readily be used in collections. The code below illustrates comparing instants.

Click here to view code image

out.println(instA.equals(instB));                 // false
out.println(instA.equals(instC));                 // false
List<Instant> list = Arrays.asList(instA, instB, instC);
Collections.sort(list);             // Natural order: position on the timeline.
// [-1949-03-01T12:30:15Z, 1949-03-01T12:30:15Z, 1970-01-01T00:00:00.000000500Z]

Click here to view code image

boolean isBefore(Instant other)
boolean isAfter(Instant other)

Determine whether this Instant is before or after the other instant on the timeline, respectively.

boolean equals(Object other)

Determines whether this Instant is equal to the other instant, based on the timeline position of the instants.

int hashCode()

Returns a hash code for this Instant.

int compareTo(Instant other)

Compares this Instant with the other instant, based on the timeline position of the instants.

Creating Modified Copies of Instants

The Instant class provides the with(field, newValue) method that returns a copy of this instant with either the epoch-second or the nano-of-second set to a new value, while the other one is unchanged.

Click here to view code image

Instant with(TemporalField field, long newValue)

Returns a copy of this instant where either the epoch-second or the nano-of-second is set to the specified value. The value of the other is retained.

This method only supports the following ChronoField constants: NANO_OF_SECOND, MICRO_OF_SECOND, MILLI_OF_SECOND, and INSTANT_SECONDS (p. 1046). For the first three fields, the nano-of-second is replaced by appropriately converting the specified value, and the epoch-second will be unchanged in the copy returned by the method. For the INSTANT_SECONDS field, the epoch-second will be replaced and the nanosecond will be unchanged in the copy returned by the method. Valid values that can be specified with these constants are [0–999999999], [0–999999], [0–999], and a long, respectively.

This method throws a DateTimeException if the field cannot be set, an Unsupported-TemporalTypeException if the field is not supported, and an ArithmeticException if number overflow occurs.

In the code below, the three instants i1, i2, and i3 will have the nano-of-second set to 5,000,000,000 nanoseconds using the with() method, but the epoch-second will not be changed.

Click here to view code image

Instant i0, i1, i2, i3;
i0 = Instant.now();
out.println(i0);                             // 2021-02-28T08:43:35.864Z
i1 = i0.with(ChronoField.NANO_OF_SECOND,  500_000_000);// 500000000 ns.
i2 = i0.with(ChronoField.MICRO_OF_SECOND, 500_000);    // 500000×1000 ns.
i3 = i0.with(ChronoField.MILLI_OF_SECOND, 500);        // 500×1000000 ns.
out.println(i1);                             // 2021-02-28T08:43:35.500Z
out.println(i1.equals(i2));                  // true
out.println(i1.equals(i3));                  // true

In the code below, oneInstant has the nano-of-second set to 500,000,000 nanoseconds and the epoch-second set to 1 day after the epoch.

Click here to view code image

Instant oneInstant = Instant.now()
                            .with(ChronoField.MILLI_OF_SECOND, 500)
                            .with(ChronoField.INSTANT_SECONDS, 24L*60*60);
out.println(oneInstant);                     // 1970-01-02T00:00:00.500Z