Instant, Duration and Period in Java
Instant marks a point on the timeline; Duration measures time based amounts and Period measures date based ones.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
Instant
An Instant is a single point on the timeline, counted in seconds and nanoseconds from the epoch of 1 January 1970 UTC. It carries no zone and no calendar, which makes it the correct type for a timestamp.
Instant now = Instant.now();
Instant epoch = Instant.EPOCH;
Instant parsed = Instant.parse("2026-08-21T09:30:00Z");
Instant fromMillis = Instant.ofEpochMilli(1_755_000_000_000L);
System.out.println(now.toEpochMilli());
System.out.println(now.getEpochSecond());
System.out.println(now.isBefore(parsed));Use Instant for anything recorded, compared or stored: created timestamps, audit logs, cache expiry. Convert to a zoned type only when a human has to read it.Duration
A Duration is a time based amount, measured in seconds and nanoseconds. It suits hours, minutes and seconds.
Duration twoHours = Duration.ofHours(2);
Duration ninetySeconds = Duration.ofSeconds(90);
Duration fromText = Duration.parse("PT1H30M"); // ISO 8601 form
System.out.println(twoHours.toMinutes()); // 120
System.out.println(ninetySeconds.toSecondsPart()); // 30
System.out.println(twoHours.plusMinutes(30)); // PT2H30M
Duration between = Duration.between(
LocalTime.of(9, 0), LocalTime.of(17, 30)); // PT8H30MPeriod
A Period is a date based amount, measured in years, months and days. It respects the calendar, so a month is a real month rather than 30 days.
Period oneMonth = Period.ofMonths(1);
Period mixed = Period.of(1, 2, 15); // 1 year, 2 months, 15 days
Period parsed = Period.parse("P1Y2M15D");
Period age = Period.between(LocalDate.of(1998, 3, 12), LocalDate.now());
System.out.printf("%d years, %d months, %d days%n",
age.getYears(), age.getMonths(), age.getDays());Duration compared with Period
Duration | Period | |
|---|---|---|
| Measures | Seconds and nanoseconds | Years, months, days |
| Works with | Instant, LocalTime, LocalDateTime | LocalDate |
| Calendar aware | No | Yes |
| A day means | Exactly 86400 seconds | One calendar day |
ZonedDateTime before = ZonedDateTime.of(
LocalDateTime.of(2026, 3, 28, 12, 0), ZoneId.of("Europe/London"));
ZonedDateTime plusDuration = before.plus(Duration.ofDays(1)); // exactly 24 hours
ZonedDateTime plusPeriod = before.plus(Period.ofDays(1)); // the same clock timeAcross a daylight saving change these give different answers. Duration adds 24 hours of elapsed time; Period adds one calendar day and keeps the local time. Choosing wrongly produces bugs that appear twice a year.
ChronoUnit for a single number
LocalDate start = LocalDate.of(2026, 1, 1);
LocalDate end = LocalDate.of(2026, 8, 21);
System.out.println(ChronoUnit.DAYS.between(start, end)); // 232
System.out.println(ChronoUnit.MONTHS.between(start, end)); // 7
System.out.println(ChronoUnit.WEEKS.between(start, end)); // 33
Instant from = Instant.now();
Instant to = from.plusSeconds(3725);
System.out.println(ChronoUnit.MINUTES.between(from, to)); // 62Use Period when you want the parts broken down, and ChronoUnit when you want one total.
Measuring elapsed time
Instant start = Instant.now();
doWork();
Duration taken = Duration.between(start, Instant.now());
System.out.println("Took " + taken.toMillis() + " ms");// For precise measurement, prefer the monotonic clock
long start = System.nanoTime();
doWork();
long tookMs = (System.nanoTime() - start) / 1_000_000;Instant.now() reads the wall clock, which can jump if the system time is adjusted. System.nanoTime() is monotonic and is the right tool for measuring elapsed time.
Converting between types
Instant instant = Instant.now();
ZonedDateTime zoned = instant.atZone(ZoneId.of("Asia/Kolkata"));
LocalDateTime local = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
LocalDate date = instant.atZone(ZoneId.systemDefault()).toLocalDate();
Instant back = local.atZone(ZoneId.systemDefault()).toInstant();
Instant fromDate = date.atStartOfDay(ZoneId.systemDefault()).toInstant();An Instant needs a zone to become a local date or time, and a local value needs a zone to become an Instant. That requirement is deliberate: it forces the ambiguity to be resolved explicitly.
A practical example
public record CacheEntry<T>(T value, Instant storedAt, Duration timeToLive) {
public boolean isExpired(Instant now) {
return now.isAfter(storedAt.plus(timeToLive));
}
public Duration remaining(Instant now) {
Duration left = Duration.between(now, storedAt.plus(timeToLive));
return left.isNegative() ? Duration.ZERO : left;
}
}Common mistakes
- Using
Duration.ofDays(30)where a calendar month was meant. - Measuring elapsed time with
System.currentTimeMillis(), which is not monotonic. - Expecting
Period.betweento give a total number of days; it gives years, months and days. - Storing a
LocalDateTimeas a timestamp and losing the zone information. - Adding a
Durationacross a daylight saving boundary and getting an unexpected local time.
Best practices
- Store and compare timestamps as
Instantor UTC. - Use
Durationfor hours and below,Periodfor days and above. - Use
ChronoUnitwhen a single total is wanted. - Use
System.nanoTime()for measuring, never the wall clock. - Be explicit about the zone whenever converting.
Practice
- Compute someone age in years, months and days from a birth date.
- Explain when
Duration.ofDays(1)andPeriod.ofDays(1)give different results. - Write a cache entry type that expires after a configurable duration.
- Why is
System.nanoTime()preferred overInstant.now()for timing a method? - Convert an
Instantto aLocalDatein a named zone and explain why the zone is required.
Conclusion
Instant marks when something happened, Duration measures elapsed time, and Period measures calendar amounts. Pick by whether the calendar matters, and be explicit about zones at every conversion.