Advanced Work with Dates and Time in Java: From LocalDate to Complex Manipulations
In modern Java (starting from version 8), the de facto standard for working with dates and time is the java.time package. It replaced the outdated java.util.Date and java.util.Calendar, offering immutable objects, thread safety, and an intuitive API. In this article, we will cover advanced techniques: working with time zones, precise difference calculations, custom adjusters, and complex formatting.
1. Date Manipulations with TemporalAdjusters
One of the most powerful features of java.time is the TemporalAdjuster interface. It allows you to perform complex date adjustments — for example, finding "next Tuesday" or "the last day of the month".
The TemporalAdjusters class (note the plural) contains ready-made static methods:
firstDayOfMonth()— the first day of the month;lastDayOfMonth()— the last day of the month;next(DayOfWeek.FRIDAY)— the next specified day of the week;previousOrSame(DayOfWeek.MONDAY)— the previous or current Monday.
Example: let's find the date of the next Wednesday after March 15, 2024.
import java.time.LocalDate;import java.time.DayOfWeek;import java.time.temporal.TemporalAdjusters;
public class TemporalExample { public static void main(String[] args) { LocalDate date = LocalDate.of(2024, 3, 15); LocalDate nextWednesday = date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY)); System.out.println("Next Wednesday: " + nextWednesday); // Output: 2024-03-20 }}You can also create your own adjusters by implementing the functional interface TemporalAdjuster. This is especially useful for business logic: "the first working day of the month" or "the last Friday of the quarter".
2. Working with Time Zones and ZonedDateTime
Global applications must account for time zones. The ZonedDateTime class combines date, time, and zone (ZoneId).
Example: converting time from New York to Berlin, accounting for daylight saving time.
import java.time.ZonedDateTime;import java.time.ZoneId;import java.time.format.DateTimeFormatter;
public class ZoneExample { public static void main(String[] args) { ZonedDateTime newYork = ZonedDateTime.now(ZoneId.of("America/New_York")); ZonedDateTime berlin = newYork.withZoneSameInstant(ZoneId.of("Europe/Berlin"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm z"); System.out.println("New York: " + newYork.format(formatter)); System.out.println("Berlin: " + berlin.format(formatter)); }}Important: to get all available zones, use ZoneId.getAvailableZoneIds(). Avoid three-letter abbreviations (EST, PST) — they are ambiguous. Always use the continent/city format (e.g., Asia/Tokyo).
3. Precise Difference Calculations: ChronoUnit and Duration
There are two approaches for calculating the difference between dates in Java:
ChronoUnit— for differences in calendar units (days, months, years);Duration— for precise time intervals (seconds, nanoseconds).
Example: how many days and months are left until New Year?
import java.time.LocalDate;import java.time.temporal.ChronoUnit;
public class DiffExample { public static void main(String[] args) { LocalDate today = LocalDate.now(); LocalDate newYear = LocalDate.of(today.getYear() + 1, 1, 1);
long days = ChronoUnit.DAYS.between(today, new