# Bài 5: Date and Time API (Java 8)

#### Mục tiêu

Bài viết này nhằm mục đích giúp bạn hiểu và sử dụng API Date and Time mới trong Java 8. Chúng ta sẽ xem xét các vấn đề với API cũ, cách tạo và sử dụng các lớp mới trong API, các phương thức và ví dụ thực tế.

#### Nội dung

### 1\. Giới thiệu về Date and Time API

#### 1.1 Vấn đề với API cũ

* **Thiếu tính bất biến:**
    
    * Các lớp như [`java.util.Date`](http://java.util.Date) và `java.util.Calendar` không bất biến, dẫn đến nhiều vấn đề khi làm việc với các giá trị ngày giờ trong các ứng dụng đa luồng.
        
    * Ví dụ:
        
        ```java
        Date date = new Date();
        date.setYear(100); // Thay đổi giá trị năm
        ```
        
* **Thiếu tính rõ ràng và dễ sử dụng:**
    
    * API cũ khó sử dụng và gây nhầm lẫn do việc sử dụng hệ thống chỉ số (0-based và 1-based) không nhất quán.
        
    * Ví dụ:
        
        ```java
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.MONTH, 11); // Tháng 12 (0-based)
        calendar.set(Calendar.DATE, 31); // Ngày 31 (1-based)
        ```
        
* **Thiếu hỗ trợ cho các thao tác thông dụng:**
    
    * Các thao tác như cộng/trừ ngày tháng, so sánh thời gian, và định dạng ngày giờ đều rất phức tạp và không trực quan.
        
    * Ví dụ:
        
        ```java
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1); // Cộng thêm 1 ngày
        Date tomorrow = calendar.getTime();
        ```
        

#### 1.2 Mục đích và lợi ích của API mới

* **Bất biến và an toàn cho đa luồng:**
    
    * Các lớp trong API mới đều bất biến, đảm bảo an toàn khi sử dụng trong môi trường đa luồng.
        
* **Cấu trúc rõ ràng và dễ sử dụng:**
    
    * API mới sử dụng các lớp với tên gọi và chức năng rõ ràng, giúp lập trình viên dễ dàng thao tác và tránh nhầm lẫn.
        
* **Hỗ trợ đầy đủ các thao tác thông dụng:**
    
    * API mới cung cấp các phương thức trực quan và dễ sử dụng cho các thao tác với ngày giờ, bao gồm cộng/trừ, so sánh, và định dạng.
        

### 2\. Các lớp chính trong Date and Time API

#### 2.1 LocalDate

* **Mục đích:** Đại diện cho một ngày cụ thể, không bao gồm thời gian.
    
* **Tạo LocalDate:**
    
    ```java
    LocalDate date = LocalDate.of(2024, Month.MAY, 17);
    LocalDate today = LocalDate.now();
    ```
    
* **Các phương thức quan trọng:**
    
    * `plusDays()`, `minusDays()`: Thêm hoặc bớt ngày.
        
    * `isBefore()`, `isAfter()`: So sánh ngày.
        
    * `format()`: Định dạng ngày.
        
    
    ```java
    LocalDate date = LocalDate.of(2024, Month.MAY, 17);
    LocalDate tomorrow = date.plusDays(1);
    boolean isAfter = date.isAfter(LocalDate.of(2024, Month.MAY, 16));
    String formattedDate = date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
    ```
    

#### 2.2 LocalTime

* **Mục đích:** Đại diện cho một thời gian cụ thể trong ngày, không bao gồm ngày.
    
* **Tạo LocalTime:**
    
    ```java
    LocalTime time = LocalTime.of(14, 30);
    LocalTime now = LocalTime.now();
    ```
    
* **Các phương thức quan trọng:**
    
    * `plusHours()`, `minusMinutes()`: Thêm hoặc bớt thời gian.
        
    * `isBefore()`, `isAfter()`: So sánh thời gian.
        
    * `format()`: Định dạng thời gian.
        
    
    ```java
    LocalTime time = LocalTime.of(14, 30);
    LocalTime later = time.plusHours(2);
    boolean isBefore = time.isBefore(LocalTime.of(16, 0));
    String formattedTime = time.format(DateTimeFormatter.ofPattern("HH:mm"));
    ```
    

#### 2.3 LocalDateTime

* **Mục đích:** Đại diện cho một ngày và thời gian cụ thể.
    
* **Tạo LocalDateTime:**
    
    ```java
    LocalDateTime dateTime = LocalDateTime.of(2024, Month.MAY, 17, 14, 30);
    LocalDateTime now = LocalDateTime.now();
    ```
    
* **Các phương thức quan trọng:**
    
    * `plusDays()`, `minusHours()`: Thêm hoặc bớt ngày và thời gian.
        
    * `isBefore()`, `isAfter()`: So sánh ngày và thời gian.
        
    * `format()`: Định dạng ngày và thời gian.
        
    
    ```java
    LocalDateTime dateTime = LocalDateTime.of(2024, Month.MAY, 17, 14, 30);
    LocalDateTime futureDateTime = dateTime.plusDays(1).minusHours(2);
    boolean isAfter = dateTime.isAfter(LocalDateTime.of(2024, Month.MAY, 16, 14, 30));
    String formattedDateTime = dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
    ```
    

#### 2.4 ZonedDateTime

* **Mục đích:** Đại diện cho một ngày và thời gian với thông tin về múi giờ.
    
* **Tạo ZonedDateTime:**
    
    ```java
    ZonedDateTime zonedDateTime = ZonedDateTime.of(LocalDateTime.of(2024, Month.MAY, 17, 14, 30), ZoneId.of("Asia/Tokyo"));
    ZonedDateTime now = ZonedDateTime.now();
    ```
    
* **Các phương thức quan trọng:**
    
    * `withZoneSameInstant()`: Thay đổi múi giờ mà không thay đổi thời gian.
        
    * `withZoneSameLocal()`: Thay đổi múi giờ và thay đổi thời gian theo múi giờ mới.
        
    * `format()`: Định dạng ngày và thời gian với múi giờ.
        
    
    ```java
    ZonedDateTime zonedDateTime = ZonedDateTime.of(LocalDateTime.of(2024, Month.MAY, 17, 14, 30), ZoneId.of("Asia/Tokyo"));
    ZonedDateTime newYorkTime = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New_York"));
    String formattedZonedDateTime = zonedDateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z"));
    ```
    

### 3\. Các phương thức tiện ích trong Date and Time API

#### 3.1 Period

* **Mục đích:** Đại diện cho một khoảng thời gian ngày, tháng, năm.
    
* **Tạo Period:**
    
    ```java
    Period period = Period.of(1, 2, 3); // 1 năm, 2 tháng, 3 ngày
    ```
    
* **Các phương thức quan trọng:**
    
    * `between()`: Tính khoảng thời gian giữa hai ngày.
        
    * `plusDays()`, `minusMonths()`: Thêm hoặc bớt khoảng thời gian.
        
    
    ```java
    LocalDate startDate = LocalDate.of(2024, Month.JANUARY, 1);
    LocalDate endDate = LocalDate.of(2025, Month.JANUARY, 1);
    Period period = Period.between(startDate, endDate);
    Period addedPeriod = period.plusMonths(1);
    ```
    

#### 3.2 Duration

* **Mục đích:** Đại diện cho một khoảng thời gian giờ, phút, giây, nano giây.
    
* **Tạo Duration:**
    
    ```java
    Duration duration = Duration.ofHours(5);
    ```
    
* **Các phương thức quan trọng:**
    
    * `between()`: Tính khoảng thời gian giữa hai thời điểm.
        
    * `plusMinutes()`, `minusSeconds()`: Thêm hoặc bớt khoảng thời gian.
        
    
    ```java
    LocalTime startTime = LocalTime.of(10, 0);
    LocalTime endTime = LocalTime.of(12, 0);
    Duration duration = Duration.between(startTime, endTime);
    Duration addedDuration = duration.plusMinutes(30);
    ```
    

### 4\. Ví dụ thực tế sử dụng Date and Time API

#### 4.1 Tạo và định dạng ngày giờ

* **Ví dụ:**
    
    ```java
    LocalDate date = LocalDate.of(2024, 5, 17);
    LocalTime time = LocalTime.of(14, 30);
    LocalDateTime dateTime = LocalDateTime.of(date, time);
    ZonedDateTime zonedDateTime = ZonedDateTime.of(dateTime, ZoneId.of("Asia/Tokyo"));
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z");
    String formattedDateTime = zonedDateTime.format(formatter);
    System.out.println(formattedDateTime); // Output: 17/05/2024 14:30 JST
    ```
    

#### 4.2 Tính khoảng thời gian giữa hai ngày

* **Ví dụ:**
    
    ```java
    
    
    LocalDate startDate = LocalDate.of(2024, Month.JANUARY, 1);
    LocalDate endDate = LocalDate.of(2025, Month.JANUARY, 1);
    
    Period period = Period.between(startDate, endDate);
    System.out.println("Years: " + period.getYears()); // Output: Years: 1
    System.out.println("Months: " + period.getMonths()); // Output: Months: 0
    System.out.println("Days: " + period.getDays()); // Output: Days: 0
    ```
    

#### 4.3 Tính khoảng thời gian giữa hai thời điểm

* **Ví dụ:**
    
    ```java
    LocalTime startTime = LocalTime.of(10, 0);
    LocalTime endTime = LocalTime.of(12, 30);
    
    Duration duration = Duration.between(startTime, endTime);
    System.out.println("Hours: " + duration.toHours()); // Output: Hours: 2
    System.out.println("Minutes: " + duration.toMinutes()); // Output: Minutes: 150
    ```
    

#### 4.4 Chuyển đổi giữa các múi giờ

* **Ví dụ:**
    
    ```java
    ZonedDateTime tokyoTime = ZonedDateTime.of(LocalDateTime.of(2024, Month.MAY, 17, 14, 30), ZoneId.of("Asia/Tokyo"));
    ZonedDateTime newYorkTime = tokyoTime.withZoneSameInstant(ZoneId.of("America/New_York"));
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z");
    System.out.println(tokyoTime.format(formatter)); // Output: 17/05/2024 14:30 JST
    System.out.println(newYorkTime.format(formatter)); // Output: 17/05/2024 01:30 EDT
    ```
    

#### 4.5 So sánh ngày giờ

* **Ví dụ:**
    
    ```java
    LocalDate date1 = LocalDate.of(2024, Month.MAY, 17);
    LocalDate date2 = LocalDate.of(2025, Month.MAY, 17);
    
    boolean isBefore = date1.isBefore(date2);
    boolean isAfter = date2.isAfter(date1);
    
    System.out.println("isBefore: " + isBefore); // Output: isBefore: true
    System.out.println("isAfter: " + isAfter); // Output: isAfter: true
    ```
    

### 5\. Thực hành với các bài toán thực tế

#### 5.1 Tính tuổi từ ngày sinh

* **Bài toán:** Tính tuổi hiện tại từ ngày sinh.
    
* **Giải pháp:**
    
    ```java
    LocalDate birthDate = LocalDate.of(1990, Month.MAY, 17);
    LocalDate currentDate = LocalDate.now();
    
    Period age = Period.between(birthDate, currentDate);
    System.out.println("Age: " + age.getYears()); // Output: Age: 34 (vào năm 2024)
    ```
    

#### 5.2 Lập lịch cuộc họp theo múi giờ

* **Bài toán:** Lập lịch cuộc họp ở Tokyo và hiển thị thời gian tương ứng ở New York.
    
* **Giải pháp:**
    
    ```java
    ZonedDateTime meetingTimeInTokyo = ZonedDateTime.of(LocalDateTime.of(2024, Month.MAY, 17, 14, 30), ZoneId.of("Asia/Tokyo"));
    ZonedDateTime meetingTimeInNewYork = meetingTimeInTokyo.withZoneSameInstant(ZoneId.of("America/New_York"));
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z");
    System.out.println("Meeting Time in Tokyo: " + meetingTimeInTokyo.format(formatter)); // Output: 17/05/2024 14:30 JST
    System.out.println("Meeting Time in New York: " + meetingTimeInNewYork.format(formatter)); // Output: 17/05/2024 01:30 EDT
    ```
    

#### 5.3 Xử lý thời gian làm việc

* **Bài toán:** Tính tổng thời gian làm việc trong một ngày.
    
* **Giải pháp:**
    
    ```java
    LocalTime startTime = LocalTime.of(9, 0);
    LocalTime endTime = LocalTime.of(17, 0);
    
    Duration workDuration = Duration.between(startTime, endTime);
    System.out.println("Work Hours: " + workDuration.toHours()); // Output: Work Hours: 8
    ```
    

### Kết luận

API Date and Time mới trong Java 8 mang lại sự rõ ràng, dễ sử dụng và an toàn cho việc xử lý các giá trị ngày giờ. Với các lớp như `LocalDate`, `LocalTime`, `LocalDateTime`, và `ZonedDateTime`, lập trình viên có thể thao tác với ngày giờ một cách dễ dàng và hiệu quả hơn. Hiểu và sử dụng thành thạo các tính năng của API này sẽ giúp bạn viết mã Java chính xác và tối ưu hơn.

---
