Java Date & Time
Java - Date & Time
Section titled “Java - Date & Time”Handling dates and times is a common requirement in many applications. Java provides powerful APIs for this, but it’s important to use the modern API introduced in Java 8.
The Modern Date/Time API (java.time)
Section titled “The Modern Date/Time API (java.time)”Introduced in Java 8, the java.time package provides a comprehensive, immutable, and much-improved API for handling dates, times, time zones, durations, and periods. This is the recommended API for all new development.
Why java.time?
Section titled “Why java.time?”- Immutability: Objects in
java.time(likeLocalDate,LocalTime) are immutable, meaning their state cannot be changed after creation. This makes them inherently thread-safe and easier to reason about. - Clarity: Clear separation between concepts like date, time, date-time, timestamp, duration, period, and time zones.
- Fluent API: Methods are designed for clear and readable chaining (e.g.,
dateTime.plusDays(5).minusHours(2)). - Better Time Zone Handling: Robust support for time zones (
ZoneId,ZonedDateTime). - ISO 8601 Standard: Based on the ISO standard for date and time representation.
Core Classes in java.time:
Section titled “Core Classes in java.time:”LocalDate: Represents a date without time or time zone (e.g., 2023-10-27).LocalTime: Represents a time without date or time zone (e.g., 14:30:55.123).LocalDateTime: Represents both date and time, without a time zone (e.g., 2023-10-27T14:30:55).ZonedDateTime: Represents a date and time with a specific time zone (e.g., 2023-10-27T14:30:55+01:00[Europe/London]).Instant: Represents a specific point on the timeline (nanosecond precision), typically relative to the UTC epoch (January 1, 1970). Useful for timestamps.Duration: Represents a time-based amount of time (seconds, nanoseconds). Useful for measuring machine time (e.g., difference between twoInstants).Period: Represents a date-based amount of time (years, months, days). Useful for human-readable time differences (e.g., age).DateTimeFormatter: Used for formatting date/time objects into strings and parsing strings into date/time objects.ZoneId: Represents a time zone identifier (e.g.,Europe/Paris,Asia/Tokyo).ZoneOffset: Represents a fixed offset from UTC (e.g.,+02:00).
Getting Current Date and Time
Section titled “Getting Current Date and Time”Use the static now() methods:
import java.time.*;
public class CurrentDateTime { public static void main(String[] args) { LocalDate today = LocalDate.now(); System.out.println("Today's Date: " + today); // e.g., 2023-10-27
LocalTime currentTime = LocalTime.now(); System.out.println("Current Time: " + currentTime); // e.g., 10:15:30.123456789
LocalDateTime currentDateTime = LocalDateTime.now(); System.out.println("Current Date and Time: " + currentDateTime);
// Get current time in a specific time zone ZoneId londonZone = ZoneId.of("Europe/London"); ZonedDateTime londonTime = ZonedDateTime.now(londonZone); System.out.println("Current London Time: " + londonTime);
Instant timestamp = Instant.now(); System.out.println("Current Instant (UTC): " + timestamp); }}Creating Specific Dates and Times
Section titled “Creating Specific Dates and Times”Use the static of() factory methods:
import java.time.*;
public class SpecificDateTime { public static void main(String[] args) { LocalDate specificDate = LocalDate.of(2024, Month.JANUARY, 15); // Year, Month, Day System.out.println("Specific Date: " + specificDate);
LocalDate dateFromYMD = LocalDate.of(2024, 1, 15); // Year, Month (1-12), Day System.out.println("Date from YMD: " + dateFromYMD);
LocalTime specificTime = LocalTime.of(18, 30, 0); // Hour, Minute, Second System.out.println("Specific Time: " + specificTime);
LocalDateTime specificDateTime = LocalDateTime.of(2024, 1, 15, 18, 30); System.out.println("Specific DateTime: " + specificDateTime);
ZoneId newYorkZone = ZoneId.of("America/New_York"); ZonedDateTime newYorkMeeting = ZonedDateTime.of(specificDateTime, newYorkZone); System.out.println("New York Meeting: " + newYorkMeeting); }}Formatting and Parsing
Section titled “Formatting and Parsing”DateTimeFormatter is used to convert date/time objects to strings (formatting) and strings back to date/time objects (parsing).
Using Predefined Formatters:
Section titled “Using Predefined Formatters:”import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.time.format.FormatStyle;
public class PredefinedFormatting { public static void main(String[] args) { LocalDateTime now = LocalDateTime.now();
// Predefined ISO formats (default for toString()) System.out.println("ISO DATE TIME: " + now.format(DateTimeFormatter.ISO_DATE_TIME)); System.out.println("ISO DATE: " + now.format(DateTimeFormatter.ISO_DATE));
// Locale-specific formats DateTimeFormatter shortFormat = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); DateTimeFormatter mediumFormat = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
System.out.println("Short format: " + now.format(shortFormat)); // e.g., 10/27/23, 11:30 AM (US locale) System.out.println("Medium format: " + now.format(mediumFormat)); // e.g., Oct 27, 2023, 11:30:00 AM }}Using Custom Patterns:
Section titled “Using Custom Patterns:”import java.time.LocalDate;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.time.format.DateTimeParseException;
public class CustomFormattingParsing { public static void main(String[] args) { LocalDateTime now = LocalDateTime.now();
// Define a custom pattern DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy 'at' hh:mm a");
// Formatting String formattedString = now.format(customFormatter); System.out.println("Custom format: " + formattedString); // e.g., Friday, October 27, 2023 at 11:35 AM
// Parsing String dateString = "Monday, June 05, 2023 at 02:30 PM"; try { LocalDateTime parsedDateTime = LocalDateTime.parse(dateString, customFormatter); System.out.println("Parsed DateTime: " + parsedDateTime); } catch (DateTimeParseException e) { System.err.println("Error parsing date string: " + e.getMessage()); }
// Parsing simpler format String simpleDate = "2023-01-20"; try { // ISO_DATE formatter is suitable here LocalDate parsedDate = LocalDate.parse(simpleDate, DateTimeFormatter.ISO_DATE); System.out.println("Parsed simple date: " + parsedDate); } catch (DateTimeParseException e) { System.err.println("Error parsing simple date: " + e.getMessage()); } }}Common Pattern Letters:
Section titled “Common Pattern Letters:”| Letter | Component | Examples |
|---|---|---|
y | Year | yy (03), yyyy (2003) |
M | Month | M (7), MM (07), MMM (Jul), MMMM (July) |
d | Day of month | d (5), dd (05) |
E | Day of week | E/EE/EEE (Tue), EEEE (Tuesday) |
H | Hour (0-23) | H (9), HH (09) |
h | Hour (1-12) | h (9), hh (09) |
m | Minute | m (5), mm (05) |
s | Second | s (8), ss (08) |
a | AM/PM marker | a (AM/PM) |
z | Time zone name | z (PDT) |
Z / O / X | Time zone offset | Z (+0100), O (GMT+1), X / XX / XXX (-08 / -0800 / -08:00) |
' | Escape for text | 'Date:' yyyy |
Date/Time Manipulation
Section titled “Date/Time Manipulation”Since java.time objects are immutable, manipulation methods return a new object with the modified value.
import java.time.*;
public class DateTimeManipulation { public static void main(String[] args) { LocalDateTime meetingTime = LocalDateTime.of(2023, 11, 10, 14, 0); // Nov 10, 2023, 2 PM System.out.println("Original Meeting Time: " + meetingTime);
// Add/Subtract time LocalDateTime rescheduledTime = meetingTime.plusDays(3).minusHours(1); System.out.println("Rescheduled Time: " + rescheduledTime); // Nov 13, 2023, 1 PM
LocalDate today = LocalDate.now(); LocalDate nextWeek = today.plusWeeks(1); System.out.println("Next Week: " + nextWeek);
// Get parts of date/time int year = meetingTime.getYear(); // 2023 Month month = meetingTime.getMonth(); // NOVEMBER int day = meetingTime.getDayOfMonth(); // 10 DayOfWeek dayOfWeek = meetingTime.getDayOfWeek(); // FRIDAY int hour = meetingTime.getHour(); // 14
System.out.println("Meeting details: " + dayOfWeek + ", " + month + " " + day + ", " + year);
// Modify specific fields using 'with' LocalDateTime startOfDay = meetingTime.withHour(9).withMinute(0).withSecond(0); System.out.println("Start of Business Day: " + startOfDay); }}Periods and Durations
Section titled “Periods and Durations”Period for date-based differences, Duration for time-based differences.
import java.time.*;
public class PeriodDurationExample { public static void main(String[] args) { // Period (Years, Months, Days) LocalDate startDate = LocalDate.of(2023, 5, 15); LocalDate endDate = LocalDate.of(2024, 7, 20); Period periodBetween = Period.between(startDate, endDate); System.out.println("Period: " + periodBetween); // P1Y2M5D (1 year, 2 months, 5 days) System.out.printf("Difference: %d years, %d months, %d days%n", periodBetween.getYears(), periodBetween.getMonths(), periodBetween.getDays());
Period twoWeeks = Period.ofWeeks(2); LocalDate futureDate = startDate.plus(twoWeeks); System.out.println("Two weeks later: " + futureDate);
// Duration (Days, Hours, Minutes, Seconds, Nanos) Instant startInstant = Instant.now(); // Simulate some work try { Thread.sleep(1500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Instant endInstant = Instant.now(); Duration timeElapsed = Duration.between(startInstant, endInstant); System.out.println("\nTime Elapsed (Duration): " + timeElapsed); // e.g., PT1.500123456S System.out.println("Time Elapsed (Millis): " + timeElapsed.toMillis());
Duration twoHours = Duration.ofHours(2); LocalTime deadline = LocalTime.of(15, 0).plus(twoHours); System.out.println("Deadline Time: " + deadline); }}Measuring Elapsed Time
Section titled “Measuring Elapsed Time”Use Instant and Duration for precise time measurement.
import java.time.Duration;import java.time.Instant;
public class MeasureTime { public static void main(String[] args) { Instant start = Instant.now(); System.out.println("Starting operation at: " + start);
// Simulate a task try { Thread.sleep(2000); // Sleep for 2 seconds } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println("Sleep interrupted"); }
Instant end = Instant.now(); System.out.println("Finished operation at: " + end);
Duration duration = Duration.between(start, end); System.out.println("Duration: " + duration); // e.g., PT2.001S System.out.println("Duration in milliseconds: " + duration.toMillis()); }}Legacy Date/Time API (java.util.Date, Calendar)
Section titled “Legacy Date/Time API (java.util.Date, Calendar)”Before Java 8, developers used java.util.Date and java.util.Calendar (often java.util.GregorianCalendar). These classes have several drawbacks:
- Mutability:
Dateobjects are mutable, leading to potential bugs in concurrent environments or when passed around. - Confusing API:
Daterepresents an instant, but itstoString()includes date/time components based on the default time zone. Month indexing inDateandCalendarwas 0-based (January=0), a common source of errors. - Poor Separation:
Datemixes the concept of an instant with date/time fields. - Limited Time Zone Support:
Calendar’s time zone handling was cumbersome.
Avoid using java.util.Date and java.util.Calendar in new code. If you need to interact with older APIs that use them, convert between the legacy and modern APIs:
import java.time.*;import java.util.Date;import java.util.Calendar;import java.util.GregorianCalendar;
public class LegacyConversion { public static void main(String[] args) { // Legacy Date to Instant Date legacyDate = new Date(); Instant instantFromDate = legacyDate.toInstant(); ZonedDateTime zdtFromDate = instantFromDate.atZone(ZoneId.systemDefault()); System.out.println("From legacy Date: " + zdtFromDate);
// Instant to Legacy Date Instant nowInstant = Instant.now(); Date dateFromInstant = Date.from(nowInstant); System.out.println("To legacy Date: " + dateFromInstant);
// Legacy Calendar to ZonedDateTime Calendar legacyCalendar = new GregorianCalendar(); // Represents current time ZonedDateTime zdtFromCalendar = ((GregorianCalendar) legacyCalendar).toZonedDateTime(); System.out.println("From legacy Calendar: " + zdtFromCalendar);
// ZonedDateTime to Legacy Calendar ZonedDateTime currentZdt = ZonedDateTime.now(); GregorianCalendar calendarFromZdt = GregorianCalendar.from(currentZdt); System.out.println("To legacy Calendar (month is 0-based): " + calendarFromZdt.get(Calendar.MONTH)); }}What’s Next?
Section titled “What’s Next?”Mastering the java.time API is essential for modern Java development. Next, we’ll look at another common data manipulation task: working with sequences of characters using the String class and related concepts like Regular Expressions.