Learn Java

Java Instant

The java.time package provides us with classes for working with chronographic units. In this topic, you will explore the Instant class: a date-time unit suitable for capturing event timestamps during the application execution. You will learn how to create those units and perform various operations with them. Class Instant has a lot in common with the LocalDateTime class but they also have differences which this theory will help you discover.

Creational methods

The Instant units are created in a similar way to Period and Duration class units. It provides static methods for creating the date and time in the ISO 8601 format. Instant values are stored in a long variable storing the seconds counting from the Java epoch and an int variable storing the nanoseconds of a second. Epoch is a common date-time representation format counting the date and time relative to January 1, 1970 (midnight UTC/GMT) which looks like 1970-01-01T00:00:00Z in the ISO 8601 format. You can obtain this value with the Instant.EPOCH static field.

Instant epoch = Instant.EPOCH;
System.out.println(epoch); // 1970-01-01T00:00:00Z

In the code above the last Z stands for the time-zone ID, which is zero in our case. So, it shows us the epoch time of the GMT0 time zone. Of course, you can obtain the time of any zone you need. We will show how to do that later in this section.
So, in Java, when working with the Instant class, you specify the date before or after the epoch time counting in seconds and nanoseconds.
Let's start with the three basic methods you will probably use most:

long posValue = 1234567890L;
long negValue = -1234567890L;

// Adding specified milliseconds to epoch
Instant milli = Instant.ofEpochMilli(posValue); // 1970-01-15T06:56:07.890Z
// Adding specified seconds to epoch
Instant second = Instant.ofEpochSecond(posValue); // 2009-02-13T23:31:30Z
// Adding specified seconds and nanoseconds to epoch
Instant secondNano = Instant.ofEpochSecond(posValue, 123L); // 2009-02-13T23:31:30.000000123Z
// Adding specified seconds and nanoseconds to epoch. Version 2
Instant nanoRounded = Instant.ofEpochSecond(posValue, 1_000_000_123L); // 2009-02-13T23:31:31.000000123Z


// Subtracting specified milliseconds from epoch
Instant milli = Instant.ofEpochMilli(negValue); // 1969-12-17T17:03:52.110Z
// Subtracting specified seconds from epoch
Instant second = Instant.ofEpochSecond(negValue); // 1930-11-18T00:28:30Z
// Subtracting specified seconds and nanoseconds from epoch
Instant secondNano = Instant.ofEpochSecond(negValue, -150L); // 1930-11-18T00:28:29.999999850Z
// Subtracting specified seconds and nanoseconds from epoch. Version 2
Instant nanoRounded = Instant.ofEpochSecond(negValue, -1_000_000_150L); // 1930-11-18T00:28:28.999999850Z

Although ofEpochSecond(long epochSecond, long nanoAdjustment) accepts a long type variable, it rounds each 1bln nanoseconds to a second and adds to the epochSecond, and the rest is stored in an int variable, as we mentioned earlier.

We created units bigger than January 1, 1970 (midnight UTC/GMT) by passing positive values to methods, and smaller units by passing negative values. As you see from the last letter, all of them show the time of GMT0 time zone. There will be many situations where you will need to obtain an Instant unit for a given time zone. In such cases you can use the ZoneId class to specify the zone:

Instant instant = Instant.ofEpochSecond(1234567890L);
       
System.out.println(instant); // 2009-02-13T23:31:30Z 
System.out.println(instant.atZone(ZoneId.of("GMT+4"))); // 2009-02-14T03:31:30+04:00[GMT+04:00]
System.out.println(instant.atZone(ZoneId.of("+04:00"))); // 2009-02-14T03:31:30+04:00
System.out.println(instant.atZone(ZoneId.of("Asia/Yerevan"))); // 2009-02-14T03:31:30+04:00[Asia/Yerevan]
System.out.println(instant.atZone(ZoneId.systemDefault())); // 2009-02-14T03:31:30+04:00[Asia/Yerevan]
        
System.out.println(ZoneId.systemDefault().getId()); // Asia/Yerevan
System.out.println(ZoneId.systemDefault().getRules()); // ZoneRules[currentStandardOffset=+04:00]

If you don't know your time zone ID or the offset (the difference between a specified time zone and GMT0), the last two lines from the code above will help you. In our case, it shows the Armenia/Yerevan time zone.
The next method for creating Instant units is Instant.parse(), which creates a unit object by accepting a text and parsing it to the Instant type.

Instant instant = Instant.parse("2009-02-14T03:31:30Z");
    
System.out.println(instant); // 2009-02-14T03:31:30Z
System.out.println(instant.atZone(ZoneId.of("GMT+4"))); // 2009-02-14T07:31:30+04:00[GMT+04:00]

Operational methods

Now that you know how to create Instant units, let's explore its other methods which help us perform different kinds of operations. We will start with the simple isBefore()/isAfter() pair of methods comparing the chronological order of two units.

Instant instant1 = Instant.ofEpochSecond(123456L);
Instant instant2 = Instant.ofEpochSecond(123456789L);
    
System.out.println(instant1.isAfter(instant2)); // false
System.out.println(instant1.isBefore(instant2)); // true

Besides these two methods returning a boolean result of the comparison, the class implements the compareTo() method from the Comparable interface:

Instant instant1 = Instant.ofEpochSecond(123456L);
Instant instant2 = Instant.ofEpochSecond(123456789L);

System.out.println(instant1.compareTo(instant2)); // -1

Depending on the situation, you can choose which approach of comparison is more suitable for you.
Working with dates and units of time, you will definitely need to add or subtract two units at some point. This class doesn't implement the addTo() and subtractFrom() methods that are implemented in the Period and Duration classes, but it implements some others: minus()plus() and their "subversions", such as minusSeconds()plusSeconds(), and so on.

Instant instant = Instant.ofEpochSecond(123456L);

System.out.println(instant); // 1970-01-02T10:17:36Z

System.out.println(instant.minus(Period.ofDays(1))); // 1970-01-01T10:17:36Z
System.out.println(instant.minus(Duration.ofDays(1))); //  1970-01-01T10:17:36Z
System.out.println(instant.minus(1, ChronoUnit.DAYS)); // 1970-01-01T10:17:36Z

System.out.println(instant.plus(Period.ofDays(1))); // 1970-01-03T10:17:36Z
System.out.println(instant.plus(Duration.ofDays(1))); // 1970-01-03T10:17:36Z
System.out.println(instant.plus(1, ChronoUnit.DAYS)); // 1970-01-03T10:17:36Z

System.out.println(instant); // 1970-01-02T10:17:36Z

These two methods have limitations concerning supported unit types. They accept units that are smaller than days (inclusive).

Instant instant = Instant.ofEpochSecond(123456L);
 
System.out.println(instant.minus(Period.of(123, 12, 3))); // UnsupportedTemporalTypeException
System.out.println(instant.plus(1, ChronoUnit.WEEKS)); // UnsupportedTemporalTypeException
        
System.out.println(instant.plus(Period.ofWeeks(1))); // 1970-01-09T10:17:36Z

Here, all lines except the last one will throw an exception. We won't tell you why: do some research, investigate the code, and feel free to share the answer with other learners.
This class has one more interesting method to calculate the difference between two units. It shows the time until another Instant unit is in the form of the specified unit:

Instant instant = Instant.ofEpochSecond(100200300L);
System.out.println(Instant.EPOCH.until(instant, ChronoUnit.DAYS)); // 1159
System.out.println(Instant.EPOCH.until(instant, ChronoUnit.HOURS)); // 27833

Get operations

Now let's take a look at a group of similar methods performing get operations from an Instant unit. There are three different methods for this purpose, which will show different results depending on how you created the Instant unit. We will consider one case using Instant.ofEpochSecond(), and you can explore the rest of them yourself.

Instant ofEpochSecond = Instant.ofEpochSecond(123456L, 789L);
System.out.println(ofEpochSecond); // 1970-01-02T10:17:36.000000789Z
System.out.println(ofEpochSecond.getEpochSecond()); // 123456

System.out.println(ofEpochSecond.get(ChronoField.MICRO_OF_SECOND)); // 0
System.out.println(ofEpochSecond.get(ChronoField.MILLI_OF_SECOND)); // 0
System.out.println(ofEpochSecond.get(ChronoField.NANO_OF_SECOND)); // 789

System.out.println(ofEpochSecond.getLong(ChronoField.INSTANT_SECONDS)); // 123456
System.out.println(ofEpochSecond.getLong(ChronoField.MICRO_OF_SECOND)); // 0
System.out.println(ofEpochSecond.getLong(ChronoField.MILLI_OF_SECOND)); // 0
System.out.println(ofEpochSecond.getLong(ChronoField.NANO_OF_SECOND)); // 789

The first getEpochSecond() returns a long value storing the unit seconds. The other two perform similarly, but the get() method returns the value of the specified unit as an int, while getLong() returns a long. Since ofEpochSecond() doesn't use milliseconds, get(ChronoField.MICRO_OF_SECOND) and get(ChronoField.MILLI_OF_SECOND) return zero. The same method calls with the same arguments wouldn't return zero if the Instant unit was created using the ofEpochMilli() method.

Note that both the get() and getLong() methods accept only those ChronoField units you can see in the code above. Passing other types will cause an UnsupportedTemporalTypeException.

Instant vs LocalDateTime

Although Instant and LocalDateTime are date-time units, they are completely different in their nature. Instant is a representation of a moment on a timeline relative to an epoch. LocalDateTime is a representation of a calendar date and daytime combination. The first one stores its value in seconds and nanoseconds, while the second one stores it as a pair of LocalDate and LocalTime objects. Finally, LocalDateTime doesn't contain any information regarding a time zone, but if you create its object with the now() method, it will be created depending on your system's default zone. On the other hand, Instant contains that information and shows the GMT0 time-stamp by default in any case.

Instant instant = Instant.now(); // System time zone independent, shows GMT0
LocalDateTime dateTime = LocalDateTime.now(); // System time zone dependent

Conclusion

In this topic dedicated to the Instant class, you learned how to create its units and how those unit values are stored internally. You also learned about some of its operational methods and its main differences from the LocalDateTime class. The functionality of this class is rather straightforward but you should study it in detail as it has plenty of features and it's crucial to understand the behavior of each of them.

Create a free account to access the full topic

“It has all the necessary theory, lots of practice, and projects of different levels. I haven't skipped any of the 3000+ coding exercises.”
Andrei Maftei
Hyperskill Graduate