Ngày 15 tháng 11 năm 2023 | Máy tính
Bài viết này sẽ giới thiệu cách thực hiện các lớp công cụ chuyển đổi truyền thống giữa Date
và String
trước khi có Java 8; sau đó khám phá cách triển khai việc chuyển đổi giữa Instant
và String
trong Java 8, cũng như cách xây dựng lớp công cụ mới.
1. Thiết kế lớp công cụ chuyển đổi ngày tháng truyền thống
Trước Java 8, chúng ta thường sử dụng Date
để biểu diễn ngày và giờ. Khi thiết kế lớp công cụ chuyển đổi giữa Date
và String
, chỉ cần sử dụng SimpleDateFormat
, bạn có thể dễ dàng thực hiện.
Mã ví dụ như sau:
import java.text.ParseException;
import [cwin 667](/post/istio-traffic-managemen/) java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
public static Date str2Date(String dateStr, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(dateStr);
} catch (ParseException e) {
throw new RuntimeException("Chuyển đổi ngày thất bại");
}
}
public static String date2Str(Date date, String pattern) {
return new SimpleDateFormat(pattern).format(date);
}
public static void main(String[] args) {
// Chuyển chuỗi thành ngày
Date date = DateUtil.str2Date("2023-11-15", "yyyy-MM-dd");
// Chuyển ngày thành chuỗi
String str = DateUtil.date2Str(date, "yyyy/MM");
System.out.println(str);
}
}
Như có thể thấy, phương thức str2Date
và date2Str
của lớp DateUtil
trên có thể lần lượt thực hiện việc chuyển đổi giữa String
và Date
, cũng như giữa Date
và String
.
2. Java 8: Thiết kế lớp công cụ chuyển đổi giữa Instant và String
Java 8 đã giới thiệu một lớp mới gọi là Instant
, đại diện cho một điểm trên dòng thời gian (thời khắc). Làm thế nào để thiết kế một lớp công cụ chuyển đổi giữa Instant
và String
?
Đầu tiên, chúng ta sẽ xem xét một ví dụ sai lầm, sau đó tìm hiểu cách sửa lỗi để tạo iwin68.club phiên bản mới ra ví dụ chính xác.
Trong Java 8, chúng ta cần sử dụng DateTimeFormatter
để thực hiện việc chuyển đổi giữa Instant
và String
.
Dưới đây là một ví dụ không hoàn chỉnh dẫn đến lỗi.
2.1 Ví dụ Sai Lầm
Dưới đây là nỗ lực bao gói lớp công cụ chuyển đổi giữa Instant
và String
. Vì nó có một số vấn đề nên chúng tôi đặt tên là FatalInstantUtil
. Phương thức str2Instant
được dùng để chuyển từ String
sang Instant
; phương thức instant2Str
được dùng để chuyển từ Instant
sang String
.
// Ví dụ sai
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class FatalInstantUtil {
public static Instant str2Instant(String dateTimeStr, String pattern) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(dateTimeStr, formatter)
.atZone(ZoneId.systemDefault())
.toInstant();
}
public static String instant2Str(Instant instant, String pattern) {
return DateTimeFormatter.ofPattern(pattern).format(instant);
}
public static void main(String[] args) {
// Chuyển chuỗi thành instant
Instant instant = str2Instant("2023-11-15", "yyyy-MM-dd");
System.out.println(instant);
// Chuyển instant thành chuỗi
String str = instant2Str(Instant.now(), "yyyy-MM");
System.out.println(str);
}
}
Khi sử dụng phương thức str2Instant
để chuyển đổi từ String
sang Instant
, các đoạn mã dưới đây đều hoạt động bình thường:
str2Instant("2023-11-15 17:23:56", "yyyy-MM-dd HH:mm:ss");
str2Instant("2023-11-15 17:23", "yyyy-MM-dd HH:mm");
str2Instant("2023-11-15 17", "yyyy-MM-dd HH");
Tuy nhiên, các đoạn mã sau sẽ gây lỗi:
str2Instant("2023-11-15", "yyyy-MM-dd");
str2Instant("2023-11", "yyyy-MM");
str2Instant("2023", "yyyy");
Lỗi xảy ra khi thực thi str2Instant("2023-11-15", "yyyy-MM-dd")
với thông báo như sau:
Exception in thread "main" java.time.format.DateTimeParseException: Text '2023-11-15' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2023-11-15 of type java.time.format.Parsed
Lý do của lỗi này nằm ở chỗ chưa cung cấp giá trị mặc định cho tháng, ngày, giờ, phút và giây. Nếu thiếu những giá trị này, DateTimeFormatter
sẽ không biết phải xử lý chúng như thế nào và sẽ ném ra ngoại lệ DateTimeParseException
.
Ngoài ra, khi sử dụng phương thức instant2Str
để chuyển đổi từ Instant
sang String
, cũng sẽ xuất hiện lỗi.
Ví dụ, khi thực thi instant2Str(Instant.now(), "yyyy-MM")
, thông báo lỗi như sau:
Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
Nguyên nhân của lỗi này là do chưa chỉ định múi giờ cho DateTimeFormatter
. Do đó, khi thực hiện format
, nó không biết chuyển đổi theo múi giờ nào và sẽ ném ra ngoại lệ.
Sau khi hiểu rõ nguyên nhân của các lỗi, chúng ta sẽ sửa chữa và xem ví dụ đúng.
2.2 Ví dụ Đúng
Mã nguồn đã sửa như sau:
// Ví dụ đúng
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
public class InstantUtil {
public static Instant str2Instant(String dateTimeStr, String pattern) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter();
return LocalDateTime.parse(dateTimeStr, formatter)
.atZone(ZoneId.systemDefault())
.toInstant();
}
public static String instant2Str(Instant instant, String pattern) {
return DateTimeFormatter.ofPattern(pattern)
.withZone(ZoneId.systemDefault())
.format(instant);
}
public static void main(String[] args) { [2233win](/post/2020-summary/)
// Chuyển chuỗi thành instant
Instant instant = str2Instant("2023-11-15", "yyyy-MM-dd");
System.out.println(instant);
// Chuyển instant thành chuỗi
String str = instant2Str(Instant.now(), "yyyy-MM");
System.out.println(str);
}
}
Trong đoạn mã đã sửa, phương thức str2Instant
sử dụng DateTimeFormatterBuilder
để xây dựng DateTimeFormatter
. Nó sử dụng parseDefaulting
để chỉ định giá trị mặc định cho tháng, ngày, giờ, phút và giây. Khi những giá trị này bị thiếu, chúng sẽ được điền bằng các giá trị mặc định và không còn gây lỗi.
Phương thức instant2Str
đã được sửa bằng cách chỉ định múi giờ cho DateTimeFormatter
, đảm bảo rằng việc chuyển đổi từ Instant
sang String
sẽ không gặp lỗi.
Từ đó, chúng ta đã hoàn thành việc thiết kế một lớp công cụ chuyển đổi giữa Instant
và String
hiệu quả.
Toàn bộ mã nguồn trong bài viết đã được lưu trữ trên GitHub cá nhân của tôi, mọi người có thể theo dõi hoặc Fork.
[1] Java: Không thể lấy LocalDateTime từ TemporalAccessor khi phân tích LocalDateTime | Stack Overflow - stackoverflow.com
[2] Java: UnsupportedTemporalTypeException khi định dạng Instant thành String | Stack Overflow - stackoverflow.com
#Java