Giới thiệu
SimpleDateFormat định dạng và phân tích cú pháp java.util.Date các giá trị sử dụng chuỗi mẫu tùy chỉnh và DateFormat cung cấp API cơ sở trừu tượng để định dạng ngày và giờ nhận biết miền địa phương. Sử dụng các API này khi bạn duy trì mã Java cũ vẫn phụ thuộc vào java.util.Date; đối với mã mới, ưu tiên DateTimeFormatter từ API ngày/giờ Java 8+ vì SimpleDateFormat không an toàn cho luồng.
Hướng dẫn này chỉ ra cách sử dụng DateFormat và SimpleDateFormat để định dạng, phân tích cú pháp, chuyển đổi múi giờ và đầu ra theo ngôn ngữ cụ thể. Nó cũng bao gồm việc xác thực nghiêm ngặt với setLenient(false) , các giải pháp đảm bảo an toàn cho luồng và đường dẫn di chuyển thực tế sang DateTimeFormatter .
Bài học chính
DateFormatlà API định dạng trừu tượng vàSimpleDateFormatlà cách triển khai cụ thể cho việc định dạng và phân tích cú pháp dựa trên mẫuSimpleDateFormathỗ trợ mã thông báo mẫu phong phú cho năm, tháng, ngày, trường thời gian và đầu ra múi giờ- Một
SimpleDateFormatđược chia sẻ instance không an toàn trong mã đa luồng vì trạng thái bên trong của nó có thể thay đổi ThreadLocal<SimpleDateFormat>tách biệt các phiên bản trình định dạng trên mỗi luồng khi mã kế thừa không thể di chuyển ngay lập tứcDateTimeFormatterlà bất biến và an toàn theo luồng, vì vậy nó là sự thay thế ưu tiên cho mã Java mới.parse()có thể némParseException, vì vậy mã phân tích cú pháp nên sử dụng tính năng thử bắt và thông báo lỗi hữu íchsetLenient(false)ngăn chặn những ngày không hợp lệ được điều chỉnh âm thầm, chẳng hạn như2024-13-45- Luôn chuyển
Localerõ ràng để tránh đầu ra phụ thuộc vào môi trường khi triển khai máy chủ
SimpleDateFormat trong Java là gì?
SimpleDateFormat là DateFormat lớp con cho phép bạn xác định các mẫu ngày/giờ rõ ràng để định dạng và phân tích cú pháp trong Java.
Sử dụng DateFormat khi bạn muốn đầu ra nhận biết ngôn ngữ, dựa trên kiểu thông qua các phương thức ban đầu và sử dụng SimpleDateFormat khi bạn cần kiểm soát mẫu chính xác, chẳng hạn như "dd-MM-yyyy" hoặc "yyyy-MM-dd'T'HH:mm:ssZ" . DateFormat hằng số kiểu (SHORT , MEDIUM , LONG , FULL ) tạo ra kết quả phù hợp với ngôn ngữ mà không yêu cầu bạn biết chính xác thứ tự ngày trong khu vực, điều này rất hữu ích cho các chuỗi hiển thị hướng tới người dùng trong đó định dạng phải tuân theo quy ước ngôn ngữ của người dùng. Sử dụng SimpleDateFormat khi định dạng đầu ra được cố định bởi một yêu cầu bên ngoài, chẳng hạn như hợp đồng API, định dạng nhật ký hoặc quy ước đặt tên tệp, vì những trường hợp đó yêu cầu một mẫu chính xác bất kể ngôn ngữ.
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Locale locale = Locale.US;
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
String styleBased = dateFormat.format(new Date());
SimpleDateFormat patternBased = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", locale);
String patternOutput = patternBased.format(new Date());
System.out.println(styleBased);
System.out.println(patternOutput);
Jan 5, 2026
05-01-2026 14:30:22
new Locale(String, String) không được dùng nữa kể từ Java 19. Sử dụng Locale.Builder thay vào đó.
Locale locale = new Locale.Builder()
.setLanguage("en")
.setRegion("US")
.build();
Để định dạng thời gian thay vì ngày, hãy sử dụng DateFormat.getTimeInstance() có cùng tham số ngôn ngữ và kiểu.
Locale locale = Locale.US;
DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
System.out.println(timeFormat.format(new Date()));
Output depends on the current time and timezone, for example:
2:30:45 PM
Để có cái nhìn tổng quan hơn về các API ngày/giờ Java hiện đại, hãy xem các tính năng Java 8 Date, LocalDate, LocalDateTime, Instant và Java 8 kèm ví dụ.
Tham chiếu cú pháp mẫu SimpleDateFormat
SimpleDateFormat Các chữ cái mẫu ánh xạ trực tiếp đến các thành phần ngày/giờ và việc lựa chọn mẫu chính xác sẽ kiểm soát cả định dạng đầu ra và hành vi phân tích cú pháp.
G Người chỉ định thời đạiG AD y Nămyyyy 2026 M Tháng trong nămMMMM January w Tuần trong nămw 3 W Tuần trong thángW 1 D Ngày trong nămD 15 d Ngày trong thángdd 05 F Ngày trong tuần trong thángF 1 E Tên ngày trong tuầnEEE Mon u Số ngày trong tuần (1 = Monday )u 1 a Điểm đánh dấu AM/PMa PM H Giờ trong ngày (0-23 )HH 14 k Giờ trong ngày (1-24 )k 14 K Giờ tính bằng sáng/chiều (0-11 )K 2 h Giờ tính bằng sáng/chiều (1-12 )hh 02 m Phút trong giờmm 30 s Giây sau phútss 45 S Mili giâySSS 123 z Múi giờ chungz IST Z Độ lệch múi giờ RFC 822Z +0530 X Độ lệch múi giờ ISO 8601XXX +05:30 Lặp lại mẫu và độ rộng đầu ra
Các chữ cái mẫu lặp lại sẽ thay đổi chiều rộng, phần đệm số hoặc kiểu văn bản.
M 1 ThángMM 01 ThángMMM Jan ThángMMMM January Ngày trong thángd 5 Ngày trong thángdd 05 Giờ (0-23 )H 7 Giờ (0-23 )HH 07 Nămyy 26 Nămyyyy 2026 Ví dụ về mẫu phổ biến với kết quả mong đợi
Những mẫu phổ biến này rất hữu ích cho nhật ký, API và ngày mà người dùng nhìn thấy.
MM/dd/yyyy 01/05/2026 dd-M-yyyy hh:mm:ss 05-1-2026 02:30:45 dd MMMM yyyy 05 January 2026 dd MMMM yyyy zzzz 05 January 2026 India Standard Time E, dd MMM yyyy HH:mm:ss z Mon, 05 Jan 2026 14:30:45 IST Cách định dạng ngày bằng SimpleDateFormat
Để định dạng Date , tạo SimpleDateFormat với một mẫu và gọi .format(date) .
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Date now = new Date();
SimpleDateFormat basic = new SimpleDateFormat("MM-dd-yyyy", Locale.US);
SimpleDateFormat withTime = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.US);
SimpleDateFormat isoLike = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
System.out.println(basic.format(now));
System.out.println(withTime.format(now));
System.out.println(isoLike.format(now));
01-05-2026
05-01-2026 14:30:45
2026-01-05T14:30:45+0000
SimpleDateFormat áp dụng các quy tắc múi giờ và ngôn ngữ từ phiên bản trình định dạng, vì vậy hãy đặt các giá trị đó một cách rõ ràng khi đầu ra phải nhất quán.
Cách phân tích chuỗi thành ngày bằng SimpleDateFormat
Để phân tích một chuỗi thành Date , tạo một trình định dạng với mẫu đầu vào chính xác và gọi .parse(input) .
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
try {
SimpleDateFormat dateParser = new SimpleDateFormat("dd-MM-yyyy", Locale.US);
Date parsedDate = dateParser.parse("05-01-2026");
System.out.println(parsedDate);
SimpleDateFormat timeParser = new SimpleDateFormat("HH:mm:ss", Locale.US);
Date parsedTime = timeParser.parse("22:15:09");
System.out.println(parsedTime);
} catch (ParseException e) {
e.printStackTrace();
}
Mon Jan 05 00:00:00 UTC 2026
Thu Jan 01 22:15:09 UTC 1970
Nếu chỉ cung cấp thời gian, Java sẽ sử dụng ngày kỷ nguyên làm phần ngày.
Xử lý ParseException một cách chính xác
parse() ném ParseException khi đầu vào không khớp với mẫu đã định cấu hình, do đó mã sản xuất sẽ bắt được đầu vào đó và ghi lại cả đầu vào thô và mẫu dự kiến.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
String input = "31/01/2026";
String pattern = "dd-MM-yyyy";
SimpleDateFormat parser = new SimpleDateFormat(pattern, Locale.US);
try {
parser.parse(input);
System.out.println("Parsed successfully");
} catch (ParseException e) {
// Include both the input value and pattern for easier debugging.
System.err.println("Failed to parse date string: " + input);
System.err.println("Expected pattern: " + pattern);
System.err.println("Parser error: " + e.getMessage());
}
Failed to parse date string: 31/01/2026
Expected pattern: dd-MM-yyyy
Parser error: Unparseable date: "31/01/2026"
Để biết các mẫu xử lý ngoại lệ mà bạn có thể sử dụng lại trên các dịch vụ, hãy xem Xử lý ngoại lệ trong Java và Java 8 Date, LocalDate, LocalDateTime, Instant.
Xác thực chuỗi ngày trước khi phân tích cú pháp
SimpleDateFormat theo mặc định là nhẹ nhàng, do đó các giá trị không hợp lệ có thể được chuyển đổi thay vì bị lỗi; gọi setLenient(false) để thực thi xác thực nghiêm ngặt.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
String invalid = "2024-13-45";
SimpleDateFormat lenientParser = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
SimpleDateFormat strictParser = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
strictParser.setLenient(false);
System.out.println("Lenient parse result:");
try {
// Lenient mode silently rolls over invalid values instead of throwing.
System.out.println(lenientParser.parse(invalid));
} catch (ParseException e) {
System.out.println("ParseException: " + e.getMessage());
}
System.out.println("Strict parse result:");
try {
System.out.println(strictParser.parse(invalid));
} catch (ParseException e) {
System.out.println("ParseException: " + e.getMessage());
}
Lenient parse result:
Fri Feb 14 00:00:00 UTC 2025
Strict parse result:
ParseException: Unparseable date: "2024-13-45"
Xử lý múi giờ trong SimpleDateFormat
SimpleDateFormat có thể hiển thị cùng một Date ở các múi giờ khác nhau bằng cách đặt múi giờ trên bộ định dạng trước khi xuất. Một Date đối tượng chỉ lưu trữ số lượng mili giây UTC và không mang múi giờ riêng. Múi giờ là vấn đề về định dạng, không phải vấn đề về lưu trữ; giống Date value tạo ra kết quả đầu ra khác nhau mà con người có thể đọc được tùy thuộc vào múi giờ mà trình định dạng áp dụng. Điều này có nghĩa là setTimeZone() phải được gọi trên bộ định dạng trước format() được gọi; cài đặt nó sau đó không ảnh hưởng đến kết quả đã được tạo ra.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
Date timestamp = new Date(1700000000000L); // Fixed instant for repeatable output
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC: " + formatter.format(timestamp));
formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("New York: " + formatter.format(timestamp));
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
System.out.println("Kolkata: " + formatter.format(timestamp));
UTC: 2023-11-14 22:13:20 +0000
New York: 2023-11-14 17:13:20 -0500
Kolkata: 2023-11-15 03:43:20 +0530
Xem Cách chuyển đổi ngày Java thành định dạng múi giờ cụ thể để biết các mẫu chuyển đổi múi giờ sâu hơn.
Các lỗi múi giờ thường gặp và cách tránh chúng
Lỗi múi giờ thường xuất phát từ việc nhầm lẫn các khoảnh khắc được lưu trữ với giờ địa phương được hiển thị.
Datelưu trữ mili giây UTC và múi giờ chỉ được áp dụng khi định dạng- Gọi
setTimeZone()trên phiên bản trình định dạng dùng chung trong môi trường đa luồng có thể thay đổi hoạt động giữa múi giờ cho lệnh gọi trong chuyến bay của luồng khác, tạo ra đầu ra sai múi giờ mà không có ngoại lệ nào được đưa ra - Sử dụng lại một
SimpleDateFormatphiên bản trên các yêu cầu HTTP trong aservlet hoặc bộ điều khiển Spring có thể gây rasetTimeZone()của một yêu cầu gọi để ảnh hưởng đến đầu ra của yêu cầu khác; tạo một phiên bản mới cho mỗi yêu cầu hoặc sử dụngThreadLocal<SimpleDateFormat>để cô lập trạng thái TimeZone.getTimeZone("Invalid/Zone")âm thầm quay trở lại GMT vì hợp đồng phương thức chỉ định GMT làm mặc định cho các ID không được nhận dạng thay vì đưa ra một ngoại lệ- Xác thực ID vùng bằng
ZoneId.of()từjava.timetrước khi chuyển chúng tớiTimeZone.getTimeZone();ZoneId.of()némZoneRulesExceptiontrên ID không hợp lệ, điều này làm cho vấn đề trở nên rõ ràng
Định dạng ngày nhận biết miền địa phương
Để tạo đầu ra ngày theo miền địa phương, chẳng hạn như tên tháng trong tiếng Pháp hoặc tên ngày trong tiếng Đức, hãy chuyển Locale đến SimpleDateFormat hàm tạo. Sử dụng các hằng số tích hợp, Locale.US , Locale.UK , Locale.FRENCH , Locale.GERMAN , cho các vùng chung hoặc tạo một ngôn ngữ tùy chỉnh với Locale.Builder khi bạn cần một vùng không bị bao phủ bởi các hằng số. Locale kiểm soát ngôn ngữ nào được sử dụng cho các trường văn bản, chẳng hạn như tên tháng, tên ngày và điểm đánh dấu AM/PM.
Chỉ định ngôn ngữ trong hàm tạo SimpleDateFormat
Vượt qua Locale làm đối số hàm tạo thứ hai. Nếu bạn bỏ qua nó, SimpleDateFormat cuộc gọi Locale.getDefault() bên trong, liên kết bộ định dạng với ngôn ngữ thời gian chạy của JVM, một giá trị khác nhau giữa các máy của nhà phát triển, môi trường CI và máy chủ sản xuất chạy trong các cấu hình ngôn ngữ hệ điều hành khác nhau.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Date sample = new Date(1700000000000L);
String pattern = "EEEE, dd MMMM yyyy";
SimpleDateFormat usFormatter = new SimpleDateFormat(pattern, Locale.US);
SimpleDateFormat frFormatter = new SimpleDateFormat(pattern, Locale.FRENCH);
String usDate = usFormatter.format(sample);
String frDate = frFormatter.format(sample);
System.out.println("US: " + usDate);
System.out.println("French: " + frDate);
US: Tuesday, 14 November 2023
French: mardi, 14 novembre 2023
Định dạng tên ngày tháng theo vùng
Cùng một mẫu tạo ra văn bản đầu ra khác nhau theo ngôn ngữ.
Locale.US EEEE, dd MMMM yyyy Tuesday, 14 November 2023 Locale.FRENCH EEEE, dd MMMM yyyy mardi, 14 novembre 2023 Locale.GERMAN EEEE, dd MMMM yyyy Dienstag, 14 November 2023
Dựa vào Locale.getDefault() trong JVM chạy trong môi trường máy chủ có thể tạo ra đầu ra không nhất quán vì cài đặt ngôn ngữ hệ điều hành khác nhau giữa các máy chủ. Luôn chuyển Locale rõ ràng .
Vấn đề về an toàn luồng với SimpleDateFormat
Tại sao SimpleDateFormat không an toàn cho luồng
SimpleDateFormat đột biến nội bộ Calendar và NumberFormat trạng thái trong các hoạt động phân tích cú pháp/định dạng. Nếu nhiều luồng sử dụng một phiên bản, thì các trường có thể thay đổi này có thể bị ghi đè trong quá trình hoạt động, gây ra tình trạng tương tranh và kết quả đầu ra không thể đoán trước. Trong thực tế, điều này hiển thị dưới dạng ngày từ một luồng xuất hiện trong kết quả của luồng khác, .parse() trả lại ngày hoàn toàn sai không có ngoại lệ hoặc ArrayIndexOutOfBoundsException được ném từ bên trong bộ định dạng. Những lỗi này xảy ra không liên tục và phụ thuộc vào tải, khiến chúng khó tái tạo trong môi trường thử nghiệm đơn luồng.
Khi bạn cần định dạng an toàn đồng thời trong mã cũ, hãy tách biệt các phiên bản theo luồng hoặc phạm vi yêu cầu. Để biết thông tin cơ bản về hành vi phân luồng Java, hãy xem Ví dụ về luồng Java.
Sử dụng ThreadLocal để tách biệt các phiên bản SimpleDateFormat
ThreadLocal<SimpleDateFormat> cung cấp cho mỗi luồng phiên bản định dạng riêng của nó và tránh trạng thái có thể thay đổi được chia sẻ. Trong các môi trường nhóm luồng như bộ chứa servlet và ứng dụng Spring, các luồng được sử dụng lại qua các yêu cầu và không bao giờ bị chấm dứt, điều đó có nghĩa là ThreadLocal các giá trị không bao giờ được tự động xóa. Luôn gọi FORMATTER.remove() sau khi thao tác hoàn tất hoặc phiên bản trình định dạng sẽ tồn tại trong suốt vòng đời của luồng và tích lũy dưới dạng rò rỉ bộ nhớ khi tải liên tục.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class ThreadSafeLegacyFormatter {
// Each thread gets one dedicated formatter instance.
private static final ThreadLocal<SimpleDateFormat> FORMATTER =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US));
public static String format(Date date) {
try {
// No cross-thread mutation because each thread reads its own formatter.
return FORMATTER.get().format(date);
} finally {
// Remove the instance after use to prevent memory leaks in thread pools.
FORMATTER.remove();
}
}
}
Chuyển sang DateTimeFormatter làm giải pháp thay thế an toàn cho luồng
DateTimeFormatter là bất biến và an toàn theo luồng, vì vậy một phiên bản tĩnh được chia sẻ sẽ an toàn.
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
// Not thread-safe when shared across threads
SimpleDateFormat unsafe = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
System.out.println(unsafe.format(new Date()));
// Thread-safe: DateTimeFormatter is immutable and can be stored as a static field
DateTimeFormatter safe = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.US);
System.out.println(safe.format(LocalDateTime.now()));
2026-01-05 14:30:22
2026-01-05 14:30:22
Di chuyển từ SimpleDateFormat sang DateTimeFormatter
Di chuyển sang DateTimeFormatter loại bỏ các rủi ro về an toàn luồng, loại bỏ ThreadLocal giải pháp thay thế và tích hợp hoàn toàn với java.time các loại. Đối với hầu hết các cơ sở mã, quá trình di chuyển là cơ học:cú pháp mẫu gần như giống hệt nhau, hai API có thể cùng tồn tại trong quá trình triển khai tăng dần và bạn không cần phải chuyển đổi mọi thứ cùng một lúc. Rủi ro chính là u ký hiệu, có nghĩa là ngày trong tuần ở SimpleDateFormat và năm ở DateTimeFormatter; các mẫu được sao chép trực tiếp giữa các API mà không kiểm tra điều này sẽ âm thầm tạo ra kết quả sai.
So sánh mã song song
Đoạn mã cạnh nhau này hiển thị hành vi phân tích và định dạng tương đương trong các API cũ và API hiện đại.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
String pattern = "yyyy-MM-dd";
String input = "2026-01-05";
// SimpleDateFormat (legacy java.util.Date API)
SimpleDateFormat legacyFormatter = new SimpleDateFormat(pattern, Locale.US);
Date legacyParsed = legacyFormatter.parse(input);
String legacyFormatted = legacyFormatter.format(new Date());
// DateTimeFormatter (modern java.time API)
DateTimeFormatter modernFormatter = DateTimeFormatter.ofPattern(pattern, Locale.US);
LocalDate modernParsed = LocalDate.parse(input, modernFormatter);
String modernFormatted = modernFormatter.format(LocalDate.now());
System.out.println(legacyParsed);
System.out.println(legacyFormatted);
System.out.println(modernParsed);
System.out.println(modernFormatted);
Mon Jan 05 00:00:00 UTC 2026
2026-01-05
2026-01-05
2026-01-05
Sự khác biệt về cú pháp mẫu giữa hai API
Hầu hết các chữ cái mẫu đều giống nhau nhưng một số ký hiệu khác nhau và có thể phá vỡ quá trình di chuyển nếu được sao chép trực tiếp.
yyyy uuuu hoặc yyyy Ưu tiên uuuu vào năm java.time để biết tính nhất quán của năm tiên lượng. Bù múi giờ/tênz , Z , X z , Z , x , X java.time phân biệt nhiều biến thể bù đắp hơn (x và X )Văn bản chữ'T' 'T' Cả hai API đều sử dụng dấu ngoặc đơn cho hằng sốu ký hiệuSố ngày trong tuầnNămĐã biết nhận định:u thay đổi ý nghĩa giữa các API Danh sách kiểm tra di chuyển từng bước
Hãy sử dụng danh sách kiểm tra này để chuyển đổi từng bộ định dạng trong các cơ sở mã hiện có.
- Thay thế
import java.text.SimpleDateFormat;vớiimport java.time.format.DateTimeFormatter; - Thay thế
new SimpleDateFormat("yyyy-MM-dd")vớiDateTimeFormatter.ofPattern("yyyy-MM-dd") - Thay thế
.parse()vớiLocalDate.parse()hoặcLocalDateTime.parse()tùy thuộc vào độ chính xác đầu vào - Thay thế
.format(date)vớiformatter.format(localDate)hoặcformatter.format(localDateTime) - Xóa
new Date()nếu có thể và sử dụngLocalDate.now()hoặcInstant.now()
DateTimeFormatter hoạt động độc quyền với java.time các loại (LocalDate , LocalDateTime , ZonedDateTime , Instant ). Nó không chấp nhận java.util.Date trực tiếp. Nếu bạn có mã vẫn tạo ra java.util.Date các giá trị, ví dụ từ trình điều khiển ORM hoặc JDBC kế thừa, trước tiên hãy chuyển đổi bằng date.toInstant() trước khi chuyển tới DateTimeFormatter . Hai API có thể cùng tồn tại trong cùng một cơ sở mã trong quá trình di chuyển gia tăng; bạn không cần phải chuyển đổi mọi thứ cùng một lúc. DateTimeFormatter cũng thay thế ParseException với java.time.format.DateTimeParseException , đây là một ngoại lệ không được kiểm tra, vì vậy các khối try-catch trở thành tùy chọn nhưng vẫn được khuyến nghị trong mã phân tích cú pháp sản xuất.
Để biết các lựa chọn về loại và ngữ cảnh di chuyển, hãy tham khảo Java 8 Date, LocalDate, LocalDateTime, Instant.
Câu hỏi thường gặp
Sự khác biệt giữa SimpleDateFormat và DateFormat trong Java là gì?
DateFormat là một lớp trừu tượng xác định hợp đồng định dạng ngày/giờ. SimpleDateFormat là lớp con cụ thể của nó cho phép định dạng dựa trên mẫu tùy chỉnh. Bạn sử dụng SimpleDateFormat trực tiếp bằng mã; bạn sử dụng DateFormat làm loại tham chiếu khi bạn muốn chấp nhận bất kỳ triển khai nào.
Chuỗi SimpleDateFormat có an toàn không?
Số SimpleDateFormat các trường hợp không an toàn theo luồng. Việc chia sẻ một phiên bản duy nhất trên các luồng mà không đồng bộ hóa sẽ gây ra kết quả phân tích cú pháp và định dạng không thể đoán trước. Sử dụng ThreadLocal<SimpleDateFormat> hoặc thay thế bằng java.time.format.DateTimeFormatter , không thể thay đổi và an toàn theo luồng.
Làm cách nào để phân tích chuỗi ngày ở định dạng dd-MM-yyyy bằng SimpleDateFormat?
Khởi tạo SimpleDateFormat với mẫu "dd-MM-yyyy" , sau đó gọi .parse(yourString) . Kết thúc cuộc gọi trong khối try-catch cho ParseException . Đảm bảo chuỗi đầu vào khớp chính xác với mẫu, bao gồm cả các ký tự phân cách.
Làm cách nào để chuyển đổi Ngày sang múi giờ khác bằng SimpleDateFormat?
Gọi .setTimeZone(TimeZone.getTimeZone("America/New_York")) trên SimpleDateFormat của bạn ví dụ trước khi gọi .format(date) . Date cơ bản đối tượng giữ UTC mili giây; trình định dạng áp dụng chênh lệch múi giờ trong quá trình xuất.
Mẫu “yyyy-MM-dd’T’HH:mm:ssZ” tạo ra cái gì?
Nó tạo ra dấu thời gian tương thích với ISO 8601, ví dụ 2024-06-15T14:30:00+0530 . T là một ký tự chữ được gói trong dấu nháy đơn. Z đại diện cho độ lệch múi giờ RFC 822.
Làm cách nào để di chuyển từ SimpleDateFormat sang DateTimeFormatter?
Thay thế new SimpleDateFormat("yyyy-MM-dd") với DateTimeFormatter.ofPattern("yyyy-MM-dd") . Thay thế .parse() cuộc gọi với LocalDate.parse() hoặc LocalDateTime.parse() . Thay thế .format(date) cuộc gọi với formatter.format(localDate) . Lưu ý rằng DateTimeFormatter sử dụng u trong năm trong một số bối cảnh thay vì y .
Tại sao SimpleDateFormat phân tích ngày không hợp lệ mà không đưa ra ngoại lệ?
Theo mặc định, SimpleDateFormat sử dụng chế độ phân tích cú pháp nhẹ nhàng, điều chỉnh các giá trị ngoài phạm vi thay vì từ chối chúng. Gọi .setLenient(false) trước khi phân tích cú pháp để thực thi xác thực nghiêm ngặt và ném ParseException với đầu vào không hợp lệ.
Làm cách nào để định dạng ngày có ngôn ngữ cụ thể bằng SimpleDateFormat?
Vượt qua Locale làm đối số thứ hai cho hàm tạo:new SimpleDateFormat("dd MMMM yyyy", Locale.FRENCH) . Điều này hiển thị tên tháng và ngày bằng ngôn ngữ được chỉ định. Điều này rất quan trọng đối với các ứng dụng phục vụ nhiều khu vực.
Kết luận
Hướng dẫn này bao gồm DateFormat và SimpleDateFormat nguyên tắc cơ bản, cú pháp mẫu, quy trình định dạng và phân tích cú pháp, hành vi múi giờ, kết xuất nhận biết ngôn ngữ, vấn đề an toàn luồng và di chuyển sang DateTimeFormatter .
Giờ đây, bạn có thể chọn trình định dạng phù hợp cho mã cũ và mã hiện đại, phân tích cú pháp đầu vào một cách phòng thủ bằng xác thực nghiêm ngặt, tránh lệch ngôn ngữ và múi giờ trong môi trường máy chủ, đồng thời loại bỏ rủi ro tương tranh khỏi các trình định dạng ngày dùng chung.
Để biết các bước tiếp theo, hãy xem lại các tính năng Java 8 Date, LocalDate, LocalDateTime, Instant, Java 8 cùng với các ví dụ, Xử lý ngoại lệ trong Java và Cách chuyển đổi ngày Java thành định dạng múi giờ cụ thể để tiếp tục hiện đại hóa việc xử lý ngày/giờ trong các ứng dụng Java.
Tài liệu tham khảo:
- Tài liệu API SimpleDateFormat
- Tài liệu API DateFormat
- Tài liệu API DateTimeFormatter
Tác phẩm này được cấp phép theo Giấy phép quốc tế Creative Commons Ghi công-NonCommercial-ShareAlike 4.0.