0

[Java Backend Zero to Hello] BÀI 2.5: DATE/TIME API (Java 8+)

Java Backend Zero to Hello

📚 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí