1. Introduction
Java 8 introduced, through JSR 310, a complete overhaul of the Date/Time API by providing new, more advanced classes for Date processing. ZonedDateTime is one such class that we will focus on in this article.
2. What is a ZonedDateTime?
ZonedDateTime is a class from the java.time
package. The class represents both a date and a time, in terms of date and time fields (year, month, day, hour, minute, second, nanosecond), plus the timezone information. For example, the value “2024-05-06T22:52:15.962090600+02:00[Europe/Paris]” can be stored in a ZonedDateTime.
The LocalDateTime is covered in a separate article.
The main particularity of ZonedDateTime is that it is immutable and thread-safe.
3. Creating a ZonedDateTime
There are two main ways of creating a ZonedDateTime in Java. The first way is by using the ZonedDateTime.now()
methods and the second way is with the ZonedDateTime.of()
methods.
3.1. Using ZonedDateTime.now()
Methods
You can create a ZonedDateTime object with the current date and time in this way:
ZonedDateTime now = ZonedDateTime.now();//2024-05-05T14:05:46.113681500+02:00[Europe/Paris]
This will query the system clock in the default timezone.
Optionally, you can provide a custom Clock to the now()
method:
Clock clock = Clock.systemDefaultZone();
ZonedDateTime now = ZonedDateTime.now(clock);
It is a best practice to pass a Clock into any method that requires the current instant. This has the advantage of making your code more testable.
Furthermore, if you need to construct a zone date object for a specific TimeZone, you can pass a ZoneId object to the now()
method:
ZoneId zoneId = ZoneId.of("America/Toronto");
ZonedDateTime now = ZonedDateTime.now(zoneId);
3.2. Using ZonedDateTime.of()
Methods
You can also create a ZonedDateTime object by providing values for the year, month, day, hour, minute, second, nanosecond, and zoneId fields:
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime zonedDateTime = ZonedDateTime.of(2024,5,1,13,30,10,5,zoneId);//2024-05-01T13:30:10.000000005+02:00[Europe/Paris]
Alternatively, you can send a LocalDate
, a LocalTime
, and a ZoneId
objects to the ZonedDateTime.of()
method:
LocalDate date = LocalDate.of(2024,5,1);
LocalTime time = LocalTime.of(13,30,10,5);
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime zonedDateTime = ZonedDateTime.of(date,time,zoneId);//2024-05-01T13:30:10.000000005+02:00[Europe/Paris]
Lastly, the ZonedDateTime.of()
can take a LocalDateTime
and a ZoneId
objects:
LocalDateTime dateTime = LocalDateTime.of(2024,5,1,13,30,10,5);
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime,zoneId);//2024-05-01T13:30:10.000000005+02:00[Europe/Paris]
All these factory methods will throw a DateTimeException if the value of any field is out of range, or if the day-of-month is invalid for the month-year.
4. Formatting a ZonedDateTime
By default, the ZonedDateTime is formatted using the ISO-8601 date format. You can use a different format by passing a DateTimeFormatter object to the format()
method:
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime zonedDateTime = ZonedDateTime.of(2024,5,1,13,30,10,5,zoneId);//2024-05-01T13:30:10.000000005+02:00[Europe/Paris]
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a XXX'['VV']'");
String formattedZonedDateTime = zonedDateTime.format(formatter);// 01/05/2024 01:30 PM +02:00[Europe/Paris]
Refer to the Official DateTimeFormatter Javadoc to find out about the different formatting options.
5. Parsing from String to ZonedDateTime
Assuming that you have a zoned datetime in ISO-8601 date format and want to build a ZonedDateTime out of it, you can use the parse()
method in this way:
String myZonedDateTime = "2024-05-01T13:30:10.000000005+02:00[Europe/Paris]";// ISO-8601 date format
ZonedDateTime zonedDateTime = ZonedDateTime.parse(myZonedDateTime);// 2024-05-01T13:30:10.000000005+02:00[Europe/Paris]
Moreover, if the zoned datetime is in a different format, you can pass a custom DateTimeFormatter to the parse()
method:
String myDateTime = "01/05/2024 01:30 PM +02:00[Europe/Paris]";//Custom format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm a XXX'['VV']'");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(myDateTime, formatter);// 2024-05-01T13:30+02:00[Europe/Paris]
Java will throw a DateTimeParseException if it is not able to parse the String with the given datetime format.
6. Operating on a ZonedDateTime
6.1. Comparing two ZonedDateTime objects
You can use isAfter()
, isBefore()
, and isEqual
methods to compare two ZonedDateTime objects:
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime firstZonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);
ZonedDateTime secondZonedDateTime = ZonedDateTime.of(2024,5,1,13,27,0,0,zoneId);
ZonedDateTime thirdZonedDateTime = ZonedDateTime.of(2024,5,1,13,33,0,0,zoneId);
ZonedDateTime fourthZonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);
boolean test1 = firstZonedDateTime.isAfter(secondZonedDateTime);//true
boolean test2 = firstZonedDateTime.isBefore(thirdZonedDateTime);//true
boolean test3 = firstZonedDateTime.isEqual(fourthZonedDateTime);//true
Since the ZonedDateTime class implements the Comparable<E>
interface, you may also use the compareTo()
method:
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime firstZonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);
ZonedDateTime secondZonedDateTime = ZonedDateTime.of(2024,5,1,13,27,0,0,zoneId);
ZonedDateTime thirdZonedDateTime = ZonedDateTime.of(2024,5,1,13,33,0,0,zoneId);
int test1 = firstZonedDateTime.compareTo(secondZonedDateTime);//A positive number
int test2 = firstZonedDateTime.compareTo(thirdZonedDateTime);//A negative number
Lastly, you should know that the ZonedDateTime class also overrides the equals()
method and provides a convenient way to check the equality of two dates:
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime firstZonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);
ZonedDateTime secondZonedDateTime = ZonedDateTime.of(2024,5,1,13,27,0,0,zoneId);
ZonedDateTime thirdZonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);
boolean test1 = firstZonedDateTime.equals(secondZonedDateTime);// false
boolean test2 = firstZonedDateTime.equals(thirdZonedDateTime);// true
6.2. Temporal Arithmetic with ZonedDateTime objects
The ZonedDateTime class provides plusXXX()
and minusXXX()
methods to increment and decrement the object field values. Since the ZonedDateTime is immutable, all these methods return a copy of the original object with the given fields updated.
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZonedDateTime zonedDateTime = ZonedDateTime.of(2024,5,1,13,30,0,0,zoneId);// 2024-05-01T13:30+02:00[Europe/Paris]
ZonedDateTime nextYear = zonedDateTime.plusYears(1);//2025-05-01T13:30+02:00[Europe/Paris]
ZonedDateTime previousYear = zonedDateTime.minusYears(1);//2023-05-01T13:30+02:00[Europe/Paris]
ZonedDateTime nextMonth = zonedDateTime.plusMonths(1);//2024-06-01T13:30+02:00[Europe/Paris]
ZonedDateTime previousMonth = zonedDateTime.minusMonths(1);//2024-04-01T13:30+02:00[Europe/Paris]
ZonedDateTime nextDay = zonedDateTime.plusDays(1);//2024-05-02T13:30+02:00[Europe/Paris]
ZonedDateTime previousDay = zonedDateTime.minusDays(1);//2024-04-30T13:30+02:00[Europe/Paris]
ZonedDateTime nextHour = zonedDateTime.plusHours(1);//2024-05-01T14:30+02:00[Europe/Paris]
ZonedDateTime previousHour = zonedDateTime.minusHours(1);//2024-05-01T12:30+02:00[Europe/Paris]
ZonedDateTime nextMinute = zonedDateTime.plusMinutes(1);//2024-05-01T13:31+02:00[Europe/Paris]
ZonedDateTime previousMinute = zonedDateTime.minusMinutes(1);//2024-05-01T13:29+02:00[Europe/Paris]
7. Conclusion
In this tutorial, you learned about the ZonedDateTime class in Java.
8. References
1) OCP Oracle Certified Professional Java SE 17 by Khalil A. Mughal and Vasily A. Strelnikov
2) Oracle Java Documentation
Pingback: OffsetDateTime Class in Java