1. Date / Number / Currency Formatting là gì?
Trong một ứng dụng Flutter, dữ liệu thường được lưu trữ và xử lý dưới dạng số, ngày giờ hoặc các kiểu dữ liệu có cấu trúc.
Tuy nhiên, dữ liệu dùng để tính toán không nhất thiết giống với cách dữ liệu được hiển thị cho người dùng.
Ví dụ, hệ thống lưu giá sản phẩm là:
1500000
Nếu hiển thị trực tiếp, người dùng có thể phải tự đọc và phân tách các chữ số.
Trong giao diện tiếng Việt, giá trị này có thể được trình bày thành:
1.500.000 ₫
Tương tự, một ngày được lưu dưới dạng dữ liệu thời gian có thể được hiển thị là 25/12/2026, 12/25/2026 hoặc một cách viết khác tùy theo locale.
Formatting là quá trình chuyển đổi cách biểu diễn dữ liệu thành chuỗi văn bản theo một định dạng hoặc quy ước xác định, nhằm giúp người dùng đọc và hiểu thông tin dễ dàng hơn.
Trong Flutter, ba nhóm định dạng phổ biến là:
Date Formatting: Định dạng ngày và giờ.
Number Formatting: Định dạng số.
Currency Formatting: Định dạng giá trị tiền tệ.
Các công việc này thường được thực hiện bằng package intl.
2. Vì sao cần Formatting?
Formatting giúp ứng dụng trình bày dữ liệu rõ ràng, nhất quán và phù hợp với người dùng.
Ví dụ, trong một ứng dụng bán hàng, nếu trang sản phẩm hiển thị 1500000, giỏ hàng hiển thị 1,500,000 và trang thanh toán hiển thị 1.500.000đ, người dùng có thể cảm thấy giao diện thiếu nhất quán.
Ngoài ra, khi ứng dụng hỗ trợ nhiều quốc gia, cách trình bày dữ liệu có thể khác nhau.
Formatting giúp giải quyết những vấn đề này mà không cần thay đổi giá trị gốc của dữ liệu.
Điểm quan trọng là Formatting chỉ thay đổi cách biểu diễn dữ liệu, không nhất thiết thay đổi giá trị dữ liệu.
Ví dụ, số 1500000 vẫn là một triệu năm trăm nghìn, dù được hiển thị bằng dấu chấm hay dấu phẩy phân cách hàng nghìn.
3. Phân biệt Formatting và Parsing
Formatting và Parsing là hai quá trình có hướng xử lý khác nhau.
Formatting chuyển dữ liệu có cấu trúc thành chuỗi hiển thị.
Ví dụ:
1500000 → "1.500.000"
Parsing phân tích chuỗi văn bản để tạo ra dữ liệu có cấu trúc.
Ví dụ:
"1.500.000" → 1500000
Hai quá trình này thường xuất hiện trong biểu mẫu nhập liệu.
Ví dụ, khi người dùng nhập số tiền bằng chuỗi văn bản, ứng dụng có thể cần phân tích chuỗi đó thành giá trị số để xử lý.
Tuy nhiên, việc Parsing phải dựa trên quy ước định dạng phù hợp.
Không nên tùy tiện xóa tất cả dấu chấm hoặc dấu phẩy vì những ký tự này có thể mang ý nghĩa khác nhau giữa các locale.
4. Package intl trong Flutter
Package intl hỗ trợ nhiều chức năng quốc tế hóa trong Dart và Flutter.
Để sử dụng:
flutter pub add intl
Sau đó import:
import 'package:intl/intl.dart';
Một số lớp thường được sử dụng gồm:
DateFormat: Định dạng và phân tích ngày giờ.
NumberFormat: Định dạng và phân tích số.
Các phương thức liên quan đến currency giúp định dạng giá trị tiền tệ theo locale và mã tiền tệ.
Package intl không tự động quyết định toàn bộ quy tắc nghiệp vụ của ứng dụng. Lập trình viên vẫn cần xác định dữ liệu đang biểu diễn điều gì và cần hiển thị theo quy ước nào.
5. Date Formatting là gì?
Date Formatting là quá trình chuyển giá trị ngày giờ thành chuỗi văn bản theo định dạng mong muốn.
Ví dụ, cùng một ngày 25 tháng 12 năm 2026 có thể hiển thị:
25/12/2026
12/25/2026
25-12-2026
25 tháng 12 năm 2026
Các cách hiển thị này có thể phù hợp với những tình huống khác nhau.
Ví dụ, trong danh sách đơn hàng, ứng dụng có thể sử dụng định dạng ngắn để tiết kiệm diện tích.
Trong trang chi tiết đơn hàng, ứng dụng có thể hiển thị đầy đủ ngày và giờ.
6. Định dạng ngày bằng DateFormat
Ví dụ:
import 'package:intl/intl.dart';
void main() {
final date = DateTime(2026, 12, 25);
final formatted =
DateFormat('dd/MM/yyyy').format(date);
print(formatted);
}
Kết quả:
25/12/2026
Trong đó:
dd: Ngày với hai chữ số.
MM: Tháng với hai chữ số.
yyyy: Năm với bốn chữ số.
Các ký hiệu này phân biệt chữ hoa và chữ thường.
Ví dụ, MM biểu diễn tháng, trong khi mm biểu diễn phút.
Đây là lỗi rất dễ gặp khi mới sử dụng DateFormat.
7. Một số mẫu DateFormat phổ biến
| Mẫu | Ví dụ kết quả | Ý nghĩa |
|---|---|---|
dd/MM/yyyy |
25/12/2026 | Ngày/tháng/năm |
MM/dd/yyyy |
12/25/2026 | Tháng/ngày/năm |
yyyy-MM-dd |
2026-12-25 | Năm-tháng-ngày |
HH:mm |
14:30 | Giờ 24 tiếng |
hh:mm a |
02:30 PM | Giờ 12 tiếng |
dd/MM/yyyy HH:mm |
25/12/2026 14:30 | Ngày và giờ |
Cần lưu ý rằng việc sử dụng một pattern cố định có thể không phản ánh đầy đủ quy ước của mọi locale.
Nếu mục tiêu là hiển thị tự nhiên theo ngôn ngữ và khu vực, nên cân nhắc những phương thức định dạng theo locale.
8. DateFormat theo Locale
Ví dụ:
final date = DateTime(2026, 12, 25);
final vi =
DateFormat.yMd('vi_VN').format(date);
final en =
DateFormat.yMd('en_US').format(date);
Hai biến trên sử dụng những quy ước ngày ngắn theo locale tương ứng.
Ưu điểm của việc sử dụng các constructor như yMd() là thư viện có thể lựa chọn mẫu định dạng phù hợp dựa trên dữ liệu locale.
Với những định dạng sử dụng tên tháng hoặc thứ, có thể cần khởi tạo dữ liệu locale theo cách package intl yêu cầu, tùy môi trường và loại định dạng.
Ví dụ:
import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl.dart';
Future<void> main() async {
await initializeDateFormatting('vi_VN');
final date = DateTime(2026, 12, 25);
print(
DateFormat.yMMMMd('vi_VN').format(date),
);
}
Ví dụ này minh họa cách chuẩn bị dữ liệu định dạng ngày theo locale.
9. Phân biệt giờ 12 tiếng và 24 tiếng
Một số giao diện sử dụng hệ thống 24 giờ.
Ví dụ:
14:30
23:15
Một số giao diện sử dụng hệ thống 12 giờ với AM và PM.
Ví dụ:
02:30 PM
11:15 PM
Trong DateFormat:
HH biểu diễn giờ theo hệ thống 24 giờ.
hh biểu diễn giờ theo hệ thống 12 giờ.
a biểu diễn ký hiệu AM/PM theo dữ liệu locale.
Ví dụ:
final date = DateTime(2026, 12, 25, 14, 30);
print(
DateFormat('HH:mm').format(date),
);
print(
DateFormat('hh:mm a', 'en_US').format(date),
);
Khi thiết kế ứng dụng, nên sử dụng quy ước phù hợp với locale hoặc cho phép người dùng lựa chọn khi sản phẩm có yêu cầu đó.
10. Number Formatting là gì?
Number Formatting là quá trình trình bày giá trị số theo một định dạng xác định.
Ví dụ:
1500000
Có thể được hiển thị thành:
1.500.000
hoặc:
1,500,000
Tùy theo locale.
Việc định dạng số thường liên quan đến:
- 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.
- Dấu phần trăm.
- Quy tắc làm tròn.
11. Định dạng số bằng NumberFormat
Ví dụ:
import 'package:intl/intl.dart';
void main() {
const value = 1234567.89;
final vi =
NumberFormat.decimalPattern('vi_VN');
final en =
NumberFormat.decimalPattern('en_US');
print(vi.format(value));
print(en.format(value));
}
Theo quy ước thông thường, kết quả có thể được trình bày như:
1.234.567,89
1,234,567.89
Ở đây, giá trị số không thay đổi.
Chỉ có cách hiển thị khác nhau.
12. Định dạng số thập phân
Trong nhiều ứng dụng, không phải lúc nào cũng cần hiển thị toàn bộ chữ số thập phân.
Ví dụ, một sản phẩm có điểm đánh giá trung bình là:
4.666666
Nếu hiển thị trực tiếp, giao diện sẽ khó đọc.
Có thể sử dụng:
final formatter =
NumberFormat('0.0', 'vi_VN');
print(formatter.format(4.666666));
Kết quả theo quy ước tiếng Việt:
4,7
Ở đây, số được làm tròn khi định dạng.
Điều quan trọng là không nên nhầm việc làm tròn để hiển thị với việc thay đổi dữ liệu gốc.
Nếu hệ thống cần tính toán chính xác, nên giữ giá trị phù hợp cho xử lý và chỉ định dạng ở lớp giao diện.
13. Percentage Formatting
Trong ứng dụng bán hàng, phần trăm thường xuất hiện ở giảm giá, tỷ lệ hoàn thành hoặc báo cáo.
Ví dụ:
final formatter =
NumberFormat.percentPattern('vi_VN');
print(formatter.format(0.15));
Giá trị 0.15 biểu diễn tỷ lệ 15%.
Điều này rất quan trọng vì một số lập trình viên nhầm rằng phải truyền số 15 để hiển thị 15%.
Với NumberFormat.percentPattern, đầu vào thường là tỷ lệ dạng số thập phân.
Nếu truyền 15, kết quả sẽ tương ứng với 1500%, không phải 15%.
Do đó, cần thống nhất cách biểu diễn tỷ lệ trong dữ liệu nghiệp vụ.
14. Currency Formatting là gì?
Currency Formatting là quá trình hiển thị giá trị tiền theo mã tiền tệ và quy ước của locale.
Ví dụ:
150000
Có thể được hiển thị thành:
150.000 ₫
nếu đang biểu diễn đồng Việt Nam.
Hoặc:
$150,000.00
nếu giá trị đang biểu diễn đô la Mỹ và sử dụng quy ước phù hợp.
Tuy nhiên, hai cách hiển thị này không phải là hai giá trị tiền tương đương.
Định dạng không thực hiện chuyển đổi tỷ giá.
15. Định dạng VND trong Flutter
Ví dụ:
import 'package:intl/intl.dart';
void main() {
final formatter = NumberFormat.currency(
locale: 'vi_VN',
symbol: '₫',
decimalDigits: 0,
);
print(formatter.format(1500000));
}
Kết quả thường có dạng:
1.500.000 ₫
Trong đó:
locale: 'vi_VN' xác định quy ước định dạng.
symbol: '₫' xác định ký hiệu hiển thị.
decimalDigits: 0 yêu cầu không hiển thị chữ số thập phân.
Đối với ứng dụng bán hàng tại Việt Nam, đây là một cách định dạng thường gặp.
Tuy nhiên, nếu cần hỗ trợ nhiều loại tiền tệ, nên sử dụng mã tiền tệ rõ ràng.
16. Định dạng USD
Ví dụ:
final formatter = NumberFormat.currency(
locale: 'en_US',
name: 'USD',
symbol: '\$',
decimalDigits: 2,
);
print(formatter.format(1500.5));
Kết quả:
$1,500.50
Trong ví dụ này, 1500.5 được hiểu là 1.500,5 USD.
Không nên lấy giá trị 1.500.000 VND rồi chỉ đổi ký hiệu thành $, vì điều đó sẽ làm sai ý nghĩa tiền tệ.
17. Phân biệt Currency Formatting và Currency Conversion
Đây là hai khái niệm rất dễ nhầm lẫn.
Currency Formatting là định dạng cách hiển thị một giá trị tiền.
Currency Conversion là quy đổi giá trị từ loại tiền này sang loại tiền khác dựa trên tỷ giá.
Ví dụ, hệ thống lưu một giá trị 100 USD.
Nếu chỉ định dạng theo locale Việt Nam, ứng dụng có thể thay đổi cách sử dụng dấu phân cách hoặc cách hiển thị mã tiền, nhưng giá trị vẫn là 100 USD.
Muốn chuyển 100 USD sang VND, hệ thống cần tỷ giá phù hợp và quy tắc làm tròn.
Vì vậy, không được thực hiện quy đổi tiền chỉ bằng cách thay locale hoặc ký hiệu tiền tệ.
18. Vấn đề độ chính xác khi xử lý tiền
Trong lập trình, kiểu double sử dụng biểu diễn số dấu phẩy động.
Một số giá trị thập phân không thể được biểu diễn chính xác tuyệt đối dưới dạng nhị phân.
Ví dụ, trong nhiều ngôn ngữ lập trình, phép cộng 0.1 + 0.2 có thể cho kết quả gần với 0.3 nhưng không hoàn toàn bằng 0.3.
Nếu ứng dụng thực hiện những phép tính tiền quan trọng, sai số có thể gây ra vấn đề.
Một phương pháp thường được sử dụng là lưu số tiền theo đơn vị nhỏ nhất bằng số nguyên, khi phù hợp với loại tiền.
Ví dụ, đối với VND không sử dụng phần thập phân trong nghiệp vụ, có thể lưu:
final priceVnd = 150000;
Đối với USD, hệ thống có thể lưu số cent:
final priceInCents = 1099;
Giá trị 1099 cent tương ứng với 10,99 USD.
Một phương pháp khác là sử dụng kiểu Decimal hoặc cơ chế tính toán tiền chuyên dụng.
Điều quan trọng là phải xác định đơn vị lưu trữ và quy tắc làm tròn rõ ràng, nhất là khi Frontend và Backend cùng tham gia xử lý thanh toán.
19. Parsing số từ ô nhập liệu
Giả sử người dùng nhập:
1.500.000
Ứng dụng cần chuyển chuỗi thành số để xử lý.
Có thể sử dụng NumberFormat với locale phù hợp:
final formatter =
NumberFormat.decimalPattern('vi_VN');
final number =
formatter.parse('1.500.000');
print(number);
Kết quả tương ứng là giá trị số một triệu năm trăm nghìn.
Tuy nhiên, cần xử lý dữ liệu không hợp lệ.
Ví dụ, người dùng có thể nhập ký tự chữ, nhiều dấu phân cách hoặc một chuỗi không đúng định dạng.
Không nên giả định mọi chuỗi nhập vào đều có thể parse thành công.
Trong biểu mẫu thực tế, cần kết hợp validation và thông báo lỗi rõ ràng.
20. Formatting nên được thực hiện ở đâu trong kiến trúc Flutter?
Một ứng dụng Flutter thường được chia thành nhiều tầng:
API → Model → Repository/Service → State Management → UI
Thông thường, dữ liệu nên được giữ ở dạng có cấu trúc trong Model và phần xử lý nghiệp vụ.
Ví dụ, giá sản phẩm được lưu là số nguyên:
class Product {
final int price;
Product({required this.price});
}
Khi hiển thị lên giao diện, ứng dụng mới định dạng:
final formatter = NumberFormat.currency(
locale: 'vi_VN',
symbol: '₫',
decimalDigits: 0,
);
Text(
formatter.format(product.price),
)
Cách này giúp phần xử lý nghiệp vụ không bị phụ thuộc vào dấu phân cách hoặc ký hiệu hiển thị.
Nếu người dùng đổi ngôn ngữ, ứng dụng chỉ cần định dạng lại mà không phải thay đổi dữ liệu gốc.
21. Formatting trong dự án sử dụng API
Một API có thể trả về dữ liệu:
{
"id": 101,
"price": 250000,
"created_at": "2026-12-25T07:30:00Z"
}
Flutter cần xử lý các trường theo đúng ý nghĩa.
price là giá trị số, không phải chuỗi đã định dạng.
created_at là chuỗi thời gian ISO 8601 có ký hiệu Z, biểu diễn thời gian UTC.
Ứng dụng có thể chuyển chúng sang kiểu dữ liệu phù hợp rồi định dạng khi hiển thị.
Ví dụ:
final price = 250000;
final createdAt = DateTime.parse(
'2026-12-25T07:30:00Z',
);
final formattedPrice =
NumberFormat.currency(
locale: 'vi_VN',
symbol: '₫',
decimalDigits: 0,
).format(price);
final formattedDate =
DateFormat('dd/MM/yyyy HH:mm').format(
createdAt.toLocal(),
);
Đoạn code trên thực hiện hai công việc khác nhau:
- Định dạng giá tiền.
- Chuyển thời gian UTC sang giờ địa phương rồi định dạng.
Việc chuyển đổi múi giờ cần được thực hiện trước khi hiển thị nếu yêu cầu nghiệp vụ là sử dụng giờ địa phương.
22. Những sai lầm thường gặp
Sai lầm đầu tiên là lưu giá tiền dưới dạng chuỗi đã có dấu phân cách rồi sử dụng trực tiếp để tính toán.
Sai lầm thứ hai là nhầm MM với mm trong DateFormat.
Sai lầm thứ ba là nghĩ rằng thay đổi locale sẽ tự động quy đổi tiền tệ.
Sai lầm thứ tư là dùng double cho mọi phép tính tiền mà không xem xét sai số.
Sai lầm thứ năm là định dạng ngày UTC trực tiếp nhưng lại gắn nhãn giờ địa phương.
Sai lầm thứ sáu là sử dụng một định dạng cố định cho tất cả người dùng dù ứng dụng hỗ trợ nhiều locale.
Sai lầm cuối cùng là không kiểm tra dữ liệu nhập vào trước khi Parsing.
23. Kết luận
Date / Number / Currency Formatting là những kỹ thuật giúp ứng dụng Flutter hiển thị dữ liệu ngày giờ, số và tiền tệ theo định dạng phù hợp với người dùng.
Package intl cung cấp các công cụ như DateFormat và NumberFormat để thực hiện công việc này.
Formatting giúp giao diện rõ ràng, nhất quán và hỗ trợ nhiều locale.
Tuy nhiên, cần phân biệt định dạng với chuyển đổi dữ liệu. Formatting không tự động thay đổi múi giờ hoặc quy đổi tiền tệ.
Trong dự án thực tế, nên giữ dữ liệu ở dạng phù hợp cho xử lý và chỉ định dạng tại những vị trí cần hiển thị. Đối với tiền tệ và thời gian, cần đặc biệt chú ý đến độ chính xác, đơn vị và ý nghĩa của dữ liệu.
24. Tài liệu tham khảo
- Dart intl: https://pub.dev/packages/intl
- DateFormat API: https://api.flutter.dev/flutter/package-intl_intl/DateFormat-class.html
- NumberFormat API: https://api.flutter.dev/flutter/package-intl_intl/NumberFormat-class.html
- Flutter Internationalization: https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization








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




