Java Notes
Complete guide to java.time package — LocalDate, LocalTime, LocalDateTime, ZonedDateTime, Duration, Period, formatting, parsing, and migration from legacy Date/Calendar.
Why a New Date/Time API?
The old java.util.Date and java.util.Calendar classes were fundamentally broken:
| Problem | Old API | New API (java.time) |
|---|---|---|
| Mutability | Date is mutable (thread-unsafe) | All classes are immutable |
| Month indexing | January = 0 | January = 1 |
| Year | 1900-based | Actual year |
| Timezone handling | Poor | First-class ZonedDateTime |
| Design | Confusing, inconsistent | Clean, fluent, ISO-8601 |
// Old API problems
Date date = new Date(2024, 1, 15); // Actually March 15, 3924!
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 1); // February (0-indexed)!
// Mutable — another thread could change it
// New API — clean and intuitive
LocalDate date = LocalDate.of(2024, 1, 15); // January 15, 2024
LocalDate date2 = LocalDate.of(2024, Month.JANUARY, 15); // Same, more readableLocalTime — Time Without Date
import java.time.LocalTime;
public class LocalTimeDemo {
public static void main(String[] args) {
// Creation
LocalTime now = LocalTime.now();
LocalTime specific = LocalTime.of(14, 30, 0); // 14:30:00
LocalTime withNanos = LocalTime.of(14, 30, 0, 500_000_000); // 14:30:00.5
LocalTime parsed = LocalTime.parse("14:30:00");
LocalTime midnight = LocalTime.MIDNIGHT; // 00:00
LocalTime noon = LocalTime.NOON; // 12:00
LocalTime max = LocalTime.MAX; // 23:59:59.999999999
// Extracting
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
int nano = now.getNano();
// Arithmetic
LocalTime later = now.plusHours(2).plusMinutes(30);
LocalTime earlier = now.minusMinutes(45);
// Comparison
boolean isAfterNoon = now.isAfter(LocalTime.NOON);
// Business hours check
LocalTime openTime = LocalTime.of(9, 0);
LocalTime closeTime = LocalTime.of(17, 0);
boolean isBusinessHours = !now.isBefore(openTime) && now.isBefore(closeTime);
}
}LocalDateTime — Date + Time Without Timezone
import java.time.LocalDateTime;
public class LocalDateTimeDemo {
public static void main(String[] args) {
// Creation
LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2024, 6, 15, 14, 30, 0);
LocalDateTime combined = LocalDateTime.of(LocalDate.now(), LocalTime.of(9, 0));
LocalDateTime parsed = LocalDateTime.parse("2024-06-15T14:30:00");
// Convert between types
LocalDate date = now.toLocalDate();
LocalTime time = now.toLocalTime();
LocalDateTime fromDate = LocalDate.now().atTime(14, 30);
LocalDateTime fromTime = LocalTime.of(14, 30).atDate(LocalDate.now());
// Arithmetic
LocalDateTime meetingEnd = now.plusHours(1).plusMinutes(30);
// Truncation
LocalDateTime startOfDay = now.truncatedTo(ChronoUnit.DAYS);
LocalDateTime startOfHour = now.truncatedTo(ChronoUnit.HOURS);
}
}ZonedDateTime — Full Date/Time with Timezone
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class ZonedDateTimeDemo {
public static void main(String[] args) {
// Creation
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime nyTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime specific = ZonedDateTime.of(2024, 6, 15, 14, 30, 0, 0,
ZoneId.of("Asia/Kolkata"));
// All available zones
Set<String> zones = ZoneId.getAvailableZoneIds(); // ~600 zones
// Convert between timezones
ZonedDateTime ist = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
ZonedDateTime est = ist.withZoneSameInstant(ZoneId.of("America/New_York"));
// Same moment, different clock reading
ZonedDateTime sameLocal = ist.withZoneSameLocal(ZoneId.of("America/New_York"));
// Same clock reading, different moment!
// Handling DST (Daylight Saving Time)
// Spring forward: 2:00 AM -> 3:00 AM (gap)
ZonedDateTime beforeGap = ZonedDateTime.of(2024, 3, 10, 1, 30, 0, 0,
ZoneId.of("America/New_York"));
ZonedDateTime afterGap = beforeGap.plusHours(1);
// 1:30 AM + 1 hour = 3:30 AM (skips 2:00-3:00)
// Instant — machine timestamp (UTC)
Instant instant = Instant.now();
Instant fromEpoch = Instant.ofEpochSecond(1718400000L);
ZonedDateTime fromInstant = instant.atZone(ZoneId.of("Asia/Kolkata"));
// OffsetDateTime — fixed offset (no DST rules)
OffsetDateTime odt = OffsetDateTime.of(2024, 6, 15, 14, 30, 0, 0,
ZoneOffset.ofHoursMinutes(5, 30)); // +05:30
}
}Duration and Period
import java.time.Duration;
import java.time.Period;
public class DurationPeriodDemo {
public static void main(String[] args) {
// Duration — time-based (hours, minutes, seconds, nanos)
Duration twoHours = Duration.ofHours(2);
Duration tenMinutes = Duration.ofMinutes(10);
Duration fiveSeconds = Duration.ofSeconds(5);
Duration complex = Duration.ofHours(2).plusMinutes(30);
Duration parsed = Duration.parse("PT2H30M"); // ISO-8601
// Between two times
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);
Duration workDay = Duration.between(start, end); // PT8H30M
long hours = workDay.toHours(); // 8
long minutes = workDay.toMinutes(); // 510
// Period — date-based (years, months, days)
Period oneMonth = Period.ofMonths(1);
Period twoWeeks = Period.ofWeeks(2); // 14 days
Period complex = Period.of(1, 6, 15); // 1 year, 6 months, 15 days
Period parsed = Period.parse("P1Y6M15D");
// Between two dates
LocalDate birth = LocalDate.of(1990, 5, 20);
LocalDate today = LocalDate.now();
Period age = Period.between(birth, today);
System.out.println(age.getYears() + " years, " + age.getMonths() + " months");
// Using with dates
LocalDate deadline = today.plus(Period.ofWeeks(2));
LocalDateTime meeting = LocalDateTime.now().plus(Duration.ofHours(3));
}
}Formatting and Parsing
import java.time.format.DateTimeFormatter;
public class FormattingDemo {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
// Predefined formatters
String iso = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// 2024-06-15T14:30:00
// Custom patterns
DateTimeFormatter custom = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
String formatted = now.format(custom); // 15/06/2024 14:30:00
DateTimeFormatter readable = DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy");
String humanReadable = now.format(readable); // Saturday, June 15, 2024
DateTimeFormatter withLocale = DateTimeFormatter
.ofPattern("dd MMMM yyyy", Locale.FRENCH);
String french = now.format(withLocale); // 15 juin 2024
// Parsing
LocalDate date = LocalDate.parse("15/06/2024",
DateTimeFormatter.ofPattern("dd/MM/yyyy"));
LocalDateTime dateTime = LocalDateTime.parse("2024-06-15 14:30:00",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// Pattern letters:
// y=year, M=month, d=day, H=hour(24), h=hour(12)
// m=minute, s=second, a=AM/PM, E=day of week
// MMMM=full month name, MMM=short, MM=number
}
}Migration from Legacy API
// Date <-> Instant <-> LocalDateTime
Date legacyDate = new Date();
Instant instant = legacyDate.toInstant();
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
// Back to Date
Date backToDate = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
// Calendar <-> ZonedDateTime
Calendar calendar = Calendar.getInstance();
ZonedDateTime zdt = ZonedDateTime.ofInstant(calendar.toInstant(),
calendar.getTimeZone().toZoneId());
// java.sql.Date <-> LocalDate
java.sql.Date sqlDate = java.sql.Date.valueOf(LocalDate.now());
LocalDate localDate = sqlDate.toLocalDate();
// java.sql.Timestamp <-> LocalDateTime
java.sql.Timestamp timestamp = java.sql.Timestamp.valueOf(LocalDateTime.now());
LocalDateTime fromTimestamp = timestamp.toLocalDateTime();Real-World Examples
Interview Questions
Q1: Why is the new Date/Time API better than Date and Calendar?
Answer: Immutability (thread-safe), proper month indexing (1-12), separation of concerns (LocalDate vs LocalTime vs ZonedDateTime), fluent API, built-in timezone support, and ISO-8601 compliance.
Q2: What is the difference between LocalDateTime and ZonedDateTime?
Answer: LocalDateTime has no timezone info — it represents a date-time on a wall clock. ZonedDateTime includes timezone rules and can handle DST transitions. Use LocalDateTime for local events, ZonedDateTime for global timestamps.
Q3: What is the difference between Duration and Period?
Answer: Duration is time-based (hours, minutes, seconds) used with LocalTime/LocalDateTime. Period is date-based (years, months, days) used with LocalDate. "3 hours" is Duration; "2 months and 5 days" is Period.
Q4: How do you convert between old Date and new LocalDateTime?
Answer: Date.toInstant() → LocalDateTime.ofInstant(instant, zoneId) and back: LocalDateTime.atZone(zoneId).toInstant() → Date.from(instant).
Q5: What happens at DST boundaries with ZonedDateTime?
Answer: Java handles gaps (spring forward) by moving forward to the next valid time, and overlaps (fall back) by choosing the earlier offset by default. You can use withEarlierOffsetAtOverlap() or withLaterOffsetAtOverlap().
Q6: What is Instant and when should you use it?
Answer: Instant represents a specific moment on the UTC timeline (machine time). Use it for timestamps, measuring elapsed time, database storage, and any time you need an absolute point in time regardless of timezone.
Summary
In this chapter, we learned about Date and Time API in Java 8 in detail. Here are the key points:
- Basic introduction to the concept and why it is needed
- Syntax and structure with complete examples
- Internal working and best practices
- Real-world applications and use cases
- Common mistakes and how to avoid them
- How this topic is asked in interviews
To practice these concepts, write and run the code in your IDE and verify the output. Modify each example and experiment so that you deeply understand the concept.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Date and Time API in Java 8.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, features, date, time
Related Java Master Course Topics