Lớp java.time.format.DateTimeFormatter
(Khuyến Khích Sử Dụng)
DateTimeFormatter là một lớp được giới thiệu từ Java 8, cung cấp các phương thức tiện lợi để định dạng và phân tích ngày/giờ. Nó linh hoạt hơn so với lớp SimpleDateFormat cũ, hỗ trợ nhiều tính năng hữu ích.
Định dạng Ngày/Giờ theo nhiều cách:
↳ Sử dụng các hằng số được định sẵn, ví dụ ISO_LOCAL_DATE để định dạng theo chuẩn ISO.
↳ Sử dụng các ký tự mẫu để tạo mẫu định dạng riêng, tương tự như SimpleDateFormat nhưng mạnh mẽ hơn.
↳ Sử dụng các kiểu định dạng được bản địa hóa theo ngôn ngữ (locale), ví dụ long hoặc medium.
↳ Tạo Bộ Định dạng Phức tạp: Lớp DateTimeFormatterBuilder giúp bạn xây dựng các bộ định dạng phức tạp hơn nếu cần.
↳ Các Phương thức trên Lớp Ngày/Giờ: Các lớp ngày/giờ chính (như LocalDate, LocalTime, ...) cung cấp hai phương thức:
↳ format(DateTimeFormatter formatter): Định dạng ngày/giờ thành chuỗi văn bản.
↳ parse(CharSequence text, DateTimeFormatter formatter): Phân tích chuỗi văn bản thành đối tượng ngày/giờ.
Ⅰ. Các định dạng đã được định nghĩa sẵn
DateTimeFormatter cung cấp nhiều bộ định dạng ngày/giờ được xây dựng sẵn để bạn sử dụng ngay, giúp bạn tiết kiệm thời gian và đảm bảo tính chính xác khi định dạng. Dưới đây là danh sách các bộ định dạng:
Theo ngôn ngữ (Locale):
↳ ofLocalizedDate(dateStyle): Định dạng ngày theo kiểu ngắn, trung bình, đầy đủ... phụ thuộc vào ngôn ngữ (locale) đang dùng.
↳ ofLocalizedTime(timeStyle): Định dạng thời gian theo kiểu ngắn, trung bình, đầy đủ... phụ thuộc vào ngôn ngữ (locale) đang dùng.
↳ ofLocalizedDateTime(dateTimeStyle): Định dạng cả ngày và giờ theo kiểu ngắn, trung bình, đầy đủ... phụ thuộc vào ngôn ngữ (locale) đang dùng.
↳ ofLocalizedDateTime(dateStyle, timeStyle): Định dạng ngày và giờ riêng biệt theo kiểu ngắn, trung bình, đầy đủ... phụ thuộc vào ngôn ngữ (locale) đang dùng.
Theo tiêu chuẩn ISO:
↳ BASIC_ISO_DATE: Ngày theo định dạng ISO cơ bản (năm tháng ngày, không dấu phân cách).
↳ ISO_LOCAL_DATE: Ngày theo định dạng ISO (năm-tháng-ngày).
↳ ISO_OFFSET_DATE: Ngày theo định dạng ISO với múi giờ.
↳ ISO_DATE: Ngày theo định dạng ISO (có thể có hoặc không có múi giờ).
↳ ISO_LOCAL_TIME: Giờ theo định dạng ISO (không có múi giờ).
↳ ISO_OFFSET_TIME: Giờ theo định dạng ISO với múi giờ.
↳ ISO_TIME: Giờ theo định dạng ISO (có thể có hoặc không có múi giờ).
↳ ISO_LOCAL_DATE_TIME: Ngày giờ theo định dạng ISO (năm-tháng-ngày giờ:phút:giây).
↳ ISO_OFFSET_DATE_TIME: Ngày giờ theo định dạng ISO với múi giờ.
↳ ISO_ZONED_DATE_TIME: Ngày giờ theo định dạng ISO với cả múi giờ và vùng (ví dụ: "2011-12-03T10:15:30+01:00[Europe/Paris]").
↳ ISO_DATE_TIME: Ngày giờ theo định dạng ISO với ZoneId.
↳ ISO_ORDINAL_DATE: Năm và ngày trong năm (ví dụ: "2012-337").
↳ ISO_WEEK_DATE: Năm và tuần (ví dụ: "2012-W48-6").
↳ ISO_INSTANT: Ngày giờ của một thời điểm (ví dụ: "2011-12-03T10:15:30Z").
Theo tiêu chuẩn khác:
↳ RFC_1123_DATE_TIME:Định dạng ngày giờ theo chuẩn RFC 1123 (thường dùng trong HTTP).
Lưu ý:
Các bộ định dạng theo ngôn ngữ (locale) sẽ tự động sử dụng các ký hiệu định dạng phù hợp với ngôn ngữ đang cài đặt. Chọn bộ định dạng phù hợp với nhu cầu của bạn để đảm bảo tính chính xác và dễ đọc cho người dùng.
Ⅱ. Mẫu định dạng (Pattern) trong DateTimeFormatter
Mẫu định dạng (Pattern) là một chuỗi ký tự đặc biệt được sử dụng để xác định cách hiển thị các thành phần ngày/giờ trong DateTimeFormatter. Bạn có thể tạo DateTimeFormatter từ mẫu định dạng bằng các phương thức ofPattern(String) và ofPattern(String, Locale).
Ký tự mẫu (Pattern Letters):
Tất cả các ký tự từ 'A' đến 'Z' và 'a' đến 'z' được dành riêng để xác định các thành phần ngày/giờ.
Bảng dưới đây liệt kê các ký tự mẫu thường dùng và ý nghĩa của chúng:
Ký Hiệu | Ý Nghĩa | Ví Dụ |
---|---|---|
y | Năm | 2004; 04 |
M/L | Tháng trong năm | 7; 07; Jul; July |
d | Ngày trong tháng | 10 |
D | Ngày trong năm | 189 |
Q/q | Quý trong năm | 3; Q3 |
Y | Năm dựa trên tuần | 1996; 96 |
w | Tuần trong năm dựa trên tuần | 27 |
W | Tuần trong tháng | 4 |
E | Ngày trong tuần | Tue; Tuesday |
a | Thời gian trong ngày AM/PM | PM |
h | Giờ trong AM/PM (1-12) | 12 |
K | Giờ trong AM/PM (0-11) | 0 |
k | Giờ trong ngày (1-24) | 24 |
H | Giờ trong ngày (0-23) | 0 |
m | Phút trong giờ | 30 |
s | Giây trong phút | 55 |
S | Phân số của giây | 978 |
V | ID múi giờ | America/Los_Angeles; Z; -08:30 |
z | Tên múi giờ | Pacific Standard Time; PST |
O | Độ lệch múi giờ | GMT+8; GMT+08:00; UTC-08:00 |
X | Độ lệch múi giờ 'Z' cho số 0 | -08; -0830; -08:30; -083015 |
x | Độ lệch múi giờ | -08; -0830; -08:30; -083015 |
Z | Độ lệch múi giờ | +0000; -0800; -08:00 |
' | Ký tự thoát | ' |
[ và ] | Phần tùy chọn | [optional section start] |
# | Dành cho tương lai | # |
{và} | Dành cho tương lai | { |
Số lượng ký tự mẫu (pattern letters) trong DateTimeFormatter quyết định cách hiển thị giá trị ngày/giờ. Dưới đây là các quy tắc chi tiết:
Kiểu văn bản (Text):
↳ Ít hơn 4 ký tự mẫu: Sử dụng dạng ngắn (short form).
↳ Đúng 4 ký tự mẫu: Sử dụng dạng đầy đủ (full form).
↳ Đúng 5 ký tự mẫu: Sử dụng dạng hẹp (narrow form).
↳ Ký tự mẫu 'L', 'c', và 'q' xác định dạng độc lập (stand-alone form) của kiểu văn bản.
Số (Number):
↳ Một ký tự mẫu: Xuất giá trị với số chữ số ít nhất và không có dấu cách.
↳ Nhiều hơn một ký tự mẫu: Số chữ số sẽ được sử dụng làm chiều rộng của trường xuất ra, với giá trị đượcเติม 0 ở bên trái nếu cần.
↳ Có giới hạn về số lượng ký tự mẫu cho một số ký tự nhất định (xem bảng tài liệu).
Số/Kiểu văn bản:
↳ 3 ký tự mẫu trở lên: Áp dụng theo quy tắc Kiểu Văn Bản.
↳ Ít hơn 3 ký tự mẫu: Áp dụng theo quy tắc Số.
Phần thập phân của giây (Fraction):
↳ Xuất ra phần nano-of-second dưới dạng phần thập phân của giây.
↳ Số lượng ký tự mẫu từ 1 đến 9 ảnh hưởng đến số chữ số thập phân được hiển thị.
Năm (Year):
↳ Số lượng ký tự mẫu xác định chiều rộng tối thiểu của trường, ít hơn sẽ được 0.
↳ Hai ký tự mẫu: Sử dụng dạng rút gọn 2 chữ số (năm trong khoảng 2000-2099).
↳ Ít hơn 4 ký tự mẫu: Chỉ hiển thị dấu âm đối với năm âm.
↳ Bốn hoặc nhiều hơn ký tự mẫu: Luôn hiển thị dấu âm nếu cần.
Mã múi giờ (ZoneId):
↳ Hai ký tự mẫu: Xuất mã múi giờ (ví dụ: Europe/Paris).
↳ Khác hai ký tự mẫu: Báo lỗi IllegalArgumentException.
Tên múi giờ (Zone names):
↳ Ký tự mẫu 'z': Tên múi giờ có tính toán giờ mùa hè (daylight saving time).
↳ Một, hai hoặc ba ký tự mẫu: Tên viết tắt.
↳ Bốn ký tự mẫu: Tên đầy đủ.
↳ Năm hoặc nhiều hơn ký tự mẫu: Báo lỗi IllegalArgumentException.
↳ Ký tự mẫu 'v': Tên múi giờ không tính toán giờ mùa hè.
↳ Một hoặc bốn ký tự mẫu: Tên viết tắt hoặc đầy đủ.
↳ Hai, ba hoặc năm hoặc nhiều hơn ký tự mẫu: Báo lỗi IllegalArgumentException. đủ.
Độ lệch giờ (Offset):
↳ X/x (một đến sáu ký tự mẫu): Định dạng độ lệch giờ dựa trên số ký tự mẫu.
↳ X (với độ lệch bằng 0): Xuất 'Z'.
↳ x (với độ lệch bằng 0): Xuất '+00', '+0000', or '+00:00'.
↳ O (khác 0): Định dạng độ lệch giờ được bản địa hóa.
↳ Z (một đến năm ký tự mẫu): Định dạng độ lệch giờ dựa trên số ký tự mẫu.
↳ Z (với độ lệch bằng 0): Xuất 'Z' hoặc văn bản được bản địa hóa.
Phần tùy chọn (Optional section):
↳ Hoạt động giống như phương thức optionalStart và optionalEnd trong DateTimeFormatterBuilder.
↳ Kiểu Chèn Khoảng Trống (Pad modifier):
↳ Ký tự mẫu này yêu cầu ký tự mẫu kế tiếp được chèn thêm khoảng trống bên trái cho đủ chiều rộng.
Ký tự không nhận diện:
↳ Bị báo lỗi.
Ký tự khác:
↳ Được xuất ra trực tiếp ngoại trừ '[', ']', '{' '}', '#' và dấu nháy đơn.
↳ Nên dùng dấu nháy đơn để bao quanh các ký tự bạn muốn xuất trực tiếp để tránh lỗi về sau.
Ⅲ. Phân giải chuỗi thành Ngày/Giờ trong DateTimeFormatter
Phân giải (Parsing) chuỗi văn bản thành ngày/giờ là một quá trình hai bước trong DateTimeFormatter:
Phân tích cú pháp (Parse): Sử dụng mẫu định dạng được cung cấp bởi DateTimeFormatter để phân tích chuỗi văn bản thành một bảng giá trị theo từng trường (field), một ZoneId (múi giờ) và một Chronology (hệ thống lịch sử dụng).
Giải quyết (Resolve): Xác thực, kết hợp và đơn giản hóa các trường đã phân tích thành các đối tượng ngày/giờ hữu ích hơn.
Các phương thức phân giải:
↳ Lớp DateTimeFormatter cung cấp 5 phương thức phân giải.
↳ Bốn phương thức thực hiện cả hai bước phân tích cú pháp và giải quyết.
↳ Phương thức thứ năm, parseUnresolved(CharSequence, ParsePosition), chỉ thực hiện phân tích cú pháp, trả về kết quả chưa được giải quyết.
Các phương thức phân giải:
↳ Quá trình giải quyết được điều khiển bởi hai tham số.
↳ ResolverStyle là một kiểu enum cung cấp ba cách tiếp cận khác nhau: nghiêm ngặt (strict), thông minh (smart - mặc định), và linh hoạt (lenient).
↳ Bạn có thể tùy chỉnh kiểu giải quyết bằng phương thức withResolverStyle(ResolverStyle).
↳ Lọc Trường cần Giải Quyết (withResolverFields): Tham số withResolverFields(TemporalField...) cho phép lọc các trường sẽ được giải quyết trước khi bắt đầu quá trình giải quyết.
↳ Ví dụ: Nếu bộ định dạng đã phân tích năm, tháng, ngày và ngày trong năm, thì có hai cách tiếp cận để giải quyết thành ngày: (năm + tháng + ngày) và (năm + ngày trong năm). Tham số withResolverFields cho phép bạn chọn một trong hai cách tiếp cận.
Các bước giải quyết:
↳ 1. Xác định hệ thống lịch sử dụng (Chronology).
↳ 2. Giải quyết các trường ngày (ChronoField).
↳ 3. Giải quyết các trường giờ (ChronoField).
↳ 4. Xử lý các trường không phải ChronoField.
↳ 5. Giải quyết lại các trường ngày và giờ ChronoField.
↳ 6. Tạo đối tượng LocalTime nếu có ít nhất giờ.
↳ 7. Kiểm tra chéo các trường chưa giải quyết với ngày/giờ đã giải quyết (đảm bảo tính hợp lệ).
↳ 8. Nếu có quá nhiều ngày được phân tích, chúng sẽ được thêm vào ngày hiện có (nếu có).
↳ 9. Nếu có trường giây nhưng không có LocalTime, giải quyết để đảm bảo có các giá trị mili giây, micro giây và nano giây.
↳ 10. Nếu cả ngày và giờ được phân tích và có múi giờ hoặc vùng, tạo trường ChronoField.INSTANT_SECONDS.
Lưu ý:
↳ DateTimeFormatter là lớp bất biến và an toàn với luồng (thread-safe).
Ⅳ. Các trường (Field) có sẵn trong DateTimeFormatter
Lớp DateTimeFormatter cung cấp một số bộ định dạng mặc định thường dùng cho các định dạng ngày/giờ khác nhau. Dưới đây là các bộ định dạng mặc định thường dùng cho các định dạng ngày/giờ:
↳ static final DateTimeFormatter BASIC_ISO_DATE: Định dạng ngày theo ISO không có offset, ví dụ: '20111203'.
↳ static final DateTimeFormatter ISO_DATE: Định dạng ngày theo ISO với offset nếu có, ví dụ: '2011-12-03' hoặc '2011-12-03+01:00'.
↳ static final DateTimeFormatter ISO_DATE_TIME: Định dạng ngày-giờ theo ISO với offset và vùng nếu có, ví dụ: '2011-12-03T10:15:30' hoặc '2011-12-03T10:15:30+01:00[Europe/Paris]'.
↳ static final DateTimeFormatter ISO_INSTANT: Định dạng thời điểm theo ISO trong UTC, ví dụ: '2011-12-03T10:15:30Z'.
↳ static final DateTimeFormatter ISO_LOCAL_DATE: Định dạng ngày theo ISO không có offset, ví dụ: '2011-12-03'.
↳ static final DateTimeFormatter ISO_LOCAL_DATE_TIME: Định dạng ngày-giờ theo ISO không có offset, ví dụ: '2011-12-03T10:15:30'.
↳ static final DateTimeFormatter ISO_LOCAL_TIME: Định dạng thời gian theo ISO không có offset, ví dụ: '10:15' hoặc '10:15:30'.
↳ static final DateTimeFormatter ISO_OFFSET_DATE: Định dạng ngày theo ISO với offset, ví dụ: '2011-12-03+01:00'.
↳ static final DateTimeFormatter ISO_OFFSET_DATE_TIME: Định dạng ngày-giờ theo ISO với offset, ví dụ: '2011-12-03T10:15:30+01:00'.
↳ static final DateTimeFormatter ISO_OFFSET_TIME: Định dạng thời gian theo ISO với offset, ví dụ: '10:15+01:00' hoặc '10:15:30+01:00'.
↳ static final DateTimeFormatter ISO_ORDINAL_DATE: Định dạng ngày theo ISO với ngày thứ trong năm, ví dụ: '2012-337'.
↳ static final DateTimeFormatter ISO_TIME: Định dạng thời gian theo ISO với offset nếu có, ví dụ: '10:15', '10:15:30' hoặc '10:15:30+01:00'.
↳ static final DateTimeFormatter ISO_WEEK_DATE: Định dạng ngày theo tuần theo ISO không có offset, ví dụ: '2012-W48-6'.
↳ static final DateTimeFormatter ISO_ZONED_DATE_TIME: Định dạng ngày-giờ theo ISO với offset và vùng, ví dụ: '2011-12-03T10:15:30+01:00[Europe/Paris]'.
↳ static final DateTimeFormatter RFC_1123_DATE_TIME: Định dạng ngày-giờ theo RFC-1123, ví dụ: 'Tue, 3 Jun 2008 11:05:30 GMT'.
Bạn có thể sử dụng các bộ định dạng này để format (định dạng) ngày/giờ hoặc parse (phân tích) chuỗi văn bản thành ngày/giờ.
Ⅴ. Khai báo lớp DateTimeFormatter trong Java
Để sử dụng lớp DateTimeFormatter 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.format.DateTimeFormatter;
Cú pháp khai báo lớp DateTimeFormatter:
Cú pháp
public final class DateTimeFormatter
extends Object
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ừ DateTimeFormatter.
↳ class DateTimeFormatter: Khai báo một lớp có tên là DateTimeFormatter. Lớp này được sử dụng để định dạng và phân tích ngày và giờ. Nó cung cấp các phương thức để chuyển đổi giữa các đối tượng ngày/giờ và chuỗi văn bản, cũng như để tạo các mẫu định dạng tùy chỉnh.
↳ extends Object: Đây là phần mở rộng của lớp DateTimeFormatter. Trong Java, tất cả các lớp đều kế thừa từ lớp Object (lớp cơ sở chung cho tất cả các lớp). Khi một lớp kế thừa từ Object, nó có thể sử dụng các phương thức của lớp Object, như toString(), equals(), hashCode(), và clone().
Ⅵ. Các phương thức của java.time.format.DateTimeFormatter
Lớp DateTimeFormatter cung cấp nhiều phương thức để định dạng và phân tích ngày/giờ theo chuẩn quốc tế. 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 DateTimeFormatter. Dưới đây là cách phân nhóm các phương thức phổ biến của lớp DateTimeFormatter:
Phương thức tạo đối tượng DateTimeFormatter
↳ static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle): Trả về định dạng ngày cụ thể theo locale cho lịch ISO.
↳ static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle): Trả về bộ định dạng ngày-giờ cụ thể theo locale cho lịch ISO.
↳ static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle): Trả về định dạng ngày và giờ cụ thể theo locale cho lịch ISO.
↳ static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle): Trả về định dạng giờ cụ thể theo locale cho lịch ISO.
↳ static DateTimeFormatter ofPattern(String pattern): Tạo bộ định dạng sử dụng mẫu được chỉ định.
↳ static DateTimeFormatter ofPattern(String pattern, Locale locale): Tạo bộ định dạng sử dụng mẫu và locale được chỉ định.
Dưới đây là một ví dụ về việc sử dụng các phương thức tạo đối tượng DateTimeFormatter trong Java:
Ví dụ: Example.java
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Example {
public static void main(String[] args) {
// Tạo định dạng ngày cụ thể theo locale cho lịch ISO
DateTimeFormatter formatterDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
LocalDate date = LocalDate.now();
String formattedDate = date.format(formatterDate);
System.out.println("Ngày định dạng theo locale: " + formattedDate);
// Tạo bộ định dạng ngày-giờ cụ thể theo locale cho lịch ISO
DateTimeFormatter formatterDateTime = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
LocalDateTime dateTime = LocalDateTime.now();
String formattedDateTime = dateTime.format(formatterDateTime);
System.out.println("Ngày-giờ định dạng theo locale: " + formattedDateTime);
// Tạo định dạng ngày và giờ cụ thể theo locale cho lịch ISO
DateTimeFormatter formatterDateTimeCustom = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT);
String formattedDateTimeCustom = dateTime.format(formatterDateTimeCustom);
System.out.println("Ngày và giờ định dạng theo locale: " + formattedDateTimeCustom);
// Tạo bộ định dạng sử dụng mẫu được chỉ định
DateTimeFormatter formatterPattern = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String formattedPatternDate = date.format(formatterPattern);
System.out.println("Ngày định dạng theo mẫu: " + formattedPatternDate);
// Tạo định dạng giờ cụ thể theo locale cho lịch ISO
DateTimeFormatter formatterTime = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
String formattedTime = dateTime.toLocalTime().format(formatterTime);
System.out.println("Giờ định dạng theo locale: " + formattedTime);
// Tạo bộ định dạng sử dụng mẫu và locale được chỉ định
DateTimeFormatter formatterPatternLocale = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.FRENCH);
String formattedPatternLocale = date.format(formatterPatternLocale);
System.out.println("Ngày định dạng theo mẫu và locale: " + formattedPatternLocale);
}
}
Kết quả của chương trình là:
Ngày-giờ định dạng theo locale: 7/25/24, 5:24 PM
Ngày và giờ định dạng theo locale: 7/25/24, 5:24 PM
Ngày định dạng theo mẫu: 25/07/2024
Giờ định dạng theo locale: 5:24 PM
Ngày định dạng theo mẫu và locale: 25 juillet 2024
Trong ví dụ trên, mỗi phương thức DateTimeFormatter được sử dụng để định dạng ngày và giờ theo các mẫu và locale khác nhau.
Phương thức định dạng
↳ String format(TemporalAccessor temporal): Định dạng một đối tượng ngày-giờ bằng cách sử dụng bộ định dạng này.
↳ void formatTo(TemporalAccessor temporal, Appendable appendable): Định dạng một đối tượng ngày-giờ và ghi vào đối tượng Appendable được cung cấp.
Dưới đây là ví dụ về hai phương thức format() và formatTo() của lớp DateTimeFormatter trong cùng một class:
Ví dụ: Example.java
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng DateTimeFormatter với mẫu định dạng
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
// Tạo một đối tượng LocalDateTime để định dạng
LocalDateTime dateTime = LocalDateTime.now();
// Sử dụng phương thức format để định dạng và in ra kết quả
String formattedDateTime = formatter.format(dateTime);
System.out.println("Ngày-giờ định dạng: " + formattedDateTime);
// Sử dụng phương thức formatTo để định dạng và ghi vào StringWriter
StringWriter writer = new StringWriter();
formatter.formatTo(dateTime, writer);
System.out.println("Ngày-giờ ghi vào StringWriter: " + writer.toString());
}
}
Kết quả của chương trình là:
Ngày-giờ ghi vào StringWriter: 25/07/2024 17:31:44
Ví dụ trên sử dụng format để định dạng và in ngày-giờ ra console, và phương thức formatTo() để định dạng và ghi ngày-giờ vào StringWriter.
Phương thức lấy thông tin
↳ Chronology getChronology(): Lấy lịch trình (chronology) được sử dụng trong quá trình định dạng.
↳ DecimalStyle getDecimalStyle(): Lấy kiểu số thập phân (DecimalStyle) được sử dụng trong quá trình định dạng.
↳ Locale getLocale(): Lấy ngôn ngữ và vùng (locale) được sử dụng trong quá trình định dạng.
↳ Set<TemporalField> getResolverFields(): Lấy các trường phân giải (resolver fields) được sử dụng trong quá trình phân tích.
↳ ResolverStyle getResolverStyle(): Lấy kiểu phân giải (resolver style) được sử dụng trong quá trình phân tích.
↳ ZoneId getZone(): Lấy múi giờ (zone) được sử dụng trong quá trình định dạng.
Dưới đây là ví dụ về các phương thức lấy thông tin từ lớp DateTimeFormatter trong cùng một class:
Ví dụ: Example.java
import java.time.ZoneId;
import java.time.chrono.Chronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.format.ResolverStyle;
import java.time.temporal.TemporalField;
import java.util.Locale;
import java.util.Set;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng DateTimeFormatter với mẫu định dạng
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")
.withLocale(Locale.FRANCE)
.withZone(ZoneId.of("Europe/Paris"));
// Lấy và in các thông tin từ DateTimeFormatter
Chronology chronology = formatter.getChronology();
DecimalStyle decimalStyle = formatter.getDecimalStyle();
Locale locale = formatter.getLocale();
Set<TemporalField> resolverFields = formatter.getResolverFields();
ResolverStyle resolverStyle = formatter.getResolverStyle();
ZoneId zone = formatter.getZone();
System.out.println("Lịch trình : " + chronology);
System.out.println("Kiểu số thập phân : " + decimalStyle);
System.out.println("Ngôn ngữ và vùng : " + locale);
System.out.println("Các trường phân giải : " + resolverFields);
System.out.println("Kiểu phân giải : " + resolverStyle);
System.out.println("Múi giờ : " + zone);
}
}
Kết quả của chương trình là:
Kiểu số thập phân : DecimalStyle[0+-.]
Ngôn ngữ và vùng : fr_FR
Các trường phân giải : null
Kiểu phân giải : SMART
Múi giờ : Europe/Paris
Ví dụ trên sử dụng các phương thức để lấy thông tin từ DateTimeFormatter, bao gồm lịch trình, kiểu số thập phân, ngôn ngữ và vùng, các trường phân giải, kiểu phân giải và múi giờ.
Phương thức phân tích
↳ TemporalAccessor parse(CharSequence text): Phân tích văn bản để tạo đối tượng ngày-giờ.
↳ TemporalAccessor parse(CharSequence text, ParsePosition position): Phân tích văn bản sử dụng bộ định dạng này, cho phép kiểm soát vị trí văn bản.
↳ <T> T parse(CharSequence text, TemporalQuery<T> query): Phân tích văn bản để tạo đối tượng của loại cụ thể được chỉ định.
↳ TemporalAccessor parseBest(CharSequence text, TemporalQuery<?>... queries): Phân tích văn bản để tạo đối tượng của một trong các loại được chỉ định.
↳ static final TemporalQuery<Period> parsedExcessDays(): Truy vấn cung cấp số ngày thừa đã được phân tích.
↳ static final TemporalQuery<Boolean> parsedLeapSecond(): Truy vấn cung cấp thông tin về việc có phân tích giây nhuận hay không.
↳ TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position): Phân tích văn bản sử dụng bộ định dạng này mà không giải quyết kết quả, dành cho các trường hợp sử dụng nâng cao.
Dưới đây là ví dụ về các phương thức phân tích từ lớp DateTimeFormatter trong cùng một class:
Ví dụ: Example.java
import java.text.ParsePosition;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// Phân tích văn bản để tạo đối tượng ngày-giờ
TemporalAccessor parsedDate = formatter.parse("2024-07-25T15:30:00");
System.out.println("Đối tượng ngày-giờ phân tích được: " + parsedDate);
// Phân tích văn bản và kiểm soát vị trí văn bản
ParsePosition position = new ParsePosition(0);
TemporalAccessor parsedWithPosition = formatter.parse("2024-07-25T15:30:00", position);
System.out.println("Vị trí phân tích: " + position.getIndex());
System.out.println("Đối tượng ngày-giờ phân tích với vị trí: " + parsedWithPosition);
// Phân tích văn bản để tạo đối tượng của loại cụ thể được chỉ định
TemporalAccessor parsedWithQuery = formatter.parse("2024-07-25T15:30:00", temporal -> temporal);
System.out.println("Đối tượng ngày-giờ phân tích với truy vấn: " + parsedWithQuery);
// Phân tích văn bản để tạo đối tượng của một trong các loại được chỉ định
TemporalAccessor parsedBest = formatter.parseBest("2024-07-25T15:30:00", TemporalQueries.localDate(), TemporalQueries.localTime());
System.out.println("Đối tượng ngày-giờ phân tích tốt nhất: " + parsedBest);
// Truy vấn số ngày thừa đã được phân tích
TemporalQuery<Period> excessDaysQuery = DateTimeFormatter.parsedExcessDays();
Period excessDays = excessDaysQuery.queryFrom(parsedDate);
System.out.println("Số ngày thừa đã được phân tích: " + excessDays);
// Truy vấn thông tin về việc có phân tích giây nhuận hay không
TemporalQuery<Boolean> leapSecondQuery = DateTimeFormatter.parsedLeapSecond();
Boolean leapSecond = leapSecondQuery.queryFrom(parsedDate);
System.out.println("Có phân tích giây nhuận không: " + leapSecond);
// Phân tích văn bản mà không giải quyết kết quả
TemporalAccessor unresolvedParsed = formatter.parseUnresolved("2024-07-25T15:30:00", position);
System.out.println("Đối tượng ngày-giờ phân tích chưa giải quyết: " + unresolvedParsed);
}
}
Kết quả của chương trình là:
Vị trí phân tích: 19
Đối tượng ngày-giờ phân tích với vị trí: ,ISO resolved to 2024-07-25T15:30
Đối tượng ngày-giờ phân tích với truy vấn: ,ISO resolved to 2024-07-25T15:30
Đối tượng ngày-giờ phân tích tốt nhất: 2024-07-25
Số ngày thừa đã được phân tích: P0D
Có phân tích giây nhuận không: false
Đối tượng ngày-giờ phân tích chưa giải quyết: null
Ví dụ trên sử dụng các phương thức phân tích của DateTimeFormatter để tạo và xử lý đối tượng ngày-giờ từ văn bản, bao gồm việc phân tích với vị trí, phân tích loại cụ thể, truy vấn ngày thừa và giây nhuận, và phân tích mà không giải quyết kết quả.
Phương thức chuyển đổi
↳ Format toFormat(): Trả về bộ định dạng này dưới dạng đối tượng java.text.Format.
↳ Format toFormat(TemporalQuery<?> parseQuery): Trả về bộ định dạng này dưới dạng đối tượng java.text.Format sẽ phân tích bằng truy vấn cụ thể.
↳ String toString(): Trả về mô tả của các bộ định dạng cơ bản.
Dưới đây là ví dụ về các phương thức chuyển đổi từ lớp DateTimeFormatter trong java:
Ví dụ: Example.java
import java.text.Format;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalQueries;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// Chuyển đổi bộ định dạng này thành đối tượng java.text.Format
Format javaTextFormat = formatter.toFormat();
System.out.println("Đối tượng java.text.Format: " + javaTextFormat);
// Chuyển đổi bộ định dạng này thành đối tượng java.text.Format với truy vấn cụ thể
Format javaTextFormatWithQuery = formatter.toFormat(TemporalQueries.localDate());
System.out.println("Đối tượng java.text.Format với truy vấn: " + javaTextFormatWithQuery);
// Trả về mô tả của các bộ định dạng cơ bản
String description = formatter.toString();
System.out.println("Mô tả của bộ định dạng: " + description);
}
}
Kết quả của chương trình là:
Đối tượng java.text.Format với truy vấn: java.time.format.DateTimeFormatter$ClassicFormat@1fb3ebeb
Mô tả của bộ định dạng: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Ví dụ trên cho thấy cách sử dụng các phương thức chuyển đổi của lớp DateTimeFormatter trong Java.
Phương thức sao chép và thay đổi
↳ DateTimeFormatter withChronology(Chronology chrono): Trả về bản sao của bộ định dạng này với lịch trình mới.
↳ DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle): Trả về bản sao của bộ định dạng này với kiểu số thập phân mới.
↳ DateTimeFormatter withLocale(Locale locale): Trả về bản sao của bộ định dạng này với locale mới.
↳ DateTimeFormatter withResolverFields(TemporalField... resolverFields): Trả về bản sao của bộ định dạng này với tập hợp các trường phân giải mới.
↳ DateTimeFormatter withResolverFields(Set<TemporalField> resolverFields): Trả về bản sao của bộ định dạng này với tập hợp các trường phân giải mới.
↳ DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle): Trả về bản sao của bộ định dạng này với kiểu phân giải mới.
↳ DateTimeFormatter withZone(ZoneId zone): Trả về bản sao của bộ định dạng này với múi giờ mới.
Dưới đây là ví dụ về các phương thức sao chép và thay đổi của lớp DateTimeFormatter trong Java:
Ví dụ: Example.java
import java.time.ZoneId;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DecimalStyle;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalField;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
public class Example {
public static void main(String[] args) {
// Tạo đối tượng DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
// Sao chép với lịch trình mới
DateTimeFormatter withChronology = formatter.withChronology(IsoChronology.INSTANCE);
System.out.println("Bản sao với lịch trình mới: " + withChronology);
// Sao chép với kiểu số thập phân mới
DateTimeFormatter withDecimalStyle = formatter.withDecimalStyle(DecimalStyle.STANDARD);
System.out.println("Bản sao với kiểu số thập phân mới: " + withDecimalStyle);
// Sao chép với locale mới
DateTimeFormatter withLocale = formatter.withLocale(Locale.FRENCH);
System.out.println("Bản sao với locale mới: " + withLocale);
// Sao chép với tập hợp các trường phân giải mới
Set<TemporalField> resolverFields = new HashSet<>();
resolverFields.add(ChronoField.YEAR);
DateTimeFormatter withResolverFields = formatter.withResolverFields(resolverFields);
System.out.println("Bản sao với tập hợp các trường phân giải mới: " + withResolverFields);
// Sao chép với kiểu phân giải mới
DateTimeFormatter withResolverStyle = formatter.withResolverStyle(ResolverStyle.STRICT);
System.out.println("Bản sao với kiểu phân giải mới: " + withResolverStyle);
// Sao chép với múi giờ mới
DateTimeFormatter withZone = formatter.withZone(ZoneId.of("Asia/Ho_Chi_Minh"));
System.out.println("Bản sao với múi giờ mới: " + withZone);
}
}
Kết quả của chương trình là:
Bản sao với lịch trình mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Bản sao với kiểu số thập phân mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Bản sao với locale mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Bản sao với tập hợp các trường phân giải mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Bản sao với kiểu phân giải mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Bản sao với múi giờ mới: Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)
Ví dụ trên cho thấy cách sử dụng các phương thức sao chép và thay đổi của lớp DateTimeFormatter trong Java.
Các ngoại lệ thường gặp khi sử dụng lớp DateTimeFormatter 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ệ DateTimeParseException
↳ Nguyên nhân: Xảy ra khi văn bản không thể phân tích được thành một đối tượng ngày-giờ hợp lệ. Điều này có thể do định dạng không khớp với mẫu hoặc giá trị ngày-giờ không hợp lệ.
↳ Ví dụ: Cố gắng phân tích chuỗi "2024-02-30" với mẫu "yyyy-MM-dd" sẽ gây ra lỗi vì ngày 30 không tồn tại trong tháng 2.
Ngoại lệ DateTimeException
↳ Nguyên nhân: Xảy ra khi có lỗi trong xử lý ngày-giờ, chẳng hạn như khi cố gắng sử dụng một lịch trình không hỗ trợ hoặc khi giá trị ngày-giờ không hợp lệ.
↳ Ví dụ: Sử dụng một mẫu định dạng không hợp lệ như "yyyy-MM-dd-xyz".
Ngoại lệ IllegalArgumentException
↳ Nguyên nhân: Xảy ra khi các tham số truyền vào không hợp lệ. Điều này có thể xảy ra khi mẫu định dạng không hợp lệ hoặc khi các thuộc tính không hợp lệ được cung cấp.
↳ Ví dụ: Truyền vào một mẫu không hợp lệ cho phương thức DateTimeFormatter.ofPattern() như "dd/MM/yyyy" khi mẫu yêu cầu một định dạng khác.
Ngoại lệ UnsupportedTemporalTypeException
↳ Nguyên nhân: Xảy ra khi một kiểu thời gian không được hỗ trợ bởi DateTimeFormatter được sử dụng. Ví dụ, cố gắng sử dụng DateTimeFormatter để định dạng một kiểu thời gian không tương thích như Year khi chỉ hỗ trợ LocalDate hoặc LocalDateTime.
↳ Ví dụ: Sử dụng DateTimeFormatter với một đối tượng Year mà không có sự hỗ trợ phù hợp trong mẫu định dạng.
Lưu ý:
Khi làm việc với DateTimeFormatter, đảm bảo chuỗi đầu vào có định dạng chính xác và phù hợp với mẫu định dạng mong muốn là điều cần thiết để tránh phát sinh ngoại lệ. Việc sử dụng các khối try-catch giúp xử lý các tình huống định dạng không hợp lệ, cung cấp thông báo lỗi rõ ràng, hoặc thực hiện các biện pháp khắc phục. Điều này không chỉ giúp ứng dụng hoạt động ổn định mà còn nâng cao tính dễ dàng bảo trì và trải nghiệm người dùng.