1. DateTimeFormatter: là gì và dùng để làm gì
Trong các chương trình thực tế, ngày tháng hiếm khi chỉ tồn tại bên trong mã. Thông thường chúng ta cần:
- Chuyển thành chuỗi để in ra console, màn hình hoặc tệp (ví dụ, "01.06.2025 14:30").
- Phân tích chuỗi, tức là biến chuỗi do người dùng nhập hoặc đến từ tệp trở lại thành đối tượng ngày/giờ.
Để làm điều đó, Java có một công cụ mạnh mẽ và tiện dụng — lớp java.time.format.DateTimeFormatter.
Có thể xem DateTimeFormatter như một “người phiên dịch” giữa các đối tượng thời gian (LocalDate, LocalDateTime, ZonedDateTime, Instant, v.v.) và các chuỗi. Nó có thể:
- Biến các đối tượng ngày/giờ thành chuỗi theo định dạng mong muốn (format — định dạng).
- Biến chuỗi thành các đối tượng ngày/giờ (parse — phân tích).
2. Các formatter tiêu chuẩn: nhanh và đơn giản
Java đã chuẩn bị sẵn cho chúng ta một bộ formatter tiêu chuẩn, bao phủ các định dạng ISO phổ biến nhất (các tiêu chuẩn quốc tế cho ngày và giờ).
Một vài cái tiêu biểu:
| Formatter | Ví dụ chuỗi | Mô tả |
|---|---|---|
|
2025-06-01 | Chỉ ngày (năm-tháng-ngày) |
|
14:30:00 | Chỉ thời gian (giờ:phút:giây) |
|
2025-06-01T14:30:00 | Ngày và giờ không có múi giờ |
|
2025-06-01T14:30:00+03:00[Europe/Minsk] | Ngày, giờ và múi giờ |
Ví dụ sử dụng formatter tiêu chuẩn
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class FormatterDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.now();
// Định dạng ngày thành chuỗi
String text = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(text); // Ví dụ: 2025-06-01
// Phân tích chuỗi về lại ngày
LocalDate parsed = LocalDate.parse("2025-06-01", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(parsed); // 2025-06-01
}
}
Ẩn dụ
Nếu Java là một quán cà phê, các formatter tiêu chuẩn chính là “americano”, “latte” và “espresso”. Nhanh, chuẩn mực, nhưng đôi khi bạn sẽ muốn thứ gì đó đặc biệt!
3. Mẫu tùy chỉnh: DateTimeFormatter.ofPattern
Đôi khi các định dạng tiêu chuẩn là chưa đủ. Ví dụ, bạn cần in ngày ở dạng "01.06.2025 14:30", chứ không phải "2025-06-01T14:30:00". Khi đó ta có thể tạo mẫu riêng bằng phương thức DateTimeFormatter.ofPattern(String pattern).
Cú pháp mẫu
Trong mẫu có các ký tự đặc biệt:
- y — năm (yyyy — 2025)
- M — tháng (MM — 06)
- d — ngày (dd — 01)
- H — giờ (định dạng 24 giờ, HH — 14)
- m — phút (mm — 30)
- s — giây (ss — 00)
Ví dụ về mẫu
| Mẫu | Kết quả ví dụ |
|---|---|
|
01.06.2025 |
|
2025/06/01 |
|
01.06.2025 14:30 |
|
2025-06-01 14:30:00 |
|
1 tháng 6 2025 (với locale tiếng Nga) |
Ví dụ: định dạng ngày và giờ
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class CustomFormatDemo {
public static void main(String[] args) {
LocalDateTime dt = LocalDateTime.of(2025, 6, 1, 14, 30);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
String text = dt.format(formatter);
System.out.println(text); // 01.06.2025 14:30
}
}
Ví dụ: phân tích chuỗi thành ngày
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dt = LocalDateTime.parse(input, formatter);
System.out.println(dt); // 2025-06-01T14:30
}
}
Lưu ý: mẫu phải khớp chính xác với chuỗi! Nếu chuỗi có giây — hãy thêm :ss vào mẫu.
4. Định dạng: biến ngày/giờ thành chuỗi
Sơ đồ tổng quát
- Tạo đối tượng cần thiết (LocalDate, LocalDateTime, ZonedDateTime, v.v.).
- Tạo hoặc chọn formatter phù hợp.
- Gọi phương thức format(DateTimeFormatter) trên đối tượng, nhận về chuỗi.
Ví dụ: in ngày theo nhiều định dạng
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class MultiFormatDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
// Chuẩn ISO
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE)); // 2025-06-01
// Định dạng tùy chỉnh
DateTimeFormatter rusFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
System.out.println(date.format(rusFormat)); // 01.06.2025
// Kiểu Mỹ (US)
DateTimeFormatter usFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy");
System.out.println(date.format(usFormat)); // 06/01/2025
}
}
Định dạng thời gian
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class TimeFormatDemo {
public static void main(String[] args) {
LocalTime time = LocalTime.of(14, 30, 5);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(time.format(formatter)); // 14:30:05
}
}
5. Phân tích chuỗi: biến chuỗi thành ngày/giờ
Sơ đồ tổng quát
- Nhận chuỗi (ví dụ, từ người dùng).
- Tạo formatter với cùng mẫu như chuỗi.
- Gọi phương thức tĩnh parse() hoặc phương thức parse() của formatter.
Ví dụ: phân tích ngày
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class ParseDateDemo {
public static void main(String[] args) {
String input = "01.06.2025";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date); // 2025-06-01
}
}
Ví dụ: phân tích ngày và giờ
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ParseDateTimeDemo {
public static void main(String[] args) {
String input = "01.06.2025 14:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(input, formatter);
System.out.println(dateTime); // 2025-06-01T14:30
}
}
6. Xử lý lỗi khi phân tích chuỗi
Parsing có thể khó chịu. Nếu chuỗi không khớp với mẫu, Java sẽ ném ngoại lệ DateTimeParseException. Đây là tình huống bình thường, chẳng hạn khi người dùng nhập sai ngày.
Ví dụ: xử lý lỗi khi phân tích
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public class ParseErrorDemo {
public static void main(String[] args) {
String input = "32.13.2025"; // Ngày không hợp lệ
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
try {
LocalDate date = LocalDate.parse(input, formatter);
System.out.println(date);
} catch (DateTimeParseException ex) {
System.out.println("Lỗi phân tích chuỗi: " + ex.getMessage());
}
}
}
Quan trọng: luôn xử lý những lỗi như vậy khi làm việc với dữ liệu nhập từ người dùng!
7. Thực hành: chuyển đổi ngày cho người dùng
Giả sử, trong ứng dụng học tập của chúng ta có yêu cầu: người dùng nhập ngày sinh theo định dạng "dd.MM.yyyy", và chương trình phải xuất ngày theo định dạng "yyyy/MM/dd", đồng thời hiển thị thứ trong tuần.
Ví dụ
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Scanner;
public class BirthdayFormatDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Nhập ngày sinh (dd.MM.yyyy): ");
String input = scanner.nextLine();
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy");
DateTimeFormatter outputFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd");
try {
LocalDate birthday = LocalDate.parse(input, inputFormat);
String formatted = birthday.format(outputFormat);
System.out.println("Ngày của bạn ở định dạng mới: " + formatted);
System.out.println("Thứ trong tuần: " + birthday.getDayOfWeek()); // Ví dụ: SATURDAY
} catch (DateTimeParseException ex) {
System.out.println("Lỗi: định dạng ngày không hợp lệ!");
}
}
}
8. Bản địa hóa: ngôn ngữ ảnh hưởng đến định dạng như thế nào
Với DateTimeFormatter, bạn không chỉ thay đổi thứ tự số mà còn có thể in tên tháng bằng chữ, thứ trong tuần, v.v. Locale (ngôn ngữ và vùng) sẽ được tính đến.
Ví dụ: in tên tháng bằng chữ (tiếng Nga)
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", new Locale("ru"));
System.out.println(date.format(formatter)); // 1 tháng 6 2025
}
}
Ví dụ: locale tiếng Anh
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class LocaleEnDemo {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2025, 6, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d MMMM yyyy", Locale.ENGLISH);
System.out.println(date.format(formatter)); // 1 June 2025
}
}
Mẹo: nếu bạn muốn tháng và thứ hiển thị đúng ngôn ngữ — hãy chỉ định locale một cách tường minh!
9. Những lỗi thường gặp khi định dạng và phân tích chuỗi ngày
Lỗi № 1: Mẫu không khớp với chuỗi.
Nếu chuỗi "01.06.2025 14:30", còn mẫu là "dd.MM.yyyy", việc phân tích sẽ thất bại. Mẫu phải khớp chính xác với chuỗi.
Lỗi № 2: Nhầm ký tự mẫu.
MM — tháng, mm — phút. Nếu viết "dd.mm.yyyy", Java sẽ hiểu bạn muốn phút và sẽ báo lỗi. Với tháng, luôn dùng chữ hoa M.
Lỗi № 3: Không xử lý ngoại lệ khi phân tích.
Nếu không bắt DateTimeParseException, chương trình có thể dừng đột ngột khi nhập sai. Luôn xử lý các lỗi này.
Lỗi № 4: Không chỉ định locale khi dùng tên bằng chữ.
Nếu dùng mẫu có tháng bằng chữ (MMMM) mà không chỉ định locale, Java có thể dùng ngôn ngữ mặc định (ví dụ, tiếng Anh). Hãy luôn đặt locale rõ ràng.
Lỗi № 5: Dùng các lớp cũ (SimpleDateFormat, Date) trong dự án mới.
Hãy nhớ: trong mã hiện đại, hãy dùng java.time và DateTimeFormatter.
GO TO FULL VERSION