Date / Number / Currency Formatting trong lập trình
Date / Number / Currency Formatting là một chủ đề quan trọng trong phát triển phần mềm, đặc biệt đối với các ứng dụng đa ngôn ngữ, ứng dụng thương mại điện tử, hệ thống quản lý tài chính và các ứng dụng cần hiển thị dữ liệu theo khu vực địa lý. Việc định dạng ngày tháng, số và tiền tệ giúp dữ liệu trở nên dễ đọc, nhất quán và phù hợp với thói quen của người dùng tại từng quốc gia.
Cùng một giá trị dữ liệu nhưng có thể được hiển thị theo nhiều cách khác nhau. Ví dụ, ngày 17 tháng 10 năm 2026 có thể được viết thành 17/10/2026, 10/17/2026 hoặc October 17, 2026. Tương tự, số một triệu có thể được trình bày thành 1.000.000 tại Việt Nam hoặc 1,000,000 tại Hoa Kỳ. Giá trị tiền tệ cũng có sự khác biệt về ký hiệu, vị trí ký hiệu và dấu phân cách.
Trong quá trình phát triển ứng dụng, lập trình viên cần hiểu cách lưu trữ dữ liệu, cách định dạng dữ liệu khi hiển thị và cách xử lý dữ liệu được nhập từ người dùng. Đây không chỉ là vấn đề giao diện mà còn liên quan đến tính chính xác của dữ liệu, trải nghiệm người dùng, khả năng quốc tế hóa và khả năng mở rộng của hệ thống.
1. Tổng quan về Date / Number / Currency Formatting
Date / Number / Currency Formatting là quá trình chuyển đổi dữ liệu ngày tháng, số học và tiền tệ thành chuỗi văn bản có định dạng phù hợp với ngôn ngữ, khu vực và quy ước trình bày của người dùng.
Thông thường, dữ liệu được lưu trữ dưới dạng giá trị có cấu trúc trong chương trình hoặc cơ sở dữ liệu. Khi hiển thị trên giao diện, hệ thống sẽ sử dụng các quy tắc định dạng để chuyển đổi dữ liệu đó thành văn bản dễ đọc.
Ví dụ:
-
Dữ liệu ngày tháng:
2026-10-17→17/10/2026. -
Dữ liệu số:
1234567.89→1.234.567,89. -
Dữ liệu tiền tệ:
1500000→1.500.000 ₫. -
Dữ liệu phần trăm:
0.256→25,6%.
Các ví dụ trên sử dụng quy ước hiển thị thường gặp tại Việt Nam. Khi chuyển sang môi trường Hoa Kỳ, cùng dữ liệu có thể được định dạng thành 10/17/2026, 1,234,567.89 và $1,500,000.00.
Điểm quan trọng là giá trị dữ liệu và cách trình bày dữ liệu là hai khái niệm khác nhau. Chương trình không nên thay đổi giá trị gốc chỉ để phù hợp với một kiểu hiển thị cụ thể.
Trong một ứng dụng thực tế, ba nhóm định dạng này thường xuất hiện cùng nhau. Một trang đặt hàng có thể hiển thị ngày đặt hàng, số lượng sản phẩm, đơn giá, tổng tiền và phần trăm giảm giá. Nếu từng giá trị được định dạng không nhất quán, người dùng có thể hiểu nhầm thông tin hoặc gặp khó khăn khi thực hiện giao dịch.
2. Vai trò của định dạng dữ liệu trong ứng dụng
2.1. Cải thiện khả năng đọc và hiểu dữ liệu
Dữ liệu thô thường không được tối ưu cho việc đọc trực tiếp. Một giá trị như 20261017 không trực quan bằng 17/10/2026. Tương tự, số 25000000 khó quan sát nhanh hơn 25.000.000.
Việc bổ sung dấu phân cách, đơn vị và quy tắc hiển thị giúp người dùng nhận biết thông tin nhanh chóng, giảm nhầm lẫn khi đọc dữ liệu có độ dài lớn.
2.2. Phù hợp với thói quen của từng quốc gia
Mỗi quốc gia có quy ước trình bày dữ liệu riêng. Ví dụ:
-
Việt Nam thường dùng
dd/MM/yyyycho ngày tháng. -
Hoa Kỳ thường dùng
MM/dd/yyyy. -
Nhiều quốc gia châu Âu sử dụng
dd.MM.yyyyhoặcdd/MM/yyyy. -
Việt Nam thường dùng dấu phẩy để biểu thị phần thập phân và dấu chấm để phân tách hàng nghìn.
-
Hoa Kỳ thường sử dụng dấu chấm cho phần thập phân và dấu phẩy cho hàng nghìn.
Những khác biệt này cần được xử lý thông qua quy tắc địa phương hóa thay vì viết cứng trong mã nguồn.
2.3. Giảm thiểu sai sót trong quá trình sử dụng
Một ngày như 05/06/2026 có thể được hiểu là ngày 5 tháng 6 hoặc ngày 6 tháng 5, tùy theo quy ước. Tương tự, 1,234 có thể đại diện cho một nghìn hai trăm ba mươi bốn hoặc một số thập phân tùy theo hệ thống định dạng.
Đối với các ứng dụng ngân hàng, thương mại điện tử, kế toán hoặc quản lý đơn hàng, sai lệch trong cách đọc dữ liệu có thể dẫn đến hậu quả đáng kể. Do đó, việc sử dụng định dạng nhất quán và phù hợp với khu vực là yêu cầu cần thiết.
2.4. Hỗ trợ quốc tế hóa và địa phương hóa
Date / Number / Currency Formatting có mối liên hệ chặt chẽ với hai khái niệm Internationalization (i18n) và Localization (l10n).
Internationalization giúp thiết kế ứng dụng có khả năng hỗ trợ nhiều ngôn ngữ và khu vực. Localization áp dụng các quy tắc cụ thể của từng khu vực, bao gồm ngôn ngữ, ngày tháng, số, tiền tệ và cách trình bày nội dung.
Ví dụ, một ứng dụng bán hàng có thể giữ nguyên logic tính toán và dữ liệu sản phẩm, nhưng hiển thị giá theo VND cho người dùng tại Việt Nam và USD cho người dùng tại Hoa Kỳ khi hệ thống hỗ trợ các thị trường tương ứng.
3. Date Formatting
Date Formatting là quá trình chuyển đổi dữ liệu ngày tháng thành chuỗi văn bản theo quy ước hiển thị cụ thể. Dữ liệu ngày tháng có thể bao gồm ngày, tháng, năm, giờ, phút, giây và múi giờ.
Trong ứng dụng, ngày tháng thường xuất hiện ở nhiều vị trí như ngày tạo tài khoản, ngày đặt hàng, lịch học, lịch làm việc, thời điểm đăng nhập, thời hạn hợp đồng và lịch sử giao dịch.
3.1. Các thành phần cơ bản của ngày tháng
Một giá trị ngày giờ có thể chứa các thành phần sau:
-
Year: Năm, ví dụ
2026. -
Month: Tháng, ví dụ
10. -
Day: Ngày trong tháng, ví dụ
17. -
Hour: Giờ, ví dụ
14. -
Minute: Phút, ví dụ
30. -
Second: Giây, ví dụ
45. -
Time zone: Múi giờ, giúp xác định thời điểm tương ứng tại một khu vực.
Tùy theo mục đích sử dụng, giao diện có thể chỉ hiển thị ngày tháng hoặc hiển thị đầy đủ cả thời gian.
Ví dụ:
| Kiểu hiển thị | Ví dụ |
|---|---|
| Ngày ngắn | 17/10/2026 |
| Ngày dài | 17 tháng 10, 2026 |
| Ngày kèm thứ | Thứ Bảy, 17/10/2026 |
| Giờ 24 tiếng | 14:30 |
| Giờ 12 tiếng | 2:30 PM |
| Ngày và giờ | 17/10/2026 14:30 |
Các định dạng trong bảng chỉ là ví dụ minh họa. Cách hiển thị thực tế còn phụ thuộc vào locale, thư viện và cấu hình của ứng dụng.
3.2. Các quy ước định dạng ngày tháng
Một trong những vấn đề quan trọng nhất của Date Formatting là thứ tự ngày, tháng và năm.
Ví dụ với ngày 17 tháng 10 năm 2026:
-
Việt Nam:
17/10/2026. -
Hoa Kỳ:
10/17/2026. -
Nhật Bản:
2026/10/17. -
Dạng ISO thường dùng để biểu diễn ngày:
2026-10-17.
Trong đó, định dạng ISO 8601 có ý nghĩa quan trọng khi trao đổi dữ liệu giữa các hệ thống. Một timestamp đầy đủ có thể chứa cả ngày, giờ và thông tin múi giờ, chẳng hạn 2026-10-17T14:30:00+07:00.
Không nên xem chuỗi ngày tháng dành cho giao diện là định dạng trao đổi dữ liệu mặc định. Một hệ thống có thể lưu trữ hoặc truyền dữ liệu theo chuẩn thống nhất, sau đó định dạng riêng cho từng locale khi hiển thị.
3.3. Date Formatting trong JavaScript
JavaScript cung cấp đối tượng Date để biểu diễn ngày giờ và Intl.DateTimeFormat để định dạng ngày giờ theo locale.
Ví dụ:
const date = new Date("2026-10-17T14:30:00+07:00");
const viFormatter = new Intl.DateTimeFormat("vi-VN", {
day: "2-digit",
month: "2-digit",
year: "numeric",
timeZone: "Asia/Ho_Chi_Minh",
});
const usFormatter = new Intl.DateTimeFormat("en-US", {
month: "2-digit",
day: "2-digit",
year: "numeric",
timeZone: "America/New_York",
});
console.log(viFormatter.format(date));
console.log(usFormatter.format(date));
Kết quả dự kiến:
17/10/2026
10/17/2026
Hai formatter sử dụng cùng một thời điểm nhưng trình bày ngày theo quy ước của hai locale khác nhau. Múi giờ được chỉ định rõ để tránh phụ thuộc vào cấu hình mặc định của thiết bị.
Một ví dụ hiển thị ngày đầy đủ:
const date = new Date("2026-10-17T14:30:00+07:00");
const formatter = new Intl.DateTimeFormat("vi-VN", {
weekday: "long",
day: "numeric",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
timeZone: "Asia/Ho_Chi_Minh",
});
console.log(formatter.format(date));
Cấu hình này cho phép trình duyệt tự lựa chọn cách trình bày tên thứ, tháng và giờ phù hợp với tiếng Việt. Lập trình viên không cần tự nối từng thành phần ngày giờ thành chuỗi.
3.4. Date Formatting trong Flutter
Trong Flutter, thư viện intl được sử dụng phổ biến để định dạng ngày tháng và số liệu theo locale.
Cài đặt thư viện trong dự án:
flutter pub add intl
Ví dụ định dạng ngày tháng:
import 'package:intl/intl.dart';
void main() {
final date = DateTime(2026, 10, 17);
final vietnameseDate = DateFormat(
'dd/MM/yyyy',
'vi_VN',
).format(date);
final readableDate = DateFormat(
'd MMMM yyyy',
'vi_VN',
).format(date);
print(vietnameseDate);
print(readableDate);
}
Kết quả minh họa:
17/10/2026
17 tháng 10 năm 2026
Một số ký hiệu thường gặp trong mẫu định dạng:
-
d: Ngày trong tháng. -
dd: Ngày có hai chữ số. -
M: Tháng dưới dạng số. -
MM: Tháng có hai chữ số. -
MMM: Tên tháng viết tắt. -
MMMM: Tên tháng đầy đủ theo locale. -
yy: Năm hai chữ số. -
yyyy: Năm bốn chữ số. -
HH: Giờ theo hệ 24 tiếng. -
hh: Giờ theo hệ 12 tiếng. -
mm: Phút. -
ss: Giây.
Cần phân biệt chữ hoa và chữ thường trong mẫu định dạng. Chẳng hạn, MM thường biểu thị tháng, trong khi mm biểu thị phút.
Đối với các ứng dụng Flutter có hỗ trợ nhiều ngôn ngữ, cần cấu hình locale phù hợp và kiểm tra dữ liệu locale trước khi sử dụng những định dạng phụ thuộc ngôn ngữ. Định dạng ngày giờ cũng cần được thống nhất giữa các màn hình để tránh mỗi thành phần hiển thị một kiểu.
3.5. Xử lý múi giờ và thời điểm
Múi giờ là một phần quan trọng trong xử lý ngày giờ. Cùng một thời điểm có thể tương ứng với các giờ địa phương khác nhau tại những khu vực khác nhau.
Ví dụ, một giao dịch được ghi nhận vào buổi sáng tại Việt Nam có thể tương ứng với thời điểm tối hôm trước tại một khu vực ở châu Mỹ.
Cần phân biệt:
-
Date: Ngày lịch, chẳng hạn ngày sinh hoặc ngày nghỉ lễ.
-
Local date-time: Ngày và giờ địa phương chưa nhất thiết xác định một thời điểm toàn cầu duy nhất.
-
Instant/timestamp: Một thời điểm cụ thể trên dòng thời gian.
-
Time zone: Quy tắc xác định giờ địa phương theo khu vực và thời gian lịch sử.
Với dữ liệu giao dịch, đăng nhập hoặc đặt hàng, hệ thống thường cần xác định chính xác thời điểm xảy ra sự kiện. Backend có thể chuẩn hóa thời điểm theo UTC và frontend chuyển đổi sang múi giờ của người dùng khi hiển thị.
Ngược lại, ngày sinh hoặc ngày kỷ niệm thường chỉ là ngày lịch. Nếu chuyển đổi không phù hợp giữa UTC và giờ địa phương, ngày có thể bị lùi hoặc tiến một ngày.
Các lỗi phổ biến cần tránh gồm tự cộng hoặc trừ số giờ cố định mà không xét quy tắc múi giờ, phân tích chuỗi ngày thiếu thông tin múi giờ và sử dụng ngày giờ địa phương như thể đó luôn là timestamp toàn cầu.
4. Number Formatting
Number Formatting là quá trình trình bày các giá trị số theo quy ước dễ đọc, bao gồm dấu phân cách hàng nghìn, dấu thập phân, số chữ số sau dấu thập phân và cách biểu diễn số lớn hoặc số nhỏ.
Định dạng số xuất hiện trong thống kê, bảng báo cáo, biểu đồ, bảng giá, số lượng sản phẩm, điểm số, chỉ số hiệu suất và các phép tính trong ứng dụng.
4.1. Các thành phần của định dạng số
Một giá trị số có thể được hiển thị theo nhiều cách:
-
Số nguyên:
1500. -
Số có phần thập phân:
1500.75. -
Số có dấu phân cách hàng nghìn:
1,500.75. -
Số theo quy ước Việt Nam:
1.500,75. -
Số được làm tròn:
1.501. -
Số có số chữ số thập phân cố định:
1.500,75.
Việc lựa chọn định dạng phụ thuộc vào mục đích hiển thị. Số lượng sản phẩm thường không cần phần thập phân, trong khi tỷ lệ, trọng lượng hoặc đơn giá có thể cần nhiều chữ số thập phân hơn.
4.2. Phân biệt dấu thập phân và dấu phân cách hàng nghìn
Dấu thập phân và dấu phân cách hàng nghìn là hai thành phần dễ gây nhầm lẫn khi ứng dụng hỗ trợ nhiều locale.
Ví dụ, giá trị 1234567.89 có thể được hiển thị như sau:
| Locale | Kết quả minh họa |
|---|---|
vi-VN |
1.234.567,89 |
en-US |
1,234,567.89 |
de-DE |
1.234.567,89 |
fr-FR |
1 234 567,89 |
Các quy ước này không chỉ thay đổi dấu chấm và dấu phẩy. Một số locale sử dụng khoảng trắng để phân tách nhóm chữ số. Quy tắc thực tế được xác định bởi dữ liệu locale và thư viện định dạng.
4.3. Number Formatting trong JavaScript
JavaScript cung cấp Intl.NumberFormat để định dạng số theo locale.
const number = 1234567.891;
const vietnameseFormatter = new Intl.NumberFormat("vi-VN", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
const usFormatter = new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
console.log(vietnameseFormatter.format(number));
console.log(usFormatter.format(number));
Kết quả:
1.234.567,89
1,234,567.89
Ở ví dụ này, minimumFractionDigits xác định số chữ số thập phân tối thiểu, còn maximumFractionDigits xác định số chữ số thập phân tối đa.
Khi cả hai đều bằng 2, kết quả được hiển thị với hai chữ số thập phân. Nếu giá trị đầu vào có nhiều chữ số hơn giới hạn, kết quả sẽ được làm tròn theo quy tắc của bộ định dạng.
Một ví dụ khác dành cho số nguyên:
const quantity = 1500000;
const formatter = new Intl.NumberFormat("vi-VN", {
maximumFractionDigits: 0,
});
console.log(formatter.format(quantity));
Kết quả:
1.500.000
Đây là cách phù hợp khi hiển thị số lượng, lượt truy cập hoặc những chỉ số không cần phần thập phân.
4.4. Định dạng phần trăm
Phần trăm thường được sử dụng để biểu diễn tỷ lệ giảm giá, tỷ lệ hoàn thành, mức tăng trưởng và các chỉ số phân tích.
Với Intl.NumberFormat, giá trị 0.25 được định dạng thành 25% khi sử dụng kiểu percent.
const ratio = 0.256;
const formatter = new Intl.NumberFormat("vi-VN", {
style: "percent",
maximumFractionDigits: 1,
});
console.log(formatter.format(ratio));
Kết quả:
25,6%
Điểm cần lưu ý là giá trị đầu vào của phần trăm thường được biểu diễn dưới dạng tỷ lệ. Nếu truyền 25.6 thay vì 0.256, kết quả sẽ tương ứng với 2560%, không phải 25,6%.
4.5. Định dạng số lớn và số rút gọn
Trong các dashboard quản trị, báo cáo doanh thu hoặc hệ thống phân tích dữ liệu, số liệu lớn có thể chiếm nhiều không gian trên giao diện.
Ví dụ:
-
1500000có thể được hiển thị thành1,5 triệu. -
2500000000có thể được hiển thị thành2,5 tỷ. -
1234567có thể được hiển thị thành1,23 triệunếu ứng dụng quy định cách làm tròn tương ứng.
JavaScript hỗ trợ notation: "compact" để tạo cách biểu diễn rút gọn theo locale.
const revenue = 1500000;
const formatter = new Intl.NumberFormat("vi-VN", {
notation: "compact",
maximumFractionDigits: 1,
});
console.log(formatter.format(revenue));
Cách rút gọn cụ thể có thể khác nhau theo môi trường và dữ liệu locale. Vì vậy, nếu ứng dụng yêu cầu thuật ngữ thống nhất như “triệu đồng” hoặc “tỷ đồng”, cần kiểm tra kết quả thực tế và xác định quy tắc hiển thị rõ ràng.
5. Currency Formatting
Currency Formatting là quá trình định dạng giá trị tiền tệ theo mã tiền tệ, quy ước địa phương, vị trí ký hiệu và số chữ số thập phân thích hợp.
Đây là thành phần quan trọng trong các hệ thống thương mại điện tử, ứng dụng ngân hàng, quản lý hóa đơn, kế toán, ví điện tử và nền tảng thanh toán.
5.1. Các thành phần của định dạng tiền tệ
Một giá trị tiền tệ thường bao gồm:
-
Giá trị số.
-
Mã tiền tệ.
-
Ký hiệu tiền tệ.
-
Quy tắc phân cách hàng nghìn.
-
Quy tắc hiển thị phần thập phân.
-
Vị trí ký hiệu và khoảng trắng.
-
Quy tắc làm tròn phù hợp với đơn vị tiền tệ.
Một số mã tiền tệ thường gặp:
| Mã tiền tệ | Loại tiền |
|---|---|
VND |
Đồng Việt Nam |
USD |
Đô la Mỹ |
EUR |
Euro |
JPY |
Yên Nhật |
GBP |
Bảng Anh |
SGD |
Đô la Singapore |
Mã tiền tệ rất quan trọng vì ký hiệu có thể trùng nhau giữa các loại tiền. Chẳng hạn, ký hiệu $ có thể được dùng cho nhiều đồng tiền khác nhau. Trong các hệ thống có nhiều thị trường, nên xác định rõ mã tiền tệ thay vì chỉ lưu ký hiệu.
5.2. Currency Formatting trong JavaScript
Intl.NumberFormat hỗ trợ định dạng tiền tệ thông qua tùy chọn style: "currency" và thuộc tính currency.
Ví dụ định dạng tiền Việt Nam:
const price = 1500000;
const formatter = new Intl.NumberFormat("vi-VN", {
style: "currency",
currency: "VND",
});
console.log(formatter.format(price));
Kết quả thường gặp:
1.500.000 ₫
Ví dụ định dạng đô la Mỹ:
const price = 1500.75;
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});
console.log(formatter.format(price));
Kết quả:
$1,500.75
Cùng một mục đích hiển thị nhưng vị trí ký hiệu, dấu phân cách và số chữ số thập phân có thể khác nhau theo locale và loại tiền tệ.
5.3. Tùy chỉnh cách hiển thị tiền tệ
Intl.NumberFormat cung cấp một số tùy chọn quan trọng:
-
currencyDisplay: "symbol": Hiển thị ký hiệu tiền tệ. -
currencyDisplay: "code": Hiển thị mã nhưUSD. -
currencyDisplay: "name": Hiển thị tên tiền tệ theo locale. -
minimumFractionDigits: Số chữ số thập phân tối thiểu. -
maximumFractionDigits: Số chữ số thập phân tối đa. -
currencySign: "accounting": Hỗ trợ cách biểu diễn số âm theo quy ước kế toán ở những locale phù hợp.
Ví dụ:
const amount = 1234.5;
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
currencyDisplay: "code",
});
console.log(formatter.format(amount));
Kết quả minh họa:
USD 1,234.50
Khoảng trắng giữa mã tiền tệ và số có thể là ký tự khoảng trắng đặc biệt. Vì vậy, không nên dựa vào việc so sánh chuỗi bằng mắt hoặc tự giả định mọi khoảng trắng đều là dấu cách thông thường.
5.4. Currency Formatting trong Flutter
Flutter có thể sử dụng thư viện intl để định dạng tiền tệ.
import 'package:intl/intl.dart';
void main() {
const price = 1500000;
final formatter = NumberFormat.currency(
locale: 'vi_VN',
name: 'VND',
symbol: '₫',
decimalDigits: 0,
);
print(formatter.format(price));
}
Kết quả dự kiến:
1.500.000 ₫
Trong ví dụ trên:
-
localexác định quy ước định dạng. -
namexác định mã tiền tệ. -
symbolxác định ký hiệu hiển thị. -
decimalDigitsxác định số chữ số thập phân trong kết quả.
Cấu hình decimalDigits: 0 phù hợp với cách hiển thị thông thường của VND trong ví dụ này. Tuy nhiên, không nên áp dụng quy tắc đó cho mọi loại tiền tệ.
Đối với ứng dụng bán hàng, nên tạo một formatter dùng chung thay vì viết lại cấu hình ở từng widget. Cách làm này giúp giá sản phẩm, phí vận chuyển, giảm giá và tổng thanh toán được hiển thị nhất quán trên toàn bộ ứng dụng.
5.5. Phân biệt định dạng tiền tệ và tính toán tài chính
Một sai lầm phổ biến là sử dụng chuỗi tiền tệ đã định dạng làm dữ liệu đầu vào cho các phép tính.
Ví dụ, chuỗi 1.500.000 ₫ là nội dung dành cho giao diện, không phải giá trị số thích hợp để trực tiếp cộng hoặc trừ.
Quy trình đúng nên là:
-
Lưu giá trị tiền tệ dưới dạng dữ liệu số hoặc kiểu dữ liệu tiền tệ phù hợp.
-
Thực hiện phép tính trên dữ liệu gốc.
-
Áp dụng quy tắc làm tròn theo nghiệp vụ.
-
Định dạng kết quả theo locale khi hiển thị.
Với hệ thống tài chính, cần đặc biệt chú ý đến sai số số thực. Các kiểu số dấu phẩy động như JavaScript Number có thể không biểu diễn chính xác mọi giá trị thập phân. Hệ thống có thể sử dụng số nguyên theo đơn vị nhỏ nhất của tiền tệ hoặc thư viện decimal phù hợp, tùy yêu cầu nghiệp vụ.
Ví dụ, nếu một hệ thống lưu số tiền bằng đơn vị đồng Việt Nam, có thể lưu 1500000 dưới dạng số nguyên và chỉ chuyển sang chuỗi hiển thị khi cần. Với những đồng tiền có đơn vị nhỏ hơn hoặc phép tính phức tạp, cần thiết kế cách biểu diễn phù hợp thay vì mặc định tất cả tiền tệ đều có hai chữ số thập phân.
6. Locale và cơ chế định dạng theo khu vực
Locale là thông tin xác định ngôn ngữ và các quy ước trình bày dữ liệu của một khu vực. Locale có ảnh hưởng trực tiếp đến Date Formatting, Number Formatting và Currency Formatting.
Một locale thường được biểu diễn bằng mã ngôn ngữ và có thể đi kèm mã khu vực theo chuẩn BCP 47.
Ví dụ:
-
vi-VN: Tiếng Việt tại Việt Nam. -
en-US: Tiếng Anh tại Hoa Kỳ. -
en-GB: Tiếng Anh tại Vương quốc Anh. -
ja-JP: Tiếng Nhật tại Nhật Bản. -
fr-FR: Tiếng Pháp tại Pháp. -
de-DE: Tiếng Đức tại Đức.
6.1. Vai trò của locale trong định dạng dữ liệu
Locale cung cấp các quy ước để thư viện định dạng lựa chọn cách trình bày phù hợp. Thay vì tự xác định dấu phân cách hoặc vị trí ký hiệu tiền tệ, lập trình viên có thể sử dụng thông tin locale để hệ thống xử lý.
Ví dụ, trong JavaScript:
const number = 1234567.89;
console.log(
new Intl.NumberFormat("vi-VN").format(number)
);
console.log(
new Intl.NumberFormat("en-US").format(number)
);
console.log(
new Intl.NumberFormat("de-DE").format(number)
);
Kết quả minh họa:
1.234.567,89
1,234,567.89
1.234.567,89
Mặc dù tiếng Việt và tiếng Đức có thể sử dụng cách phân tách số tương tự trong ví dụ này, điều đó không có nghĩa hai locale hoàn toàn giống nhau. Quy tắc ngày tháng, tên tháng, đơn vị tiền tệ và nhiều thành phần khác vẫn có thể khác biệt.
6.2. Phân biệt locale, ngôn ngữ và múi giờ
Ba khái niệm này có mối liên hệ nhưng không thay thế cho nhau.
-
Language: Xác định ngôn ngữ hiển thị nội dung.
-
Locale: Xác định các quy ước định dạng ngày tháng, số và những dữ liệu phụ thuộc khu vực.
-
Time zone: Xác định cách chuyển đổi một thời điểm thành giờ địa phương.
Ví dụ, người dùng có thể chọn giao diện tiếng Anh nhưng vẫn muốn hiển thị số theo quy ước Việt Nam. Đồng thời, người dùng đó có thể đang sinh sống tại Nhật Bản và muốn xem thời gian theo múi giờ Nhật Bản.
Vì vậy, không nên mặc định rằng ngôn ngữ giao diện luôn quyết định toàn bộ cách định dạng dữ liệu.
6.3. Cơ sở dữ liệu locale và Unicode CLDR
Unicode CLDR (Common Locale Data Repository) là kho dữ liệu locale được duy trì trong hệ sinh thái Unicode. CLDR cung cấp thông tin về quy tắc ngày tháng, ký hiệu số, tiền tệ và nhiều dữ liệu phụ thuộc ngôn ngữ, khu vực.
Các thư viện quốc tế hóa có thể sử dụng dữ liệu locale để định dạng thông tin nhất quán mà không cần lập trình viên tự xây dựng toàn bộ quy tắc cho từng quốc gia.
7. Ứng dụng trong các hệ thống thực tế
Date / Number / Currency Formatting không chỉ xuất hiện trong những ví dụ đơn giản mà còn là thành phần quan trọng của kiến trúc ứng dụng.
7.1. Website thương mại điện tử
Trong website bán hàng, định dạng dữ liệu xuất hiện ở hầu hết các chức năng:
-
Ngày tạo đơn hàng.
-
Thời gian thanh toán.
-
Giá sản phẩm.
-
Số lượng tồn kho.
-
Phần trăm giảm giá.
-
Phí vận chuyển.
-
Tổng giá trị đơn hàng.
-
Thời gian dự kiến giao hàng.
Ví dụ, dữ liệu đơn hàng có thể được lưu trữ như sau:
const order = {
id: "ORD-20261017",
createdAt: "2026-10-17T07:30:00Z",
quantity: 2,
unitPrice: 1500000,
discountRate: 0.1,
};
Frontend có thể định dạng các trường dữ liệu khi hiển thị:
const locale = "vi-VN";
const dateFormatter = new Intl.DateTimeFormat(locale, {
dateStyle: "medium",
timeStyle: "short",
timeZone: "Asia/Ho_Chi_Minh",
});
const moneyFormatter = new Intl.NumberFormat(locale, {
style: "currency",
currency: "VND",
maximumFractionDigits: 0,
});
const numberFormatter = new Intl.NumberFormat(locale);
const total = order.quantity * order.unitPrice;
const discount = total * order.discountRate;
const finalTotal = total - discount;
console.log(dateFormatter.format(new Date(order.createdAt)));
console.log(numberFormatter.format(order.quantity));
console.log(moneyFormatter.format(total));
console.log(moneyFormatter.format(discount));
console.log(moneyFormatter.format(finalTotal));
Với dữ liệu trên, tổng tiền trước giảm giá là 3.000.000 đồng, số tiền giảm là 300.000 đồng và tổng tiền sau giảm giá là 2.700.000 đồng.
Ví dụ này chỉ minh họa việc định dạng dữ liệu. Trong hệ thống thực tế, backend vẫn phải kiểm tra giá sản phẩm, chính sách giảm giá, thuế và các quy tắc thanh toán. Không nên tin tưởng hoàn toàn vào phép tính do frontend gửi lên.
7.2. Dashboard quản trị và báo cáo
Trong dashboard, định dạng số giúp người quản trị nhanh chóng nắm bắt tình hình hoạt động.
Ví dụ, hệ thống có thể hiển thị:
-
Doanh thu trong ngày:
125.500.000 ₫. -
Tổng số đơn hàng:
1.250. -
Tỷ lệ chuyển đổi:
4,8%. -
Giá trị đơn hàng trung bình:
350.000 ₫. -
Thời điểm cập nhật:
17/10/2026, 14:30.
Các số liệu này nên được định dạng thông qua một bộ quy tắc dùng chung. Điều đó giúp giao diện tránh tình trạng một màn hình hiển thị 125,500,000, trong khi màn hình khác lại hiển thị 125.500.000.
Đối với biểu đồ, cần phân biệt giá trị thực tế được dùng để vẽ và chuỗi nhãn được hiển thị. Ví dụ, biểu đồ có thể sử dụng giá trị số 125500000, nhưng trục hoặc tooltip trình bày thành 125,5 triệu ₫.
7.3. Ứng dụng ngân hàng và tài chính
Các ứng dụng tài chính cần đặc biệt chú ý đến độ chính xác của giá trị tiền tệ, mã tiền tệ, quy tắc làm tròn và cách trình bày số âm.
Ví dụ, một giao dịch hoàn tiền có thể được hiển thị bằng số tiền dương kèm nhãn “Hoàn tiền”, trong khi một giao dịch chi tiêu được biểu diễn bằng số âm hoặc một dấu trừ ở vị trí phù hợp.
Tuy nhiên, cách hiển thị không được làm thay đổi ý nghĩa của giao dịch. Những thao tác như chuyển đổi ngoại tệ, tính phí, tính lãi và tổng hợp số dư phải tuân theo quy tắc nghiệp vụ riêng, không thể chỉ dựa vào formatter.
7.4. Ứng dụng lịch và quản lý công việc
Các ứng dụng lịch cần định dạng ngày tháng, thời gian và khoảng thời gian nhất quán.
Ví dụ:
-
Ngày bắt đầu công việc.
-
Hạn hoàn thành.
-
Thời gian họp.
-
Khoảng thời gian giữa hai sự kiện.
-
Thời gian còn lại trước hạn chót.
Đối với sự kiện diễn ra tại một địa điểm cụ thể, ứng dụng cần xử lý múi giờ phù hợp. Đối với một hạn chót chỉ bao gồm ngày lịch, hệ thống cần tránh tự động chuyển đổi ngày đó thành thời điểm ở múi giờ khác nếu điều đó làm thay đổi ngày người dùng đã chọn.
8. Xây dựng lớp định dạng dữ liệu dùng chung
Trong một dự án có nhiều màn hình, việc tạo formatter riêng tại từng vị trí sẽ dẫn đến mã nguồn lặp lại và khó bảo trì. Giải pháp phù hợp là xây dựng một lớp hoặc module định dạng dữ liệu dùng chung.
8.1. Xây dựng formatter trong JavaScript
Ví dụ, tạo file formatters.js:
const DEFAULT_LOCALE = "vi-VN";
const DEFAULT_TIME_ZONE = "Asia/Ho_Chi_Minh";
export function formatDate(value, locale = DEFAULT_LOCALE) {
if (value == null || value === "") {
return "";
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return "";
}
return new Intl.DateTimeFormat(locale, {
day: "2-digit",
month: "2-digit",
year: "numeric",
timeZone: DEFAULT_TIME_ZONE,
}).format(date);
}
export function formatNumber(value, locale = DEFAULT_LOCALE) {
if (typeof value !== "number" || !Number.isFinite(value)) {
return "";
}
return new Intl.NumberFormat(locale).format(value);
}
export function formatCurrency(
value,
currency = "VND",
locale = DEFAULT_LOCALE
) {
if (typeof value !== "number" || !Number.isFinite(value)) {
return "";
}
return new Intl.NumberFormat(locale, {
style: "currency",
currency,
}).format(value);
}
export function formatPercent(value, locale = DEFAULT_LOCALE) {
if (typeof value !== "number" || !Number.isFinite(value)) {
return "";
}
return new Intl.NumberFormat(locale, {
style: "percent",
maximumFractionDigits: 2,
}).format(value);
}
Cách sử dụng:
import {
formatDate,
formatNumber,
formatCurrency,
formatPercent,
} from "./formatters.js";
console.log(formatDate("2026-10-17T00:00:00Z"));
console.log(formatNumber(1234567.89));
console.log(formatCurrency(1500000));
console.log(formatPercent(0.256));
Đoạn mã trên có thể sử dụng trong ứng dụng JavaScript hoặc frontend framework có hỗ trợ module ES.
Có một điểm cần lưu ý: formatDate() đang cố ý quy định múi giờ Việt Nam. Nếu ứng dụng cần hỗ trợ nhiều múi giờ, nên đưa múi giờ vào cấu hình hoặc tham số thay vì cố định trong toàn bộ hệ thống.
Ngoài ra, trả về chuỗi rỗng khi dữ liệu không hợp lệ chỉ là một lựa chọn cho ví dụ này. Trong ứng dụng thực tế, có thể cần ghi log, hiển thị trạng thái không có dữ liệu hoặc báo lỗi tùy theo mục đích sử dụng.
8.2. Xây dựng formatter trong Flutter
Đối với Flutter, có thể tạo file formatters.dart để tập trung logic định dạng.
import 'package:intl/intl.dart';
class Formatters {
static String date(
DateTime value, {
String locale = 'vi_VN',
}) {
return DateFormat('dd/MM/yyyy', locale).format(value);
}
static String number(
num value, {
String locale = 'vi_VN',
}) {
return NumberFormat.decimalPattern(locale).format(value);
}
static String currency(
num value, {
String locale = 'vi_VN',
String name = 'VND',
String symbol = '₫',
int decimalDigits = 0,
}) {
return NumberFormat.currency(
locale: locale,
name: name,
symbol: symbol,
decimalDigits: decimalDigits,
).format(value);
}
static String percent(
num value, {
String locale = 'vi_VN',
}) {
return NumberFormat.percentPattern(locale).format(value);
}
}
Cách sử dụng:
void main() {
print(Formatters.date(DateTime(2026, 10, 17)));
print(Formatters.number(1234567.89));
print(Formatters.currency(1500000));
print(Formatters.percent(0.256));
}
Lớp Formatters giúp các widget gọi chung một API, giảm việc tạo formatter lặp lại và hỗ trợ thay đổi quy tắc hiển thị tập trung.
Trong dự án lớn, có thể mở rộng lớp này để nhận locale hiện tại của ứng dụng, cấu hình múi giờ, xử lý dữ liệu thiếu và thống nhất quy tắc định dạng giữa các màn hình.
9. Những lỗi phổ biến khi định dạng dữ liệu
9.1. Viết cứng định dạng theo một quốc gia
Việc tự nối ngày, tháng và năm bằng dấu gạch chéo có thể hoạt động với một locale nhưng không phù hợp với những khu vực khác.
Cách tốt hơn là sử dụng API quốc tế hóa hoặc thư viện định dạng có hỗ trợ locale.
9.2. Nhầm lẫn giữa định dạng và phân tích dữ liệu
Formatting chuyển giá trị có cấu trúc thành chuỗi hiển thị. Parsing thực hiện chiều ngược lại: chuyển dữ liệu đầu vào thành giá trị có thể xử lý.
Ví dụ, chuỗi 1.234,56 theo quy ước Việt Nam không thể được phân tích đúng bằng cách mặc định loại bỏ dấu phẩy hoặc chuyển thẳng sang kiểu số của JavaScript.
Đối với dữ liệu nhập từ người dùng, cần xác định locale, quy tắc phân tích và xử lý dữ liệu không hợp lệ một cách rõ ràng.
9.3. Sử dụng chuỗi đã định dạng để tính toán
Không nên thực hiện phép tính trực tiếp trên những chuỗi như 1.500.000 ₫ hoặc 25,6%.
Các chuỗi này có thể chứa dấu phân cách, ký hiệu tiền tệ hoặc ký tự đặc biệt. Chúng phục vụ việc hiển thị, không phải biểu diễn số học.
9.4. Bỏ qua múi giờ
Việc chuyển đổi ngày giờ không đúng có thể khiến thời gian giao dịch, lịch hẹn hoặc ngày tạo bản ghi bị lệch.
Cần xác định rõ dữ liệu biểu diễn một ngày lịch hay một thời điểm cụ thể, đồng thời quy định múi giờ khi chuyển đổi sang chuỗi.
9.5. Làm tròn không nhất quán
Một màn hình có thể hiển thị giá trị với hai chữ số thập phân, trong khi màn hình khác làm tròn về số nguyên. Nếu không có quy tắc thống nhất, dữ liệu có thể tạo cảm giác không khớp.
Đối với tiền tệ, cần phân biệt làm tròn khi tính toán nghiệp vụ với việc làm tròn phục vụ hiển thị.
9.6. Mặc định mọi loại tiền tệ đều có hai chữ số thập phân
Các đồng tiền không sử dụng cùng một quy ước về đơn vị nhỏ. Một số loại tiền thường được hiển thị không có chữ số thập phân, trong khi những loại khác thường dùng hai chữ số.
Nên để thư viện định dạng xử lý quy tắc mặc định theo mã tiền tệ, trừ khi nghiệp vụ yêu cầu một cách hiển thị cụ thể.
9.7. Không kiểm tra dữ liệu đầu vào
Các giá trị null, undefined, chuỗi rỗng, ngày không hợp lệ, NaN hoặc Infinity có thể tạo ra kết quả không mong muốn.
Formatter dùng chung nên xác định cách xử lý những trường hợp này. Đối với các màn hình tài chính, cần đặc biệt tránh hiển thị một chuỗi có vẻ hợp lệ khi dữ liệu gốc thực chất bị lỗi.
10. Nguyên tắc triển khai và kiểm thử
Để triển khai Date / Number / Currency Formatting hiệu quả, cần xây dựng quy tắc rõ ràng từ tầng dữ liệu đến tầng giao diện.
10.1. Tách dữ liệu gốc khỏi chuỗi hiển thị
Dữ liệu gốc nên giữ nguyên kiểu dữ liệu phù hợp với mục đích sử dụng. Ngày giờ, số lượng và giá trị tiền tệ không nên bị chuyển thành chuỗi định dạng quá sớm.
Giao diện chỉ nên chuyển đổi sang chuỗi ở thời điểm cần hiển thị. Cách tiếp cận này giúp tái sử dụng dữ liệu trong phép tính, sắp xếp, lọc và xử lý nghiệp vụ.
10.2. Thống nhất quy tắc trong toàn bộ dự án
Một ứng dụng nên có quy ước chung về định dạng ngày, giờ, số, phần trăm và tiền tệ. Các formatter nên được tổ chức thành module hoặc lớp dùng chung để tránh sao chép logic giữa những màn hình.
Khi ứng dụng hỗ trợ nhiều locale, cần xác định rõ nguồn cung cấp locale hiện tại và cách các formatter nhận cấu hình đó.
10.3. Kiểm thử nhiều locale
Không nên chỉ kiểm tra ứng dụng bằng một locale duy nhất. Những trường hợp cần kiểm thử bao gồm:
-
Ngày có một chữ số và ngày có hai chữ số.
-
Tháng đầu năm và tháng cuối năm.
-
Ngày nhuận.
-
Thời điểm gần nửa đêm.
-
Số nguyên và số có nhiều chữ số thập phân.
-
Giá trị âm và giá trị bằng không.
-
Tiền tệ có quy tắc chữ số thập phân khác nhau.
-
Giá trị lớn vượt quá kích thước hiển thị thông thường.
-
Dữ liệu thiếu hoặc không hợp lệ.
Khi kiểm thử, nên ưu tiên kiểm tra hành vi và quy tắc mong muốn. Nếu ứng dụng phụ thuộc vào dữ liệu locale của môi trường, cần tránh giả định mọi trình duyệt hoặc phiên bản thư viện đều tạo ra chuỗi hoàn toàn giống nhau trong tất cả trường hợp.
10.4. Kiểm thử tính chính xác của dữ liệu
Formatter chỉ chịu trách nhiệm về cách trình bày. Những kiểm thử về tính đúng đắn của phép tính, quy tắc làm tròn, tỷ giá và thời điểm giao dịch cần được thực hiện riêng.
Đặc biệt, đối với ứng dụng thương mại điện tử hoặc tài chính, cần xác minh rằng việc định dạng không làm thay đổi giá trị gốc và việc phân tích dữ liệu đầu vào không tạo ra sai lệch số học.
10.5. Đảm bảo khả năng bảo trì và mở rộng
Khi ứng dụng bổ sung thị trường mới, lập trình viên nên có thể thêm locale hoặc điều chỉnh cấu hình mà không phải sửa từng widget.
Cách tổ chức hợp lý thường bao gồm:
-
Module định dạng ngày giờ.
-
Module định dạng số và phần trăm.
-
Module định dạng tiền tệ.
-
Cấu hình locale và múi giờ.
-
Bộ kiểm thử cho các trường hợp quan trọng.
Cách tổ chức này giúp giảm lỗi, cải thiện khả năng tái sử dụng và tạo nền tảng tốt cho việc mở rộng ứng dụng đa ngôn ngữ.
11. Kết luận
Date / Number / Currency Formatting là một phần thiết yếu trong quá trình xây dựng ứng dụng hiện đại. Việc định dạng đúng ngày tháng, số và tiền tệ giúp dữ liệu dễ đọc, giảm nhầm lẫn và tạo trải nghiệm nhất quán cho người dùng ở nhiều quốc gia.
Lập trình viên cần phân biệt rõ dữ liệu gốc với chuỗi hiển thị, hiểu vai trò của locale, xử lý múi giờ chính xác và sử dụng các thư viện định dạng phù hợp như Intl.DateTimeFormat, Intl.NumberFormat trong JavaScript hoặc intl trong Flutter.
Đối với các dự án lớn, việc xây dựng module formatter dùng chung, thống nhất quy tắc hiển thị và kiểm thử nhiều locale sẽ giúp mã nguồn dễ bảo trì và mở rộng. Đối với các hệ thống tài chính, cần bổ sung những quy tắc riêng về độ chính xác số học, đơn vị tiền tệ và làm tròn nghiệp vụ.
Tóm lại, định dạng dữ liệu không chỉ là bước làm đẹp giao diện. Đây là một phần của thiết kế hệ thống, ảnh hưởng trực tiếp đến tính dễ hiểu, tính nhất quán và độ tin cậy của ứng dụng.








Khoá học lập trình game con rắn cho trẻ em




