Lớp java.time.YearMonth
Lớp YearMonth trong gói java.time của Java được sử dụng để biểu diễn tháng-năm trong hệ lịch ISO-8601 (ví dụ: "2007-12"). Nó là một đối tượng ngày giờ bất biến (immutable) và cung cấp các phương thức để thao tác với tháng-năm.
Ⅰ. Đặc điểm của lớp YearMonth
↳ Kết hợp cả năm (Year) và tháng (Month) thành một giá trị duy nhất.
↳ Có thể truy xuất các thông tin liên quan đến tháng-năm như quý trong năm.
↳ Không lưu trữ hoặc biểu diễn ngày, thời gian hoặc múi giờ. Ví dụ, "Tháng 10 năm 2007" có thể được lưu trữ trong một đối tượng YearMonth.
↳ Sử dụng hệ lịch ISO-8601 tương tự như lớp Year.
Lưu ý:
↳ Hệ lịch ISO-8601 có thể không phù hợp với các ứng dụng xử lý ngày lịch sử đòi hỏi độ chính xác cao.
↳ YearMonth là lớp dựa trên giá trị (value-based class); do đó, việc sử dụng các phép toán dựa trên danh tính (identity-sensitive operations) như so sánh bằng (==), mã băm danh tính (identity hash code) hoặc đồng bộ hóa trên các thể hiện của YearMonth có thể dẫn đến kết quả không mong đợi và nên tránh. Sử dụng phương thức equals để so sánh các YearMonth.
↳ Lớp YearMonth bất biến (immutable) và an toàn cho nhiều luồng (thread-safe).
Ⅱ. Khai báo lớp YearMonth trong Java
Để sử dụng lớp YearMonth và các lớp khác trong gói java.time, bạn cần thêm câu lệnh import vào đầu file Java của mình.
Cú pháp câu lệnh import:
Cú pháp
import java.time.YearMonth;
Cú pháp khai báo lớp YearMonth:
Cú pháp khai báo YearMonth
public final class YearMonth
extends Object
implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable
Dưới đây là giải thích chi tiết về cú pháp khai báo này:
↳ public: Lớp này có thể được truy cập từ bất kỳ đâu trong chương trình, không bị giới hạn phạm vi.
↳ final: Lớp này không thể bị kế thừa. Điều này có nghĩa là bạn không thể tạo một lớp con từ YearMonth.
↳ class YearMonth: Khai báo một lớp có tên là YearMonth.
↳ extends Object: Tất cả các lớp trong Java đều kế thừa từ lớp Object (lớp gốc của tất cả các lớp trong Java). Việc này cho phép lớp YearMonth kế thừa các phương thức cơ bản từ Object, chẳng hạn như toString(), equals(), và hashCode().
implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable
Lớp YearMonth thực hiện (implements) các giao diện Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable. Điều này có nghĩa là lớp YearMonth phải cung cấp các phương thức được khai báo trong những giao diện này.
↳ implements Temporal: Lớp này triển khai giao diện Temporal, cung cấp các phương thức để thao tác với các đơn vị thời gian.
↳ implements TemporalAdjuster: Lớp này triển khai giao diện TemporalAdjuster, cho phép điều chỉnh các đối tượng thời gian.
↳ implements Comparable<YearMonth>: Lớp này triển khai giao diện Comparable để có thể so sánh các đối tượng YearMonth với nhau.
↳ implements Serializable: Lớp này triển khai giao diện Serializable, cho phép các đối tượng của lớp này có thể được tuần tự hóa (serialized), tức là có thể chuyển đổi thành một chuỗi byte để lưu trữ hoặc truyền tải qua mạng.
Ⅲ. Các phương thức của lớp YearMonth
Lớp YearMonth cung cấp nhiều phương thức để thao tác với tháng-năm. Việc phân nhóm các phương thức theo chức năng sẽ giúp bạn hiểu rõ hơn về cách sử dụng lớp YearMonth. Dưới đây là cách phân nhóm các phương thức phổ biến của lớp YearMonth:
Tạo đối tượng và lấy thông tin YearMonth
↳ now(): Lấy tháng-năm hiện tại từ đồng hồ hệ thống hoặc một Clock cụ thể.
↳ of(int year, int month): Tạo một đối tượng YearMonth từ năm và tháng cho trước.
↳ get(TemporalField field): Lấy giá trị của một trường thời gian cụ thể (như năm, tháng) từ YearMonth.
↳ isLeapYear(): Kiểm tra xem năm trong YearMonth có phải là năm nhuận hay không.
Dưới đây là ví dụ về các phương thức tạo đối tượng và lấy thông tin của lớp YearMonth trong java:
Ví dụ: Example.java
import java.time.YearMonth;
import java.time.temporal.ChronoField;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng YearMonth từ năm và tháng cho trước
YearMonth ym1 = YearMonth.of(2023, 7);
System.out.println("YearMonth từ năm 2023 và tháng 7: " + ym1);
// Lấy tháng-năm hiện tại từ đồng hồ hệ thống
YearMonth ym2 = YearMonth.now();
System.out.println("YearMonth hiện tại: " + ym2);
// Lấy giá trị của một trường thời gian cụ thể từ YearMonth
int year = ym1.get(ChronoField.YEAR);
int month = ym1.get(ChronoField.MONTH_OF_YEAR);
System.out.println("Năm: " + year + ", Tháng: " + month);
// Kiểm tra xem năm trong YearMonth có phải là năm nhuận hay không
boolean isLeap = ym1.isLeapYear();
System.out.println("Năm " + year + " có phải là năm nhuận không? " + isLeap);
}
}
Kết quả của chương trình là:
YearMonth hiện tại: 2024-07
Năm: 2023, Tháng: 7
Năm 2023 có phải là năm nhuận không? false
Trong ví dụ trên, các phương thức được sử dụng để tạo đối tượng YearMonth từ năm và tháng cho trước, lấy tháng-năm hiện tại từ hệ thống, lấy giá trị của các trường thời gian cụ thể, và kiểm tra xem năm trong YearMonth có phải là năm nhuận hay không.
Kiểm tra
↳ isAfter(YearMonth other): Kiểm tra xem YearMonth hiện tại có sau YearMonth khác hay không.
↳ isBefore(YearMonth other): Kiểm tra xem YearMonth hiện tại có trước YearMonth khác hay không.
Dưới đây là ví dụ về hai phương thức isAfter và isBefore của lớp YearMonth trong java:
Ví dụ: Example.java
import java.time.YearMonth;
public class Example {
public static void main(String[] args) {
// Tạo các đối tượng YearMonth
YearMonth ym1 = YearMonth.of(2023, 7);
YearMonth ym2 = YearMonth.of(2022, 5);
YearMonth ym3 = YearMonth.of(2024, 1);
// Kiểm tra xem ym1 có sau ym2 hay không
boolean isAfter = ym1.isAfter(ym2);
System.out.println("YearMonth " + ym1 + " có sau " + ym2 + " không? " + isAfter);
// Kiểm tra xem ym1 có trước ym3 hay không
boolean isBefore = ym1.isBefore(ym3);
System.out.println("YearMonth " + ym1 + " có trước " + ym3 + " không? " + isBefore);
}
}
Kết quả của chương trình là:
YearMonth 2023-07 có trước 2024-01 không? true
Trong ví dụ trên, các phương thức isAfter và isBefore được sử dụng để kiểm tra xem một đối tượng YearMonth có sau hoặc trước một đối tượng YearMonth khác hay không và in ra kết quả để bạn có thể thấy sự khác biệt trong cách chúng hoạt động.
So sánh
↳ equals(Object obj): Kiểm tra xem hai YearMonth có bằng nhau hay không.
↳ compareTo(YearMonth other): So sánh hai YearMonth và trả về một số nguyên thể hiện kết quả so sánh.
Dưới đây là ví dụ về hai phương thức equals và compareTo của lớp YearMonth trong một class:
Ví dụ: Example.java
import java.time.YearMonth;
public class Example {
public static void main(String[] args) {
// Tạo các đối tượng YearMonth
YearMonth ym1 = YearMonth.of(2023, 7);
YearMonth ym2 = YearMonth.of(2023, 7);
YearMonth ym3 = YearMonth.of(2022, 5);
// Kiểm tra xem ym1 có bằng ym2 hay không
boolean isEqual = ym1.equals(ym2);
System.out.println("YearMonth " + ym1 + " có bằng " + ym2 + " không? " + isEqual);
// So sánh ym1 với ym3
int comparisonResult = ym1.compareTo(ym3);
if (comparisonResult > 0) {
System.out.println("YearMonth " + ym1 + " lớn hơn " + ym3);
} else if (comparisonResult < 0) {
System.out.println("YearMonth " + ym1 + " nhỏ hơn " + ym3);
} else {
System.out.println("YearMonth " + ym1 + " bằng với " + ym3);
}
}
}
Kết quả của chương trình là:
YearMonth 2023-07 lớn hơn 2022-05
Hy vọng ví dụ này giúp bạn hiểu cách kết hợp ngày và thời gian để tạo một đối tượng LocalDateTime trong Java!
Điều chỉnh
↳ adjustInto(Temporal temporal): Điều chỉnh một đối tượng thời gian (Temporal) khác để có cùng tháng-năm với YearMonth hiện tại.
↳ plus(TemporalAmount amountToAdd): Cộng thêm một khoảng thời gian vào YearMonth.
↳ minus(TemporalAmount amountToSubtract): Trừ đi một khoảng thời gian khỏi YearMonth.
↳ withMonth(int month): Thay đổi tháng của YearMonth.
↳ withYear(int year): Thay đổi năm của YearMonth.
↳ atEndOfMonth(): Trả về một LocalDate đại diện cho ngày cuối cùng của tháng trong YearMonth hiện tại.
Dưới đây là ví dụ về sáu phương thức adjustInto, plus, minus, withMonth, withYear, và atEndOfMonth của lớp YearMonth trong một class:
Ví dụ: Example.java
import java.time.LocalDate;
import java.time.Period;
import java.time.YearMonth;
import java.time.temporal.Temporal;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng YearMonth
YearMonth ym = YearMonth.of(2023, 7);
System.out.println("YearMonth ban đầu: " + ym);
// Điều chỉnh đối tượng thời gian khác để có cùng tháng-năm với YearMonth hiện tại
LocalDate date = LocalDate.of(2021, 1, 1);
Temporal adjustedDate = ym.adjustInto(date);
System.out.println("Ngày đã điều chỉnh: " + adjustedDate);
// Cộng thêm một khoảng thời gian vào YearMonth
YearMonth ymPlus = ym.plus(Period.ofMonths(2));
System.out.println("YearMonth sau khi cộng thêm 2 tháng: " + ymPlus);
// Trừ đi một khoảng thời gian khỏi YearMonth
YearMonth ymMinus = ym.minus(Period.ofMonths(3));
System.out.println("YearMonth sau khi trừ đi 3 tháng: " + ymMinus);
// Thay đổi tháng của YearMonth
YearMonth ymWithMonth = ym.withMonth(12);
System.out.println("YearMonth với tháng thay đổi: " + ymWithMonth);
// Thay đổi năm của YearMonth
YearMonth ymWithYear = ym.withYear(2025);
System.out.println("YearMonth với năm thay đổi: " + ymWithYear);
// Trả về LocalDate đại diện cho ngày cuối cùng của tháng trong YearMonth hiện tại
LocalDate endOfMonth = ym.atEndOfMonth();
System.out.println("Ngày cuối cùng của tháng: " + endOfMonth);
}
}
Kết quả của chương trình là:
Ngày đã điều chỉnh: 2023-07-01
YearMonth sau khi cộng thêm 2 tháng: 2023-09
YearMonth sau khi trừ đi 3 tháng: 2023-04
YearMonth với tháng thay đổi: 2023-12
YearMonth với năm thay đổi: 2025-07
Ngày cuối cùng của tháng: 2023-07-31
Trong ví dụ trên, các phương thức adjustInto, plus, minus, withMonth, withYear, và atEndOfMonth được sử dụng để điều chỉnh, cộng, trừ, thay đổi tháng, thay đổi năm, và lấy ngày cuối cùng của tháng trong YearMonth hiện tại, và in ra kết quả để bạn có thể thấy sự khác biệt trong cách chúng hoạt động.
Định dạng
↳ format(DateTimeFormatter formatter):Định dạng YearMonth theo một mẫu định dạng cho trước.
Dưới đây là ví dụ về cách sử dụng phương thức format của lớp YearMonth trong một class:
Ví dụ: Example.java
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng YearMonth
YearMonth ym = YearMonth.of(2023, 7);
// Định dạng YearMonth theo một mẫu định dạng cho trước
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-yyyy");
String formattedYearMonth = ym.format(formatter);
// In ra kết quả định dạng
System.out.println("YearMonth đã định dạng: " + formattedYearMonth);
}
}
Kết quả của chương trình là:
Trong ví dụ trên, phương thức format được sử dụng để định dạng YearMonth theo mẫu định dạng "MM-yyyy" và in ra kết quả để bạn có thể thấy cách nó hoạt động.
Tính toán khoảng cách
↳ until(Temporal endExclusive, TemporalUnit unit): Tính khoảng cách giữa YearMonth hiện tại và một Temporal khác theo một đơn vị thời gian nhất định.
Dưới đây là ví dụ về cách sử dụng phương thức atTime(int hour, int minute) của lớp LocalDate để kết hợp ngày với thời gian và tạo ra một đối tượng LocalDateTime.
Ví dụ: Example.java
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng YearMonth hiện tại
YearMonth start = YearMonth.of(2023, 7);
// Tạo đối tượng YearMonth kết thúc
YearMonth end = YearMonth.of(2025, 12);
// Tính khoảng cách giữa start và end theo đơn vị tháng
long monthsBetween = start.until(end, ChronoUnit.MONTHS);
// In ra kết quả
System.out.println("Khoảng cách giữa " + start + " và " + end + " là " + monthsBetween + " tháng.");
}
}
Kết quả của chương trình là:
Trong ví dụ trên, phương thức until được sử dụng để tính khoảng cách giữa hai đối tượng YearMonth theo đơn vị tháng và in ra kết quả để bạn có thể thấy cách nó hoạt động.
Các ngoại lệ thường gặp khi sử dụng lớp YearMonth trong Java
Dưới đây là các ngoại lệ thường gặp và nguyên nhân của chúng:
Ngoại lệ DateTimeException
↳ Nguyên nhân: Xảy ra khi các giá trị đầu vào không hợp lệ trong việc thao tác với YearMonth.
↳ Ví dụ: Khi bạn cố tạo một đối tượng YearMonth với năm là số âm hoặc vượt quá phạm vi hợp lệ.
Ngoại lệ DateTimeParseException
↳ Nguyên nhân: Xảy ra khi chuỗi được phân tích không tuân theo định dạng ngày tháng hợp lệ.
↳ Ví dụ: Khi bạn cố gắng phân tích chuỗi "2024-15" thành một đối tượng YearMonth, nhưng "15" không phải là tháng hợp lệ.
Ngoại lệ NullPointerException
↳ Nguyên nhân: Xảy ra khi truyền một tham chiếu null vào phương thức của YearMonth.
↳ Ví dụ: Khi bạn cố gọi phương thức YearMonth.parse(null) mà không kiểm tra giá trị null.
Ngoại lệ UnsupportedTemporalTypeException
↳ Nguyên nhân: Xảy ra khi truy cập một trường hoặc giá trị không được hỗ trợ bởi YearMonth.
↳ Ví dụ: Khi bạn cố lấy giá trị ngày (DAY_OF_MONTH) từ một đối tượng YearMonth, nhưng lớp này chỉ hỗ trợ năm và tháng.
Ngoại lệ ArithmeticException
↳ Nguyên nhân: Xảy ra khi thực hiện các phép toán gây tràn số (overflow) hoặc chia cho không.
↳ Ví dụ: Khi bạn cố gắng cộng một số lượng lớn tháng hoặc năm vào YearMonth vượt quá giới hạn của kiểu dữ liệu.
Lưu ý:
Khi làm việc với YearMonth, việc kiểm tra dữ liệu đầu vào và các thao tác liên quan đến năm, tháng là rất quan trọng để tránh các ngoại lệ. Sử dụng các khối try-catch để xử lý ngoại lệ, cung cấp thông báo lỗi hoặc xử lý các tình huống bất thường sẽ giúp ứng dụng của bạn ổn định hơn và dễ dàng duy trì trong dài hạn.