[Java Backend Zero to Hello] BÀI 2.5: DATE/TIME API (Java 8+)
📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 2: Java Core Nâng Cao | Bài 20/86
BÀI 2.5: DATE/TIME API (Java 8+)
Mục tiêu
- Hiểu vấn đề của java.util.Date
- Sử dụng Date/Time API mới (java.time)
- Format và parse ngày tháng
- Tính toán với date/time
1. VẤN ĐỀ CỦA DATE CŨ
java.util.Date, Calendar, SimpleDateFormat có nhiều vấn đề:
- Không thread-safe
- Thiết kế kém (Date vừa là date vừa là time)
- Tháng bắt đầu từ 0
- Format phức tạp
2. JAVA.TIME API
Java 8 giới thiệu package java.time với thiết kế tốt hơn.
Các class chính
| Class | Mô tả |
|---|---|
LocalDate |
Ngày (không có giờ) |
LocalTime |
Giờ (không có ngày) |
LocalDateTime |
Ngày + giờ |
ZonedDateTime |
Ngày giờ có timezone |
Instant |
Timestamp (epoch) |
Duration |
Khoảng thời gian (giờ, phút, giây) |
Period |
Khoảng thời gian (năm, tháng, ngày) |
DateTimeFormatter |
Format/Parse |
3. LOCALDATE
import java.time.LocalDate;
import java.time.Month;
// Tạo LocalDate
LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2024, Month.JANUARY, 15);
LocalDate parsed = LocalDate.parse("2024-01-15");
// Lấy thông tin
int year = today.getYear();
int month = today.getMonthValue(); // 1-12
Month monthEnum = today.getMonth(); // JANUARY
int day = today.getDayOfMonth();
DayOfWeek dayOfWeek = today.getDayOfWeek();
int dayOfYear = today.getDayOfYear();
boolean isLeap = today.isLeapYear();
4. LOCALTIME
import java.time.LocalTime;
LocalTime now = LocalTime.now();
LocalTime specific = LocalTime.of(14, 30, 0); // 14:30:00
LocalTime parsed = LocalTime.parse("14:30:00");
int hour = now.getHour();
int minute = now.getMinute();
int second = now.getSecond();
int nano = now.getNano();
5. LOCALDATETIME
import java.time.LocalDateTime;
LocalDateTime now = LocalDateTime.now();
LocalDateTime specific = LocalDateTime.of(2024, Month.JANUARY, 15, 14, 30);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15T14:30:00");
// Chuyển đổi
LocalDate date = now.toLocalDate();
LocalTime time = now.toLocalTime();
LocalDateTime fromDateTime = LocalDateTime.of(date, time);
6. ZONEDDATETIME
import java.time.ZoneId;
import java.time.ZonedDateTime;
ZonedDateTime nowInHCM = ZonedDateTime.now(ZoneId.of("Asia/Ho_Chi_Minh"));
ZonedDateTime nowInUTC = ZonedDateTime.now(ZoneId.of("UTC"));
ZonedDateTime nowInNY = ZonedDateTime.now(ZoneId.of("America/New_York"));
// Chuyển timezone
ZonedDateTime hcmTime = ZonedDateTime.now();
ZonedDateTime nyTime = hcmTime.withZoneSameInstant(ZoneId.of("America/New_York"));
7. INSTANT
import java.time.Instant;
Instant now = Instant.now();
Instant specific = Instant.ofEpochSecond(1000000000L);
long epochSecond = now.getEpochSecond();
long epochMilli = now.toEpochMilli();
8. TÍNH TOÁN VỚI DATE/TIME
8.1 Cộng/trừ
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
LocalDate nextWeek = today.plusWeeks(1);
LocalDate nextMonth = today.plusMonths(1);
LocalDate nextYear = today.plusYears(1);
LocalDate yesterday = today.minusDays(1);
LocalDate lastMonth = today.minusMonths(1);
8.2 So sánh
LocalDate date1 = LocalDate.of(2024, 1, 15);
LocalDate date2 = LocalDate.of(2024, 2, 20);
boolean isBefore = date1.isBefore(date2); // true
boolean isAfter = date1.isAfter(date2); // false
boolean isEqual = date1.isEqual(date2); // false
8.3 Tính khoảng cách
LocalDate start = LocalDate.of(2024, 1, 1);
LocalDate end = LocalDate.of(2024, 12, 31);
Period period = Period.between(start, end);
int years = period.getYears(); // 0
int months = period.getMonths(); // 11
int days = period.getDays(); // 30
// Tổng số ngày
long daysBetween = ChronoUnit.DAYS.between(start, end); // 365
long monthsBetween = ChronoUnit.MONTHS.between(start, end); // 11
9. DATETIMEFORMATTER
9.1 Format mặc định
import java.time.format.DateTimeFormatter;
LocalDateTime now = LocalDateTime.now();
String iso = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// "2024-01-15T14:30:00"
String basic = now.format(DateTimeFormatter.BASIC_ISO_DATE);
// "20240115"
9.2 Format tùy chỉnh
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
String formatted = now.format(formatter);
// "15/01/2024 14:30:00"
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("EEEE, dd MMMM yyyy", Locale.ENGLISH);
String formatted2 = now.format(formatter2);
// "Monday, 15 January 2024"
9.3 Parse
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date = LocalDate.parse("15/01/2024", formatter);
9.4 Các pattern phổ biến
| Pattern | Mô tả | Ví dụ |
|---|---|---|
yyyy |
Năm | 2024 |
MM |
Tháng (2 chữ số) | 01 |
dd |
Ngày (2 chữ số) | 15 |
HH |
Giờ (24h) | 14 |
mm |
Phút | 30 |
ss |
Giây | 45 |
EEE |
Thứ (viết tắt) | Mon |
EEEE |
Thứ (đầy đủ) | Monday |
MMM |
Tháng (viết tắt) | Jan |
MMMM |
Tháng (đầy đủ) | January |
a |
AM/PM | PM |
10. DURATION VÀ PERIOD
import java.time.Duration;
import java.time.Period;
// Duration - giờ, phút, giây, nano
LocalTime start = LocalTime.of(9, 0);
LocalTime end = LocalTime.of(17, 30);
Duration duration = Duration.between(start, end);
long hours = duration.toHours(); // 8
long minutes = duration.toMinutes(); // 510
// Period - năm, tháng, ngày
LocalDate birth = LocalDate.of(1990, 5, 15);
LocalDate today = LocalDate.now();
Period age = Period.between(birth, today);
int years = age.getYears();
11. CHUYỂN ĐỔI VỚI DATE CŨ
// Date → LocalDateTime
Date oldDate = new Date();
LocalDateTime newDateTime = oldDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
// LocalDateTime → Date
LocalDateTime ldt = LocalDateTime.now();
Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
12. BÀI TẬP THỰC HÀNH
Bài 1: Tính tuổi
public static int calculateAge(LocalDate birthDate) {
return Period.between(birthDate, LocalDate.now()).getYears();
}
Bài 2: Kiểm tra ngày hợp lệ
public static boolean isValidDate(int year, int month, int day) {
try {
LocalDate.of(year, month, day);
return true;
} catch (DateTimeException e) {
return false;
}
}
Bài 3: Đếm ngày làm việc
public static long countWorkingDays(LocalDate start, LocalDate end) {
long count = 0;
LocalDate current = start;
while (!current.isAfter(end)) {
DayOfWeek day = current.getDayOfWeek();
if (day != DayOfWeek.SATURDAY && day != DayOfWeek.SUNDAY) {
count++;
}
current = current.plusDays(1);
}
return count;
}
Bài 4: Format ngày sinh nhật
public static String formatBirthday(LocalDate birthday) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd 'tháng' MM, yyyy", new Locale("vi"));
return birthday.format(formatter);
}
13. TÓM TẮT
| Class | Mô tả |
|---|---|
LocalDate |
Ngày |
LocalTime |
Giờ |
LocalDateTime |
Ngày + giờ |
ZonedDateTime |
Có timezone |
Instant |
Timestamp |
Duration |
Khoảng thời gian (giờ) |
Period |
Khoảng thời gian (ngày) |
DateTimeFormatter |
Format/Parse |
Bài tiếp theo: 2.6 Đa luồng (Multithreading)
🧭 Điều Hướng Series
⬅️ Bài trước: BÀI 2.4: OPTIONAL
📋 Lộ trình tổng quan: Xem Toàn Bộ Series
➡️ Bài tiếp theo: BÀI 2.6: ĐA LUỒNG (MULTITHREADING)
All rights reserved