Period and Duration Classes in Java
The Period
class representing a date-based unit and the Duration
class representing a time-based unit. Both of them belong to the java.time
package. This guide covers how you can create its instances in various ways using static methods. You will also learn about some important methods allowing us to perform operations with these classes.
Creating Period units
The Period
class represents a period of time in terms of years, months, and days. If the unit includes all metrics, its unit format is P{year}Y{month}M{day}D
, where {year}
, {month}
, and {day}
are placeholders for values. Let's take a look at a few methods for creating Period
units:
- The first and probably the most common way of creating
Period
units is by using theof()
static method.
Period period = Period.of(1995, 5, 23);
System.out.println(period); // P1995Y5M23D
- The next method allows us to get a
Period
unit in the form of a difference between two dates:
LocalDate startDate = LocalDate.of(1995, 5, 23);
LocalDate endDate = LocalDate.of(1995 , 8, 25);
Period period = Period.between(startDate, endDate);
System.out.println(period); // P3M2D
It will show negative values if the second argument is smaller, zero if they are equal, and a positive value if the second argument is larger.
- Another method accepts a text and parses it to a
Period
type.
// 23 days
System.out.println(Period.parse("P23D")); // P23D
// 5 months 23 days
System.out.println(Period.parse("P5M23D")); // P5M23D
// -1995 years 5 months 23 days
System.out.println(Period.parse("P-1995Y5M23D")); // P-1995Y5M23D
The same logic works for negative values. Here is a code snippet which showcases a pattern you can use to mention that values are negative:
// -23 days
System.out.println(Period.parse("P-23D")); // P-23D
// -5 months -23 days
System.out.println(Period.parse("P-5M-23D")); // P-5M-23D
// -1995 years -5 months -23 days
System.out.println(Period.parse("P-1995Y-5M-23D")); // P-1995Y-5M-23D
// -1995 years -5 months -23 days
System.out.println(Period.parse("-P1995Y5M23D")); // P-1995Y-5M-23D
Extracting Period units
Normally, if you print a full date of the Period
type, it will look like the patterns we showed in the previous sections. This class also provides us with some methods that are helpful when you want to extract a single date unit from a full date.
Period period = Period.of(1995, 5, 23);
System.out.println(period.getYears()); // 1995
System.out.println(period.getMonths()); // 5
System.out.println(period.getDays()); // 23
Another method that performs the same operation is the get()
method. If you have the same instance-level period
variable from the previous section, your code will look like this:
public static void main(String[] args) {
Period period = Period.of(1995, 5, 23);
System.out.println(period.get(ChronoUnit.YEARS)); // 1995
System.out.println(period.get(ChronoUnit.MONTHS)); // 5
System.out.println(period.get(ChronoUnit.DAYS)); // 23
}
Note that ChronoUnit
has fields for other units too, but the scope of this method only allows using the three fields mentioned above. If you use a unit such as ChronoUnit.WEEKS
or any other, you will face an UnsupportedTemporalTypeException
.
Operating with Period units
Now let's explore two pairs of methods designed for adding and subtracting date-based units, namely:
addTo()
andsubtractFrom()
plus()
andminus()
These pairs of methods perform similar operations but behave differently. The code samples below show the difference. Let's start with the first pair, addTo()
and subtractFrom()
:
Period period = Period.of(1, 1, 1);
System.out.println(period.addTo(LocalDate.of(1995, 5, 23))); // 1996-06-24
System.out.println(period.subtractFrom(LocalDate.of(1995, 5, 23))); // 1994-04-22
System.out.println(period); // P1Y1M1D
This means that the methods aren't designed to work with two Period
units. With their help, you will add or subtract a period to/from a Temporal
variable which is a base interface of several classes including LocalDate
, LocalDateTime
, ZonedDateTime
, and so on.
On the other hand, the second pair plus()
and minus()
, is designed to operate with two Period
type variables.
Period period = Period.of(1, 1, 1);
System.out.println(period.plus(Period.of(1995, 5, 23))); // P1996Y6M24D
System.out.println(period.minus(Period.of(1995, 5, 23))); // P-1994Y-4M-22D
System.out.println(period); // P1Y1M1D
As you can see, we have a completely different result when subtracting. The subtractFrom()
method subtracts a period
variable from a LocalDate
while the minus()
subtracts the second Period
unit from the first one.
Creating Duration units
Java Duration
represents a period of time storing the value in seconds and nanoseconds. Its structure has a lot in common with the Period
class. They have similar methods that have similar roles. Units of this class are created in the same way as the units of Period
and have a similar unit format; that is PT{hour}H{minute}M{second}S
, when the unit includes all metrics. We will consider the same four methods used when creating Period
units. First of all, let's explore the of()
method.
Duration durationOf = Duration.of(3, ChronoUnit.DAYS);
Duration durationOf1 = Duration.of(3, ChronoUnit.MINUTES);
Duration durationOf2 = Duration.of(3, ChronoUnit.NANOS);
System.out.println(durationOf); // PT72H
System.out.println(durationOf1); // PT3M
System.out.println(durationOf2); // PT0.000000003S
Here this method has a slightly different behavior. It accepts two arguments specifying the amount and the time unit. The first parameter doesn't need an explanation, but you should be aware of an important limitation regarding the second one. Although ChronoUnit
provides us with many units of time, here we can only use accurate units and days, which are counted as 24 hours (although the actual duration of a day is a bit longer). All unsupported units will cause an UnsupportedTemporalTypeException
. The other two methods behave no differently from the same methods of the Period
class. Here you see the between()
method:
LocalTime startTime = LocalTime.of(11, 45, 30);
LocalTime endTime = LocalTime.of(12, 50, 30);
System.out.println(Duration.between(startTime, endTime)); // PT1H5M
The parse()
method also performs in the same way:
Duration duration1 = Duration.parse("PT1H20M");
Duration duration2 = Duration.parse("PT30M");
System.out.println(duration1); // PT1H20M
System.out.println(duration2); // PT30M
Extracting Duration units
Unlike the Period
class, there are fewer methods here to extract the desired unit from a Duration
instance:
System.out.println(Duration.of(1, ChronoUnit.DAYS).getSeconds()); // 86400
System.out.println(Duration.of(1, ChronoUnit.HOURS).getSeconds()); // 3600
System.out.println(Duration.of(90, ChronoUnit.MINUTES).getSeconds()); // 5400
System.out.println(Duration.of(90, ChronoUnit.SECONDS).getSeconds()); // 90
System.out.println(Duration.of(90, ChronoUnit.SECONDS).getNano()); // 0
System.out.println(Duration.of(90, ChronoUnit.NANOS).getNano()); // 90
It has two methods operating on specified units: getSeconds()
and getNano()
, each returning its component in a unit. So, if the unit contains both seconds and nanoseconds, getSeconds()
will return only seconds and the second one will return only nanoseconds.
Duration duration = Duration.ofSeconds(3675, 75);
System.out.println(duration); // PT1H1M15.000000075S
System.out.println(duration.getSeconds()); // 3675
System.out.println(duration.getNano()); // 75
Also, you can use the get()
method if you don't want to specify the unit explicitly but pass the required unit as an argument when calling it:
Duration duration = Duration.of(10, ChronoUnit.MINUTES);
System.out.println(duration.get(ChronoUnit.SECONDS)); // 600
Like the similar method from the Period
class, it will throw an exception if you pass an unsupported unit.
Operating with Duration units
The Duration
class provides the same methods for adding and subtracting its units.
Duration duration = Duration.of(90, ChronoUnit.MINUTES);
System.out.println(duration.addTo(LocalTime.of(19, 5, 23))); // 20:35:23
System.out.println(duration.subtractFrom(LocalTime.of(19, 5, 23))); // 17:35:23
System.out.println(duration); // PT1H30M
If you take a closer look at the two code samples in this section and their results, you will see that the methods operate similarly to their Period
equivalents.
Duration duration = Duration.of(90, ChronoUnit.MINUTES);
System.out.println(duration.plus(Duration.of(10, ChronoUnit.MINUTES))); // PT1H40M
System.out.println(duration.minus(Duration.of(10, ChronoUnit.MINUTES))); // PT1H20M
System.out.println(duration); // PT1H30M
Conclusion
The Period
and Duration
classes in the java.time
package are powerful tools for working with date-based and time-based units in Java programming. Both classes offer methods for extracting individual units and performing operations like addition and subtraction, but with different priority: Period
handles years, months and days, while Duration
is used for hours, minutes, seconds and nanoseconds.