Lớp java.time.Month
Lớp Month trong gói java.time của Java là một kiểu liệt kê (enum) biểu diễn 12 tháng trong năm: Tháng Một, Tháng Hai, Tháng Ba, Tháng Tư, Tháng Năm, Tháng Sáu, Tháng Bảy, Tháng Tám, Tháng Chín, Tháng Mười, Tháng Mười Một và Tháng Mười Hai.
Ⅰ. Đặc điểm của lớp Month
↳ Mỗi tháng có tên đầy đủ (ví dụ: Tháng Bảy) và một giá trị kiểu số nguyên (int).
↳ Giá trị int của tháng bắt đầu từ 1 (Tháng Một) đến 12 (Tháng Mười Hai), tuân theo cách sử dụng thông thường và chuẩn ISO-8601.
↳ Nên sử dụng tên tháng (enum) thay vì giá trị số int để đảm bảo mã dễ đọc.
↳ Sử dụng phương thức getValue() để lấy giá trị số int của tháng, không nên dùng phương thức ordinal().
↳ Month là một khái niệm chung trong nhiều hệ thống lịch. Do đó, nó có thể được sử dụng bởi bất kỳ hệ thống lịch nào có khái niệm tháng tương đương với lịch ISO-8601.
↳ Month là một kiểu liệt kê bất biến (immutable) và an toàn cho nhiều luồng (thread-safe).
Ⅱ. Khai báo lớp Month trong Java
Để sử dụng lớp Month 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.Month;
Cú pháp khai báo lớp Month:
Cú pháp
public enum Month
extends Enum<Month>
implements TemporalAccessor, TemporalAdjuster
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.
↳ enum Month: Đây là một enum (liệt kê) công khai có tên là Month. Một enum là một loại lớp đặc biệt trong Java dùng để định nghĩa một tập hợp các hằng số. Trong trường hợp này, Month đại diện cho các tháng trong năm.
extends Enum<Month>: Month kế thừa từ lớp Enum<Month>. Điều này có nghĩa là Month là một kiểu liệt kê và sẽ kế thừa các phương thức và thuộc tính từ lớp Enum.
implements TemporalAccessor, TemporalAdjuster
Lớp Month thực hiện (implements) các giao diện TemporalAccessor, TemporalAdjuster. Điều này có nghĩa là lớp Month phải cung cấp các phương thức được khai báo trong những giao diện này.
↳ implements TemporalAccessor: Cung cấp các phương thức để truy cập thông tin về thời gian. Giao diện này cho phép Month truy cập và lấy thông tin về tháng.
↳ implements TemporalAdjuster: Cho phép Month điều chỉnh các đối tượng thời gian khác. Giao diện này cho phép điều chỉnh hoặc tính toán các giá trị liên quan đến thời gian dựa trên Month.
Các Hằng Số Enum
Month cung cấp các hằng số enum để biểu diễn các tháng cụ thể trong năm:
↳ JANUARY: Biểu diễn tháng Một, có 31 ngày.
↳ FEBRUARY: Biểu diễn tháng Hai, có 28 ngày trong năm thường và 29 ngày trong năm nhuận.
↳ APRIL: Biểu diễn tháng Tư, có 30 ngày.
↳ MAY: Biểu diễn tháng Năm, có 31 ngày.
↳ JUNE: Biểu diễn tháng Sáu, có 30 ngày.
↳ JULY: Biểu diễn tháng Bảy, có 31 ngày.
↳ AUGUST: Biểu diễn tháng Tám, có 31 ngày.
↳ SEPTEMBER: Biểu diễn tháng Chín, có 30 ngày.
↳ OCTOBER: Biểu diễn tháng Mười, có 31 ngày.
↳ NOVEMBER: Biểu diễn tháng Mười Một, có 30 ngày.
↳ DECEMBER: Biểu diễn tháng Mười Hai, có 31 ngày.
Lưu ý rằng: Mỗi hằng số này là một đối tượng duy nhất (singleton) đại diện cho tháng tương ứng trong năm.
Ⅲ. Các phương thức của lớp Month
Lớp Month cung cấp nhiều phương thức để thao tác với tháng. 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 Month. Dưới đây là cách phân nhóm các phương thức phổ biến của lớp Month:
Tạo đối tượng Month
↳ of(int month): Tạo một đối tượng Month từ một số nguyên biểu diễn tháng.
↳ values(): Trả về một mảng chứa tất cả các giá trị có thể của Month.
↳ valueOf(String name): Tạo một Month từ tên của nó (ví dụ: "JANUARY").
from(TemporalAccessor temporal): Chuyển đổi một đối tượng thời gian khác thành Month.
Dưới đây là ví dụ về cách sử dụng các phương thức of(), values(), valueOf(), và from() của lớp Month trong một lớp Java:
Ví dụ: Example.java
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAccessor;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng Month từ số nguyên biểu diễn tháng
Month monthFromInt = Month.of(5); // Tháng 5
System.out.println("Tháng của 5: " + monthFromInt);
// Trả về một mảng chứa tất cả các giá trị của Month
Month[] allMonths = Month.values();
System.out.println("Tất cả các tháng:");
for (Month month : allMonths) {
System.out.println(month);
}
// Tạo một Month từ tên của nó
Month monthFromName = Month.valueOf("JANUARY"); // Tháng 1
System.out.println("Giá trị thángTrong số 'JANUARY': " + monthFromName);
// Chuyển đổi một đối tượng thời gian khác thành Month
TemporalAccessor temporal = LocalDate.of(2024, Month.AUGUST, 15); // Ngày 15 tháng 8 năm 2024
Month monthFromTemporal = Month.from(temporal);
System.out.println("Tháng từ LocalDate: " + monthFromTemporal);
}
}
Kết quả của chương trình là:
Tháng của 5: MAY
Tất cả các tháng:
JANUARY
FEBRUARY
MARCH
APRIL
MAY
JUNE
JULY
AUGUST
SEPTEMBER
OCTOBER
NOVEMBER
DECEMBER
Giá trị thángTrong số 'JANUARY': JANUARY
Tháng từ LocalDate: AUGUST
Trong ví dụ trên, các phương thức được sử dụng để tạo đối tượng Month từ số nguyên, lấy tất cả các giá trị có thể của Month, và tạo đối tượng Month từ tên của nó.
Lấy thông tin
↳ get(TemporalField field): Lấy giá trị của một trường thời gian cụ thể (như tháng).
↳ getLong(TemporalField field): Giống get nhưng trả về giá trị kiểu long.
↳ getValue(): Lấy giá trị số nguyên biểu diễn tháng.
↳ getDisplayName(TextStyle style, Locale locale): Lấy tên hiển thị của tháng.
↳ isSupported(TemporalField field): Kiểm tra xem trường thời gian có được hỗ trợ hay không.
↳ range(TemporalField field): Lấy phạm vi các giá trị hợp lệ cho một trường thời gian.
↳ length(boolean leapYear): Trả về số ngày trong tháng dựa trên năm.
↳ maxLength(): Trả về số ngày tối đa của tháng.
↳ minLength(): Trả về số ngày tối thiểu của tháng.
↳ firstDayOfYear(boolean leapYear): Trả về ngày đầu tiên của tháng trong năm.
↳ firstMonthOfQuarter(): Trả về tháng đầu tiên của quý.
Dưới đây là ví dụ về cách sử dụng các phương thức của lớp Month để lấy thông tin:
Ví dụ: Example.java
import java.time.Month;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.util.Locale;
public class Example {
public static void main(String[] args) {
Month month = Month.JULY; // Tháng 7
// Lấy giá trị của một trường thời gian cụ thể
int monthValue = month.get(ChronoField.MONTH_OF_YEAR);
System.out.println("Giá trị của tháng theo ChronoField.MONTH_OF_YEAR: " + monthValue);
// Lấy giá trị của một trường thời gian theo kiểu long
long monthValueLong = month.getLong(ChronoField.MONTH_OF_YEAR);
System.out.println("Giá trị của tháng theo ChronoField.MONTH_OF_YEAR (long): " + monthValueLong);
// Lấy giá trị số nguyên biểu diễn tháng
int value = month.getValue();
System.out.println("Giá trị số nguyên của tháng: " + value);
// Lấy tên hiển thị của tháng
String displayName = month.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
System.out.println("Tên hiển thị của tháng: " + displayName);
// Kiểm tra xem trường thời gian có được hỗ trợ hay không
boolean isSupported = month.isSupported(ChronoField.MONTH_OF_YEAR);
System.out.println("Trường MONTH_OF_YEAR có được hỗ trợ không: " + isSupported);
// Lấy phạm vi các giá trị hợp lệ cho một trường thời gian
System.out.println("Phạm vi giá trị hợp lệ cho MONTH_OF_YEAR: " + month.range(ChronoField.MONTH_OF_YEAR));
// Trả về số ngày trong tháng dựa trên năm
int length = month.length(false); // false cho năm không nhuận
System.out.println("Số ngày trong tháng (không nhuận): " + length);
// Trả về số ngày tối đa của tháng
int maxLength = month.maxLength();
System.out.println("Số ngày tối đa trong tháng: " + maxLength);
// Trả về số ngày tối thiểu của tháng
int minLength = month.minLength();
System.out.println("Số ngày tối thiểu trong tháng: " + minLength);
// Trả về ngày đầu tiên của tháng trong năm
int firstDayOfYear = month.firstDayOfYear(false); // false cho năm không nhuận
System.out.println("Ngày đầu tiên của tháng trong năm (không nhuận): " + firstDayOfYear);
// Trả về tháng đầu tiên của quý
Month firstMonthOfQuarter = month.firstMonthOfQuarter();
System.out.println("Tháng đầu tiên của quý: " + firstMonthOfQuarter);
}
}
Kết quả của chương trình là:
Giá trị của tháng theo ChronoField.MONTH_OF_YEAR (long): 7
Giá trị số nguyên của tháng: 7
Tên hiển thị của tháng: July
Trường MONTH_OF_YEAR có được hỗ trợ không: true
Phạm vi giá trị hợp lệ cho MONTH_OF_YEAR: 1 - 12
Số ngày trong tháng (không nhuận): 31
Số ngày tối đa trong tháng: 31
Số ngày tối thiểu trong tháng: 31
Ngày đầu tiên của tháng trong năm (không nhuận): 182
Tháng đầu tiên của quý: JULY
Trong ví dụ trên, mỗi phương thức đều được sử dụng đúng cách để lấy thông tin từ lớp Month, giúp bạn tránh lỗi và làm việc hiệu quả hơn với các đối tượng Month trong Java.
So sánh và kiểm tra
↳compareTo(Month other): So sánh hai Month với nhau.
↳ equals(Object obj): Kiểm tra hai Month có bằng nhau không.
Dưới đây là ví dụ về cách sử dụng hai phương thức compareTo() và equals() của lớp Month trong Java:
Ví dụ: Example.java
import java.time.Month;
public class Example {
public static void main(String[] args) {
// Tạo các đối tượng Month
Month month1 = Month.JANUARY;
Month month2 = Month.MARCH;
Month month3 = Month.JANUARY;
// So sánh hai Month với nhau
int comparison = month1.compareTo(month2);
if (comparison < 0) {
System.out.println(month1 + " trước " + month2);
} else if (comparison > 0) {
System.out.println(month1 + " sau " + month2);
} else {
System.out.println(month1 + " và " + month2 + " giống nhau");
}
// Kiểm tra hai Month có bằng nhau không
boolean isEqual = month1.equals(month3);
if (isEqual) {
System.out.println(month1 + " và " + month3 + " bằng nhau");
} else {
System.out.println(month1 + " và " + month3 + " không bằng nhau");
}
}
}
Kết quả của chương trình là:
JANUARY và JANUARY bằng nhau
Hy vọng ví dụ này giúp bạn hiểu rõ hơn về cách sử dụng các phương thức compareTo() và equals() trong lớp Month.
Điều chỉnh
↳ plus(long months): Cộng thêm một số tháng.
↳ minus(long months): Trừ đi một số tháng.
↳ adjustInto(Temporal temporal): Điều chỉnh một đối tượng thời gian khác về tháng này.
Dưới đây là ví dụ về cách sử dụng các phương thức plus(), minus(), và adjustInto() của lớp Month trong Java:
Ví dụ: Example.java
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.Temporal;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng Month
Month currentMonth = Month.JANUARY;
// Cộng thêm 3 tháng
Month newMonthPlus = currentMonth.plus(3);
System.out.println("Tháng sau khi cộng 3 tháng: " + newMonthPlus);
// Trừ đi 2 tháng
Month newMonthMinus = currentMonth.minus(2);
System.out.println("Tháng sau khi trừ 2 tháng: " + newMonthMinus);
// Điều chỉnh LocalDate để có tháng hiện tại
LocalDate date = LocalDate.of(2024, Month.MARCH, 15);
Temporal adjustedDate = currentMonth.adjustInto(date);
System.out.println("Ngày sau khi điều chỉnh về tháng hiện tại: " + adjustedDate);
}
}
Kết quả của chương trình là:
Tháng sau khi trừ 2 tháng: NOVEMBER Ngày sau khi điều chỉnh về tháng hiện tại: 2024-01-15
Ví dụ trên minh họa cách cộng, trừ tháng và điều chỉnh ngày theo tháng từ đối tượng Month.
Truy vấn
↳ query(TemporalQuery query): Thực hiện một truy vấn tùy chỉnh trên Month
Dưới đây là ví dụ về cách sử dụng phương thức query() với lớp Month trong Java:
Ví dụ: Example.java
import java.time.Month;
import java.time.format.TextStyle;
import java.time.temporal.TemporalQuery;
import java.util.Locale;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng Month
Month month = Month.MARCH;
// Truy vấn để lấy tên hiển thị của tháng
TemporalQuery<String> query = temporal -> {
if (temporal instanceof Month) {
return ((Month) temporal).getDisplayName(TextStyle.FULL, Locale.getDefault());
}
return null;
};
// Sử dụng phương thức query
String monthName = month.query(query);
// In kết quả
System.out.println("Tên tháng là: " + monthName);
}
}
Kết quả của chương trình là:
Trong ví dụ trên, phương thức query() được sử dụng để thực hiện truy vấn tùy chỉnh nhằm lấy tên hiển thị của tháng từ đối tượng Month.
Các ngoại lệ thường gặp khi sử dụng lớp Month 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: Ngày tháng không hợp lệ hoặc ngoài phạm vi cho phép.
↳ Ví dụ: Khi cố gắng truy cập ngày không tồn tại trong tháng, như ngày 30 tháng February (tháng 2) trong một năm không nhuận.
Ngoại lệ IllegalArgumentException
↳ Nguyên nhân: Số nguyên không hợp lệ được cung cấp cho phương thức Month.of(int month).
↳ Ví dụ: Khi gọi Month.of(13) vì số 13 không phải là tháng hợp lệ.
Ngoại lệ UnsupportedTemporalTypeException
↳ Nguyên nhân: Phương thức get hoặc range được gọi với một trường thời gian không được hỗ trợ bởi Month.
↳ Ví dụ: Khi gọi month.range(ChronoField.DAY_OF_MONTH) vì Month không hỗ trợ trường này.
Ngoại lệ ClassCastException
↳ Nguyên nhân: Cố gắng truy vấn hoặc chuyển đổi từ một đối tượng không phải là Month trong các phương thức như query(TemporalQuery query).
↳ Ví dụ: Khi thực hiện truy vấn với một đối tượng không phải là Month, như LocalDate mà không có xử lý hợp lệ.
Lưu ý:
Khi làm việc với lớp Month, việc kiểm tra dữ liệu đầu vào và các thao tác ngày tháng là rất quan trọng để tránh các ngoại lệ. Sử dụng các cơ chế kiểm tra lỗi và xử lý ngoại lệ phù hợp để cung cấp thông báo lỗi hoặc xử lý các tình huống bất thường, làm cho ứng dụng của bạn ổn định và dễ duy trì hơn.