DateUtility
Tổng quan
DateUtility cung cấp một instance Day.js đã cấu hình sẵn với các plugin thiết yếu để thao tác ngày giờ có nhận biết múi giờ. Tất cả service backend đều import dayjs từ @nx/core để đảm bảo việc xử lý ngày giờ nhất quán trên toàn hệ thống.
Nguồn: packages/core/src/utilities/date.utility.ts (23 dòng)
Mã nguồn
Toàn bộ module chỉ gồm 23 dòng -- một singleton được export sau khi cấu hình sẵn:
typescript
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import isoWeek from 'dayjs/plugin/isoWeek';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
dayjs.extend(customParseFormat);
dayjs.extend(timezone);
dayjs.extend(isoWeek);
dayjs.extend(utc);
dayjs.extend(isSameOrBefore);
dayjs.extend(isSameOrAfter);
const tz = process.env.APP_ENV_APPLICATION_TIMEZONE ?? 'Asia/Ho_Chi_Minh';
dayjs.tz.setDefault(tz);
export { dayjs };Cấu hình
Múi giờ mặc định
Múi giờ mặc định là Asia/Ho_Chi_Minh (UTC+7). Có thể ghi đè thông qua biến môi trường APP_ENV_APPLICATION_TIMEZONE.
| Biến | Bắt buộc | Mặc định | Mô tả |
|---|---|---|---|
APP_ENV_APPLICATION_TIMEZONE | Không | Asia/Ho_Chi_Minh | Định danh múi giờ theo IANA |
bash
# .env.development
APP_ENV_APPLICATION_TIMEZONE=Asia/Ho_Chi_Minh # Default
APP_ENV_APPLICATION_TIMEZONE=America/New_York # Override for US Eastern
APP_ENV_APPLICATION_TIMEZONE=UTC # UTC modeCác plugin đã nạp
| Plugin | Mục đích | Ví dụ |
|---|---|---|
customParseFormat | Phân tích ngày với chuỗi định dạng tuỳ chỉnh | dayjs('20/01/2025', 'DD/MM/YYYY') |
timezone | Chuyển đổi và nhận biết múi giờ | dayjs().tz('Asia/Tokyo') |
isoWeek | Tính số tuần theo chuẩn ISO | dayjs().isoWeek() |
utc | Thao tác ở chế độ UTC | dayjs.utc() |
isSameOrBefore | So sánh "trước" bao gồm cả bằng | date.isSameOrBefore(other) |
isSameOrAfter | So sánh "sau" bao gồm cả bằng | date.isSameOrAfter(other) |
Import
typescript
import { dayjs } from '@nx/core';
// or
import { dayjs } from '@nx/core/utilities';Cách dùng cơ bản
Ngày/giờ hiện tại
typescript
// Current time in default timezone (Asia/Ho_Chi_Minh)
const now = dayjs();
// Current time in UTC
const utcNow = dayjs.utc();
// Current time in a specific timezone
const tokyoNow = dayjs().tz('Asia/Tokyo');Phân tích ngày
typescript
// ISO string
const date1 = dayjs('2025-01-20T10:00:00Z');
// Custom format (requires customParseFormat plugin)
const date2 = dayjs('20/01/2025', 'DD/MM/YYYY');
// From timestamp
const date3 = dayjs(1705708800000);
// From Date object
const date4 = dayjs(new Date());Định dạng ngày
typescript
const date = dayjs('2025-01-20T15:30:00');
date.format('YYYY-MM-DD'); // "2025-01-20"
date.format('DD/MM/YYYY'); // "20/01/2025"
date.format('YYYY-MM-DD HH:mm:ss'); // "2025-01-20 15:30:00"
date.format('YYYY-MM-DD HH:mm:ss Z'); // "2025-01-20 15:30:00 +07:00"Thao tác múi giờ
Chuyển đổi giữa các múi giờ
typescript
const date = dayjs('2025-01-20T10:00:00Z'); // UTC
// Convert to Vietnam time
const vnTime = date.tz('Asia/Ho_Chi_Minh');
vnTime.format('HH:mm'); // "17:00"
// Convert to US Eastern
const etTime = date.tz('America/New_York');
etTime.format('HH:mm'); // "05:00"Mẫu lưu trữ và hiển thị
typescript
// Store in UTC (for database)
const stored = dayjs().utc().toISOString();
// "2025-01-20T08:30:00.000Z"
// Display in user's timezone
const displayTime = dayjs(stored).tz('Asia/Ho_Chi_Minh').format('HH:mm DD/MM/YYYY');
// "15:30 20/01/2025"Luồng múi giờ
So sánh ngày
So sánh cơ bản
typescript
const date1 = dayjs('2025-01-20');
const date2 = dayjs('2025-01-25');
date1.isBefore(date2); // true
date1.isAfter(date2); // false
date1.isSame(date2); // false
date1.isSame(date2, 'month'); // true (same month)Bằng hoặc trước/sau
Các phương thức này đến từ plugin isSameOrBefore và isSameOrAfter:
typescript
const startDate = dayjs('2025-01-01');
const endDate = dayjs('2025-01-31');
const checkDate = dayjs('2025-01-15');
// Check if within an inclusive range
const isInRange =
checkDate.isSameOrAfter(startDate) &&
checkDate.isSameOrBefore(endDate);
// trueSo sánh theo độ chi tiết
typescript
const date1 = dayjs('2025-01-20 10:00');
const date2 = dayjs('2025-01-20 15:00');
date1.isSame(date2, 'day'); // true (same day)
date1.isSame(date2, 'hour'); // false (different hour)
date1.isBefore(date2, 'hour'); // trueBiến đổi ngày
Cộng/trừ
typescript
const date = dayjs('2025-01-20');
date.add(7, 'day').format('YYYY-MM-DD'); // "2025-01-27"
date.add(1, 'month').format('YYYY-MM-DD'); // "2025-02-20"
date.subtract(1, 'year').format('YYYY-MM-DD'); // "2024-01-20"
// Chaining
date.add(1, 'month').add(15, 'day').format('YYYY-MM-DD');
// "2025-03-07"Đầu/cuối kỳ
typescript
const date = dayjs('2025-01-20 15:30:45');
date.startOf('day').format('YYYY-MM-DD HH:mm:ss');
// "2025-01-20 00:00:00"
date.endOf('day').format('YYYY-MM-DD HH:mm:ss');
// "2025-01-20 23:59:59"
date.startOf('month').format('YYYY-MM-DD');
// "2025-01-01"
date.endOf('month').format('YYYY-MM-DD');
// "2025-01-31"Thao tác tuần ISO
Plugin isoWeek cung cấp tính toán tuần theo chuẩn ISO 8601:
typescript
const date = dayjs('2025-01-20');
date.isoWeek(); // 4 (ISO week number)
date.isoWeekday(); // 1 (Monday = 1, Sunday = 7)
date.isoWeekYear(); // 2025
// Get start of ISO week (Monday)
const weekStart = date.startOf('isoWeek');
weekStart.format('YYYY-MM-DD'); // "2025-01-20" (Monday)
// Get end of ISO week (Sunday)
const weekEnd = date.endOf('isoWeek');
weekEnd.format('YYYY-MM-DD'); // "2025-01-26" (Sunday)Các tình huống dùng phổ biến
Kiểm tra hợp lệ ngày sự kiện
typescript
function isEventDateValid(eventDate: string): boolean {
const event = dayjs(eventDate);
const now = dayjs();
const maxFutureDate = now.add(1, 'year');
return event.isAfter(now) && event.isBefore(maxFutureDate);
}Khoảng ngày cho báo cáo
typescript
function getMonthlyReportRange(year: number, month: number) {
const start = dayjs()
.year(year)
.month(month - 1)
.startOf('month');
const end = start.endOf('month');
return {
start: start.toISOString(),
end: end.toISOString(),
};
}Tích hợp cơ sở dữ liệu
typescript
// Store in UTC
async createEvent(data: CreateEventDto) {
const eventDateUtc = dayjs
.tz(data.eventDate, data.timezone)
.utc()
.toISOString();
return this.eventRepository.create({
data: {
...data,
eventDate: eventDateUtc,
},
});
}
// Query by date range
const weekStart = dayjs().startOf('isoWeek').toISOString();
const weekEnd = dayjs().endOf('isoWeek').toISOString();
const events = await eventRepository.find({
where: {
eventDate: { gte: weekStart, lte: weekEnd },
},
});Thực hành tốt nhất
1. Luôn lưu trữ theo UTC
typescript
// Correct -- store in UTC
const stored = dayjs.tz(userInput, userTimezone).utc().toISOString();
// Avoid -- timezone-ambiguous
const stored = dayjs(userInput).format();2. Phân tích với múi giờ rõ ràng
typescript
// Correct -- explicit timezone
const date = dayjs.tz('2025-01-20 15:00', 'Asia/Ho_Chi_Minh');
// Avoid -- ambiguous
const date = dayjs('2025-01-20 15:00'); // Which timezone?3. Dùng định dạng ISO cho phản hồi API
typescript
// Correct -- machine-readable
{ createdAt: dayjs(record.createdAt).toISOString() }
// "2025-01-20T08:30:00.000Z"
// Avoid -- locale-specific
{ createdAt: dayjs(record.createdAt).format('DD/MM/YYYY') }
// "20/01/2025"Tham chiếu IGNIS Framework
Instance dayjs được @nx/core export xây dựng trên tiện ích Date của IGNIS. Để xem tài liệu của tiện ích nền tảng, xem: