Java Date/Time APIs, Exception Handling, and Optional Class Guide
1. Date and Time Classes
1.1 The Date Class
Epoch Reference Point
The epoch in computing begins at January 1, 1970, 00:00:00 UTC. All timestamps are calculated relative to this point.
Time Conversion
1 second equals 1000 milliseconds.
Date Class Overview
The Date class represents a specific moment in time, accurate to milliseconds.
Constructors
| Method | Description |
|---|---|
| public Date() | Creates a Date object initialized to the current time |
| public Date(long date) | Creates a Date object initialized to the specified milliseconds since epoch |
Example
public class DateDemo01 {
public static void main(String[] args) {
Date d1 = new Date();
System.out.println(d1);
long milliseconds = 1000 * 60 * 60;
Date d2 = new Date(milliseconds);
System.out.println(d2);
}
}
1.2 Common Date Methods
| Method | Description |
|---|---|
| public long getTime() | Returns milliseconds since epoch to the Date object |
| public void setTime(long time) | Sets the time using milliseconds |
Example
public class DateDemo02 {
public static void main(String[] args) {
Date d = new Date();
long currentMillis = System.currentTimeMillis();
d.setTime(currentMillis);
System.out.println(d);
}
}
1.3 SimpleDateFormat Class
Overview
SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner.
java.text.SimpleDateFormat formats dates to text and parses text to dates independently of language conventions.
Constructors
| Method | Description |
|---|---|
| public SimpleDateFormat() | Creates using default pattern and date format |
| public SimpleDateFormat(String pattern) | Creates using specified pattern and default date format |
Common Methods
- Formatting (Date → String): public final String format(Date date)
- Parsing (String → Date): public Date parse(String source)
Example
public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
Date current = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String formatted = formatter.format(current);
System.out.println(formatted);
System.out.println("--------");
String input = "2048-08-09 11:11:11";
SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date parsed = parser.parse(input);
System.out.println(parsed);
}
}
Calendar Class
Important Notes
- Month values: January is 0, February is 1, and so on (December is 11)
- Day of week values: Sunday is 1, Monday is 2, and so on (Saturday is 7)
Example
import org.junit.Test;
import java.util.Calendar;
import java.util.TimeZone;
public class CalendarTests {
@Test
public void testBasicCalendar() {
Calendar cal = Calendar.getInstance();
System.out.println(cal);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute);
}
@Test
public void testTimeZone() {
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
Calendar cal = Calendar.getInstance(tz);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DATE);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute);
}
@Test
public void testManipulation() {
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
date = new Date(234234235235L);
calendar.setTime(date);
calendar.set(Calendar.DAY_OF_MONTH, 8);
System.out.println("After setting day to 8: " + calendar.getTime());
calendar.add(Calendar.HOUR, 2);
System.out.println("After adding 2 hours: " + calendar.getTime());
calendar.add(Calendar.MONTH, -2);
System.out.println("After subtracting 2 months: " + calendar.getTime());
}
}
1.4 Date and Time Practice
Requirement
Flash sale starts at November 11, 2020 00:00:00 and ends at November 11, 2020 00:10:00. User A orders at 00:03:47, User B orders at 00:10:11. Determine which users successfully participated.
Implementation Steps
- Check if order time falls within the start and end range
- Convert string time to milliseconds
Code
public class FlashSaleCheck {
public static void main(String[] args) throws ParseException {
String startTime = "2020年11月11日 0:0:0";
String endTime = "2020年11月11日 0:10:0";
String userAOrder = "2020年11月11日 0:03:47";
String userBOrder = "2020年11月11日 0:10:11";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
long startMillis = sdf.parse(startTime).getTime();
long endMillis = sdf.parse(endTime).getTime();
long userAMillis = sdf.parse(userAOrder).getTime();
long userBMillis = sdf.parse(userBOrder).getTime();
if (userAMillis >= startMillis && userAMillis <= endMillis) {
System.out.println("User A participated successfully");
} else {
System.out.println("User A did not participate");
}
System.out.println("------------------------");
if (userBMillis >= startMillis && userBMillis <= endMillis) {
System.out.println("User B participated successfully");
} else {
System.out.println("User B did not participate");
}
}
}
2. JDK 8 Date and Time API
Expressing time as "1502643933071" is simple but lacks context. We need human-readable time tied to days and seasons, which complicates things. JDK 1.0 had java.util.Date, but most of its methods were deprecated when Calendar was introduced in JDK 1.1. Calendar wasn't much better:
- Mutability: Date and time classes should be immutable
- Offsets: Year values start from 1900, months from 0
- Formatting: Only works with Date, not Calendar
- Thread Safety: Not thread-safe; no leap second handling
A leap second is added to keep UTC close to UT1. Due to Earth's irregular rotation, when the difference exceeds ±0.9 seconds, UTC is adjusted by one second (positive or negative). 27 leap seconds have occurred globally, all positive.
The third date-time API introduction in Java 8 fixed these issues with java.time.
New API packages:
java.time– Core value typesjava.time.chrono– Alternative calendar systemsjava.time.format– Formatting and parsingjava.time.temporal– Framework extensionsjava.time.zone– Time zone support
2.1 New Date Classes
- LocalDate: Date only (year, month, day)
- LocalTime: Time only (hours, minutes, seconds)
- LocalDateTime: Date and time combined
2.2 Creating LocalDateTime
| Method | Description |
|---|---|
| public static LocalDateTime now() | Gets current system time |
| public static LocalDateTime of(year, month, day, hour, minute, second) | Creates with specified values |
Example
public class JDK8DateDemo2 {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
LocalDateTime specific = LocalDateTime.of(2020, 11, 11, 11, 11, 11);
System.out.println(specific);
}
}
2.3 Getting LocalDateTime Values
| Method | Description |
|---|---|
| public int getYear() | Gets year |
| public int getMonthValue() | Gets month (1-12) |
| public int getDayOfMonth() | Gets day of month (1-31) |
| public int getDayOfYear() | Gets day of year (1-366) |
| public DayOfWeek getDayOfWeek() | Gets day of week |
| public int getMinute() | Gets minutes |
| public int getHour() | Gets hours |
Example
public class JDK8DateDemo3 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 11, 11, 11, 11, 20);
System.out.println("Year: " + dt.getYear());
System.out.println("Month: " + dt.getMonthValue());
System.out.println("Day of month: " + dt.getDayOfMonth());
System.out.println("Day of year: " + dt.getDayOfYear());
System.out.println("Day of week: " + dt.getDayOfWeek());
System.out.println("Hour: " + dt.getHour());
System.out.println("Minute: " + dt.getMinute());
}
}
2.4 Converting LocalDateTime
| Method | Description |
|---|---|
| public LocalDate toLocalDate() | Converts to LocalDate |
| public LocalTime toLocalTime() | Converts to LocalTime |
Example
public class JDK8DateDemo4 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 12, 12, 8, 10, 12);
LocalDate date = dt.toLocalDate();
System.out.println(date);
LocalTime time = dt.toLocalTime();
System.out.println(time);
}
}
2.5 Formatting and Parsing LocalDateTime
| Method | Description |
|---|---|
| public String format(DateTimeFormatter formatter) | Formats to string |
| public static LocalDateTime parce(CharSequence text, DateTimeFormatter formatter) | Parses from string |
| public static DateTimeFormatter ofPattern(String pattern) | Creates formatter |
Example
public class JDK8DateDemo5 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 11, 12, 13, 14, 15);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String result = dt.format(fmt);
System.out.println(result);
String input = "2020年11月12日 13:14:15";
LocalDateTime parsed = LocalDateTime.parse(input, fmt);
System.out.println(parsed);
}
}
2.6 Adding Time to LocalDateTime
| Method | Description |
|---|---|
| public LocalDateTime plusYears(long years) | Adds/subtracts years |
| public LocalDateTime plusMonths(long months) | Adds/subtracts months |
| public LocalDateTime plusDays(long days) | Adds/subtracts days |
| public LocalDateTime plusHours(long hours) | Adds/subtracts hours |
| public LocalDateTime plusMinutes(long minutes) | Adds/subtracts minutes |
| public LocalDateTime plusSeconds(long seconds) | Adds/subtracts seconds |
| public LocalDateTime plusWeeks(long weeks) | Adds/subtracts weeks |
Example
public class JDK8DateDemo6 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
LocalDateTime adjusted = dt.plusYears(-1);
System.out.println(adjusted);
}
}
2.7 Subtracting Time from LocalDateTime
| Method | Description |
|---|---|
| public LocalDateTime minusYears(long years) | Subtracts/adds years |
| public LocalDateTime minusMonths(long months) | Subtracts/adds months |
| public LocalDateTime minusDays(long days) | Subtracts/adds days |
| public LocalDateTime minusHours(long hours) | Subtracts/adds hours |
| public LocalDateTime minusMinutes(long minutes) | Subtracts/adds minutes |
| public LocalDateTime minusSeconds(long seconds) | Subtracts/adds seconds |
| public LocalDateTime minusWeeks(long weeks) | Subtracts/adds weeks |
Example
public class JDK8DateDemo7 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
LocalDateTime adjusted = dt.minusYears(-1);
System.out.println(adjusted);
}
}
2.8 Modifying LocalDateTime
| Method | Description |
|---|---|
| public LocalDateTime withYear(int year) | Sets year directly |
| public LocalDateTime withMonth(int month) | Sets month directly |
| public LocalDateTime withDayOfMonth(int day) | Sets day of month |
| public LocalDateTime withDayOfYear(int day) | Sets day of year |
| public LocalDateTime withHour(int hour) | Sets hour |
| public LocalDateTime withMinute(int minute) | Sets minute |
| public LocalDateTime withSecond(int second) | Sets second |
Example
public class JDK8DateDemo8 {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2020, 11, 11, 13, 14, 15);
LocalDateTime modified = dt.withMonth(20);
System.out.println(modified);
}
}
2.9 Instant Class
Instant represents a point on the timeline without timezone context. It stores seconds since epoch (January 1, 1970 00:00:00 UTC).
| Method | Description |
|---|---|
| now() | Returns Instant for default UTC zone |
| ofEpochMilli(long millis) | Creates Instant from milliseconds |
| atOffset(ZoneOffset offset) | Creates OffsetDateTime with offset |
| toEpochMilli() | Returns milliseconds since epoch |
China (UTC+8) is 8 hours ahead of UTC. Beijing is in the eastern 8th time zone.
2.10 DateTimeFormatter Class
Three formatting approaches:
- Predefined standard formats: ISO_LOCAL_DATE_TIME, ISO_LOCAL_DATE, ISO_LOCAL_TIME
- Localized formats: ofLocalizedDate(FormatStyle.LONG)
- Custom patterns: ofPattern("yyyy-MM-dd HH:mm:ss")
| Method | Description |
|---|---|
| ofPattern(String pattern) | Creates formatter with pattern |
| format(TemporalAccessor temporal) | Formats to string |
| parse(CharSequence text) | Parses from string |
Example
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
public class FormatterTests {
@Test
public void testStandardFormat() {
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dt = LocalDateTime.now();
String result = formatter.format(dt);
System.out.println(result);
TemporalAccessor parsed = formatter.parse("2022-12-04T21:02:14.808");
LocalDateTime fromParse = LocalDateTime.from(parsed);
System.out.println(fromParse);
}
@Test
public void testLocalizedFormat() {
LocalDateTime dt = LocalDateTime.now();
DateTimeFormatter fmt1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String str1 = fmt1.format(dt);
System.out.println(str1);
DateTimeFormatter fmt2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String str2 = fmt2.format(java.time.LocalDate.now());
System.out.println(str2);
}
@Test
public void testCustomPattern() {
DateTimeFormatter customFmt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String formatted = customFmt.format(LocalDateTime.now());
System.out.println(formatted);
TemporalAccessor parsed = customFmt.parse("2022/12/04 21:05:42");
LocalDateTime dt = LocalDateTime.from(parsed);
System.out.println(dt);
}
}
2.11 Time Zone Handling
ZoneId and ZonedDateTime
- ZoneId: Contains all timezone information (e.g., Europe/Paris)
- ZonedDateTime: Date-time with timezone in ISO-8601 calendar (e.g., 2007-12-03T10:15:30+01:00)
Common Zone IDs
Asia/Shanghai
UTC
America/New_York
Example
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;
public class ZoneTests {
@org.junit.Test
public void listAllZones() {
Set<String> zones = ZoneId.getAvailableZoneIds();
for (String zone : zones) {
System.out.println(zone);
}
}
@org.junit.Test
public void useZones() {
ZonedDateTime local = ZonedDateTime.now();
System.out.println(local);
ZonedDateTime ny = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println(ny);
}
}
2.12 Period and Duration
Period - Date-based intervals
| Method | Description |
|---|---|
| static Period between(LocalDate start, LocalDate end) | Calculates interval |
| int getYears() | Gets years |
| int getMonths() | Gets months |
| int getDays() | Gets days |
| long toTotalMonths() | Total months |
Example
public class JDK8DateDemo9 {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2020, 1, 1);
LocalDate date2 = LocalDate.of(2048, 12, 12);
Period period = Period.between(date1, date2);
System.out.println(period);
System.out.println("Years: " + period.getYears());
System.out.println("Months: " + period.getMonths());
System.out.println("Days: " + period.getDays());
System.out.println("Total months: " + period.toTotalMonths());
}
}
Duration - Time-based intervals
| Method | Description |
|---|---|
| static Duration between(Temporal start, Temporal end) | Calculates interval |
| long toSeconds() | Total seconds |
| int toMillis() | Total milliseconds |
| int toNanos() | Total nanoseconds |
Example
public class JDK8DateDemo10 {
public static void main(String[] args) {
LocalDateTime dt1 = LocalDateTime.of(2020, 1, 1, 13, 14, 15);
LocalDateTime dt2 = LocalDateTime.of(2020, 1, 2, 11, 12, 13);
Duration duration = Duration.between(dt1, dt2);
System.out.println(duration);
System.out.println("Seconds: " + duration.toSeconds());
System.out.println("Millis: " + duration.toMillis());
System.out.println("Nanos: " + duration.toNanos());
}
}
2.13 Conversion with Legacy APIs
| New Class | To Legacy | From Legacy |
|---|---|---|
| Instant ↔ java.util.Date | Date.from(instant) | date.toInstant() |
| Instant ↔ java.sql.Timestamp | Timestamp.from(instant) | timestamp.toInstant() |
| ZonedDateTime ↔ GregorianCalendar | GregorianCalendar.from(zdt) | cal.toZonedDateTime() |
| LocalDate ↔ java.sql.Date | Date.valueOf(localDate) | date.toLocalDate() |
| LocalTime ↔ java.sql.Time | Time.valueOf(localTime) | time.toLocalTime() |
| LocalDateTime ↔ java.sql.Timestamp | Timestamp.valueOf(ldt) | ts.toLocalDateTime() |
| ZoneId ↔ java.util.TimeZone | TimeZone.getTimeZone(id) | tz.toZoneId() |
3. Exception Handling
3.1 Exception Overview
An exception is an abnormal condition during program execution.
3.2 Checked vs Unchecked Exceptions
Checked Exceptions
- All subclasses of Exception
- Must be handled explicitly, otherwise compilation fails
Unchecked Exceptions
- All subclasses of RuntimeException
- Optional handling, can be treated like checked exceptions
3.3 JVM Default Exception Handling
When an exception occurs with no handling:
- Exception name, cause, and location printed to console
- Program execution stops
3.4 Exception Information
Console output shows: exception class name, reason, and location. Use this to locate and fix bugs.
3.5 Handling with throws
Declaration Format
public void method() throws ExceptionType {
}
Example
public class ExceptionDemo {
public static void main(String[] args) throws ParseException {
System.out.println("Start");
method2();
System.out.println("End");
}
public static void method2() throws ParseException {
String dateStr = "2048-08-09";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(dateStr);
System.out.println(d);
}
public static void method() throws ArrayIndexOutOfBoundsException {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
}
}
Notes
- throws follows the method parentheses
- Checked exceptions must be handled (try-catch or throws)
- Unchecked exceptions may not be declared, handled by JVM by default
3.6 Throwing Exceptions
Format
throw new Exception();
Code after throw does not execute.
throws vs throw
| throws | throw |
|---|---|
| In method declaration, followed by exception class | In method body, followed by exception object |
| Declares possible exception, caller may need handling | Manually throws exception object |
Example
public class ExceptionDemo8 {
public static void main(String[] args) {
int[] arr = null;
printArray(arr);
}
private static void printArray(int[] array) {
if (array == null) {
throw new NullPointerException();
}
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
3.7 try-catch Handling
Format
try {
// Code that may throw exception
} catch (ExceptionType variable) {
// Exception handling
}
Flow
- Execute code inside try
- On exception, jump to corresponding catch
- Continue execution after try-catch block
Example
public class ExceptionDemo01 {
public static void main(String[] args) {
System.out.println("Start");
process();
System.out.println("End");
}
public static void process() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
System.out.println("Can this print?");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index out of bounds, please fix");
}
}
}
Key Points
- If try completes without exception, catch is skipped
- If exception occurs in try, remaining try code is skipped, catch executes
- Uncaught exceptions are handled by JVM
- Multiple catch blocks handle different exceptions; parent classes should come last
3.8 Throwable Methods
| Method | Description |
|---|---|
| String getMessage() | Returns detailed exception message |
| String toString() | Returns short description |
| void printStackTrace() | Prints full stack trace to console |
Example
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("Start");
process();
System.out.println("End");
}
public static void process() {
try {
int[] arr = {1, 2, 3};
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
3.9 Exception Practice
Requirement
Input student name and age (18-25). Invalid ages require re-entry until valid.
Student Class
public class Student {
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 18 && age <= 25) {
this.age = age;
} else {
throw new RuntimeException("Age out of range");
}
}
}
Test Class
public class StudentInputDemo {
public static void main(String[] args) {
Student student = new Student();
Scanner scanner = new Scanner(System.in);
System.out.println("Enter name:");
student.setName(scanner.nextLine());
while (true) {
System.out.println("Enter age:");
String ageInput = scanner.nextLine();
try {
int age = Integer.parseInt(ageInput);
student.setAge(age);
break;
} catch (NumberFormatException e) {
System.out.println("Please enter a valid integer");
} catch (AgeOutOfBoundsException e) {
System.out.println(e.toString());
System.out.println("Enter age within valid range");
}
}
System.out.println(student);
}
}
3.10 Custom Exceptions
When to Use
When built-in exceptions don't meet requirements.
Steps
- Create exception class
- Extend appropriate base class
- Provide no-arg constructor
- Provide constructor with message
Custom Exception
public class AgeOutOfBoundsException extends RuntimeException {
public AgeOutOfBoundsException() {}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
Student Class with Custom Expection
public class Student {
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
setAge(age);
}
public void setAge(int age) {
if (age >= 18 && age <= 25) {
this.age = age;
} else {
throw new AgeOutOfBoundsException("Age out of range");
}
}
}
4. Optional Class
4.1 Creating Optional Objects
Overview
Optional is a container that may or may not hold a non-null value.
| Method | Description |
|---|---|
| static <T> Optional<T> of(T value) | Creates Optional with non-null value |
| static <T> Optional<T> ofNullable(T value) | Creates Optional that may be null |
Example
public class OptionalDemo1 {
public static void main(String[] args) {
Student s = null;
Optional<Student> optional = Optional.ofNullable(s);
System.out.println(optional);
}
}
4.2 Common Methods
| Method | Description |
|---|---|
| T get() | Returns value if present, throws NoSuchElementException otherwise |
| boolean isPresent() | Returns true if value exists, false otherwise |
Example
public class OptionalDemo2 {
public static void main(String[] args) {
Student s = null;
Optional<Student> optional = Optional.ofNullable(s);
if (optional.isPresent()) {
Student student = optional.get();
System.out.println(student);
} else {
System.out.println("Optional is empty");
}
}
}
4.3 Handling Null Values
| Method | Description |
|---|---|
| T orElse(T other) | Returns value if present, otherwise returns other |
| T orElseGet(Supplier<? extends T> supplier) | Returns value if present, otherwise returns supplier result |
| void ifPresent(Consumer<? super T> action) | Executes action if value present |
| void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) | Executes action if present, else executes emptyAction |
Example
public class OptionalDemo3 {
public static void main(String[] args) {
Student s = null;
Optional<Student> optional = Optional.ofNullable(s);
// orElse: returns default if empty
Student result1 = optional.orElse(new Student("lisi", 24));
System.out.println(result1);
// orElseGet: returns supplier result if empty
Student result2 = optional.orElseGet(() -> new Student("wangwu", 25));
System.out.println(result2);
// ifPresent: execute if not empty
optional.ifPresent(student -> System.out.println(student));
// ifPresentOrElse: execute different actions based on presence
optional.ifPresentOrElse(
student -> System.out.println(student),
() -> System.out.println("No value present")
);
}
}